You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ka...@apache.org on 2019/03/06 01:18:14 UTC
[phoenix-queryserver] branch master updated: PHOENIX-5063 Create a
new repo for the phoenix query server (#3)
This is an automated email from the ASF dual-hosted git repository.
karanmehta93 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix-queryserver.git
The following commit(s) were added to refs/heads/master by this push:
new 8068436 PHOENIX-5063 Create a new repo for the phoenix query server (#3)
8068436 is described below
commit 8068436b9b9c89f2b15736492b582604ac1fb80d
Author: karanmehta93 <ka...@gmail.com>
AuthorDate: Tue Mar 5 17:18:10 2019 -0800
PHOENIX-5063 Create a new repo for the phoenix query server (#3)
Added load-balancer module
---
load-balancer/pom.xml | 85 ++++++++++
.../phoenix/end2end/LoadBalancerEnd2EndIT.java | 144 +++++++++++++++++
.../service/LoadBalanceZookeeperConfImpl.java | 103 ++++++++++++
.../phoenix/loadbalancer/service/LoadBalancer.java | 178 +++++++++++++++++++++
.../queryserver/register/ZookeeperRegistry.java | 72 +++++++++
...x.loadbalancer.service.LoadBalanceZookeeperConf | 1 +
...rg.apache.phoenix.queryserver.register.Registry | 1 +
pom.xml | 23 +++
8 files changed, 607 insertions(+)
diff --git a/load-balancer/pom.xml b/load-balancer/pom.xml
new file mode 100644
index 0000000..cb893f7
--- /dev/null
+++ b/load-balancer/pom.xml
@@ -0,0 +1,85 @@
+<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.phoenix</groupId>
+ <artifactId>phoenix-queryserver</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>load-balancer</artifactId>
+ <name>Phoenix Load Balancer</name>
+ <description>A Load balancer which routes calls to Phoenix Query Server</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.hbase</groupId>
+ <artifactId>hbase-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.phoenix</groupId>
+ <artifactId>queryserver</artifactId>
+ </dependency>
+ <!-- for tests -->
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ <goal>test-jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf</exclude>
+ <exclude>src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java b/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java
new file mode 100644
index 0000000..a5e2c9b
--- /dev/null
+++ b/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java
@@ -0,0 +1,144 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.end2end;
+
+import com.google.common.net.HostAndPort;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.curator.CuratorZookeeperClient;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.TestingServer;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.phoenix.loadbalancer.service.LoadBalancer;
+import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf;
+import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConfImpl;
+import org.apache.phoenix.queryserver.register.Registry;
+import org.apache.phoenix.queryserver.register.ZookeeperRegistry;
+import org.apache.zookeeper.KeeperException;
+import org.junit.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class LoadBalancerEnd2EndIT {
+ private static TestingServer testingServer;
+ private static CuratorFramework curatorFramework;
+ private static final Log LOG = LogFactory.getLog(LoadBalancerEnd2EndIT.class);
+ private static final LoadBalanceZookeeperConf LOAD_BALANCER_CONFIGURATION = new LoadBalanceZookeeperConfImpl();
+ private static String path;
+ private static LoadBalancer loadBalancer;
+ private static HostAndPort pqs1 = HostAndPort.fromParts("localhost",1000);
+ private static HostAndPort pqs2 = HostAndPort.fromParts("localhost",2000);
+ private static HostAndPort pqs3 = HostAndPort.fromParts("localhost",3000);
+ public static String zkConnectString;
+ public static Registry registry;
+
+ @BeforeClass
+ public static void setup() throws Exception{
+
+ registry = new ZookeeperRegistry();
+ zkConnectString = LOAD_BALANCER_CONFIGURATION.getZkConnectString();
+ int port = Integer.parseInt(zkConnectString.split(":")[1]);
+ testingServer = new TestingServer(port);
+ testingServer.start();
+
+ path = LOAD_BALANCER_CONFIGURATION.getParentPath();
+ curatorFramework = CuratorFrameworkFactory.newClient(zkConnectString,
+ new ExponentialBackoffRetry(1000, 3));
+ curatorFramework.start();
+ createNodeForTesting(Arrays.asList(pqs1,pqs2,pqs3));
+ curatorFramework.setACL().withACL(LOAD_BALANCER_CONFIGURATION.getAcls());
+ loadBalancer = LoadBalancer.getLoadBalancer();
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ CloseableUtils.closeQuietly(curatorFramework);
+ CloseableUtils.closeQuietly(testingServer);
+ }
+
+ private static void createNodeForTesting(List<HostAndPort> pqsNodes) throws Exception{
+ for(HostAndPort pqs:pqsNodes) {
+ registry.registerServer(LOAD_BALANCER_CONFIGURATION,pqs.getPort(),zkConnectString,pqs.getHostText());
+ }
+ curatorFramework.getChildren().forPath(LOAD_BALANCER_CONFIGURATION.getParentPath()).size();
+ }
+
+
+ @Test
+ public void testGetAllServiceLocation() throws Exception {
+ Assert.assertNotNull(loadBalancer);
+ List<HostAndPort> serviceLocations = loadBalancer.getAllServiceLocation();
+ Assert.assertTrue(" must contains 3 service location",serviceLocations.size() == 3);
+ }
+
+ @Test
+ public void testGetSingleServiceLocation() throws Exception {
+ Assert.assertNotNull(loadBalancer);
+ HostAndPort serviceLocation = loadBalancer.getSingleServiceLocation();
+ Assert.assertNotNull(serviceLocation);
+ }
+
+ @Test(expected=Exception.class)
+ public void testZookeeperDown() throws Exception{
+ testingServer.stop();
+ CuratorZookeeperClient zookeeperClient = curatorFramework.getZookeeperClient();
+ //check to see if zookeeper is really down.
+ while (zookeeperClient.isConnected()){
+ Thread.sleep(1000);
+ };
+ loadBalancer.getSingleServiceLocation();
+ }
+
+ @Test(expected = KeeperException.NoNodeException.class)
+ public void testNoPhoenixQueryServerNodeInZookeeper() throws Exception{
+ List<HostAndPort> hostAndPorts = Arrays.asList(pqs1, pqs2, pqs3);
+ for(HostAndPort pqs: hostAndPorts) {
+ String fullPathToNode = LOAD_BALANCER_CONFIGURATION.getFullPathToNode(pqs);
+ curatorFramework.delete().deletingChildrenIfNeeded().forPath(fullPathToNode);
+ while (curatorFramework.checkExists().forPath(fullPathToNode) != null){
+ //wait for the node to deleted
+ Thread.sleep(1000);
+ };
+ }
+ //delete the parent
+ curatorFramework.delete().forPath(path);
+ // should throw an exception as there is
+ // no node in the zookeeper
+ try {
+ loadBalancer.getSingleServiceLocation();
+ } catch(Exception e) {
+ throw e;
+ } finally {
+ // need to create node for other tests to run.
+ createNodeForTesting(hostAndPorts);
+ }
+ }
+
+ @Test
+ public void testSingletonPropertyForLoadBalancer(){
+ LoadBalancer anotherloadBalancerRef = LoadBalancer.getLoadBalancer();
+ Assert.assertTrue(" the load balancer is not singleton",loadBalancer == anotherloadBalancerRef );
+ }
+
+
+
+}
diff --git a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
new file mode 100644
index 0000000..98e2682
--- /dev/null
+++ b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
@@ -0,0 +1,103 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.phoenix.loadbalancer.service;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.net.HostAndPort;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+
+public class LoadBalanceZookeeperConfImpl implements LoadBalanceZookeeperConf {
+
+ private Configuration configuration;
+
+ public LoadBalanceZookeeperConfImpl() {
+ this.configuration = HBaseConfiguration.create();
+ }
+
+ public LoadBalanceZookeeperConfImpl(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @VisibleForTesting
+ public void setConfiguration(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public String getQueryServerBasePath(){
+ return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH,
+ QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH);
+ }
+
+ @Override
+ public String getServiceName(){
+ return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_SERVICE_NAME,
+ QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME);
+ }
+
+ @Override
+ public String getZkConnectString(){
+ return String.format("%s:%s",configuration.get(QueryServices.ZOOKEEPER_QUORUM_ATTRIB,
+ "localhost"),configuration.get(QueryServices.ZOOKEEPER_PORT_ATTRIB,"2181"));
+ }
+
+ private String getZkLbUserName(){
+ return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME,
+ QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME);
+ }
+
+ private String getZkLbPassword(){
+ return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD,
+ QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD);
+ }
+
+ @Override
+ public List<ACL> getAcls() {
+ ACL acl = new ACL();
+ acl.setId(new Id("digest",getZkLbUserName()+":"+getZkLbPassword()));
+ acl.setPerms(ZooDefs.Perms.READ);
+ return Arrays.asList(acl);
+ }
+
+ @Override
+ public String getParentPath() {
+ String path = String.format("%s/%s",getQueryServerBasePath(),getServiceName());
+ return path;
+ }
+
+ @Override
+ public String getFullPathToNode(HostAndPort hostAndPort) {
+ String path = String.format("%s/%s",getParentPath()
+ ,hostAndPort.toString());
+ return path;
+ }
+}
+
diff --git a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java
new file mode 100644
index 0000000..23e9025
--- /dev/null
+++ b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java
@@ -0,0 +1,178 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.loadbalancer.service;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.UnhandledErrorListener;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.state.ConnectionState;
+import org.apache.curator.framework.state.ConnectionStateListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+
+import java.net.ConnectException;
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.io.Closeable;
+import java.util.List;
+
+/**
+ * LoadBalancer class is singleton , used by the client
+ * to find out about various location of PQS servers.
+ * The client needs to configure the HBase-site.xml with the needed
+ * properties i.e. location of zookeeper ( or service locator), username, password etc.
+ */
+public class LoadBalancer {
+
+ private static final LoadBalanceZookeeperConf CONFIG = new LoadBalanceZookeeperConfImpl(HBaseConfiguration.create());
+ private static CuratorFramework curaFramework = null;
+ protected static final Log LOG = LogFactory.getLog(LoadBalancer.class);
+ private static PathChildrenCache cache = null;
+ private static final LoadBalancer loadBalancer = new LoadBalancer();
+ private ConnectionStateListener connectionStateListener = null;
+ private UnhandledErrorListener unhandledErrorListener = null;
+ private List<Closeable> closeAbles = Lists.newArrayList();
+
+ private LoadBalancer() {
+ try {
+ start();
+ }catch(Exception ex){
+ LOG.error("Exception while creating a zookeeper clients and cache",ex);
+ if ((curaFramework != null) && (connectionStateListener != null)){
+ curaFramework.getConnectionStateListenable()
+ .removeListener(connectionStateListener);
+ }
+ if ((curaFramework != null) && (unhandledErrorListener != null)){
+ curaFramework.getUnhandledErrorListenable()
+ .removeListener(unhandledErrorListener);
+ }
+ for (Closeable closeable : closeAbles) {
+ CloseableUtils.closeQuietly(closeable);
+ }
+ }
+ }
+
+
+
+ /**
+ * Return Singleton Load Balancer every single time.
+ * @return LoadBalancer
+ */
+ public static LoadBalancer getLoadBalancer() {
+ return loadBalancer;
+ }
+
+ /**
+ * It returns the location of Phoenix Query Server
+ * in form of Guava <a href="https://google.github.io/guava/releases/19.0/api/docs/com/google/common/net/HostAndPort.html">HostAndPort</a>
+ * from the cache. The client should catch Exception incase
+ * the method is unable to fetch PQS location due to network failure or
+ * in-correct configuration issues.
+ * @return - return Guava HostAndPort. See <a href="http://google.com">http://google.com</a>
+ * @throws Exception
+ */
+ public HostAndPort getSingleServiceLocation() throws Exception{
+ List<HostAndPort> childNodes = conductSanityCheckAndReturn();
+ // get an random connect string
+ int i = ThreadLocalRandom.current().nextInt(0, childNodes.size());
+ return childNodes.get(i);
+ }
+
+ /**
+ * return locations of all Phoenix Query Servers
+ * in the form of a List of PQS servers <a href="https://google.github.io/guava/releases/19.0/api/docs/com/google/common/net/HostAndPort.html">HostAndPort</a>
+ * @return - HostAndPort
+ * @throws Exception
+ */
+ public List<HostAndPort> getAllServiceLocation() throws Exception{
+ return conductSanityCheckAndReturn();
+ }
+
+ private List<HostAndPort> conductSanityCheckAndReturn() throws Exception{
+ Preconditions.checkNotNull(curaFramework
+ ," curator framework in not initialized ");
+ Preconditions.checkNotNull(cache," cache value is not initialized");
+ boolean connected = curaFramework.getZookeeperClient().isConnected();
+ if (!connected) {
+ String message = " Zookeeper seems to be down. The data is stale ";
+ ConnectException exception =
+ new ConnectException(message);
+ LOG.error(message, exception);
+ throw exception;
+ }
+ List<String> currentNodes = curaFramework.getChildren().forPath(CONFIG.getParentPath());
+ List<HostAndPort> returnNodes = new ArrayList<>();
+ String nodeAsString = null;
+ for(String node:currentNodes) {
+ try {
+ returnNodes.add(HostAndPort.fromString(node));
+ } catch(Throwable ex) {
+ LOG.error(" something wrong with node string "+nodeAsString,ex);
+ }
+ }
+ return returnNodes;
+ }
+ private String getZkConnectString(){
+ return CONFIG.getZkConnectString();
+ }
+
+ private ConnectionStateListener getConnectionStateListener(){
+ return new ConnectionStateListener() {
+ @Override
+ public void stateChanged(CuratorFramework client, ConnectionState newState) {
+ if (!newState.isConnected()) {
+ LOG.error( " connection to zookeeper broken. It is in "+ newState.name()+" state.");
+ }
+ }
+ };
+ }
+
+ private UnhandledErrorListener getUnhandledErrorListener(){
+ return new UnhandledErrorListener() {
+ @Override
+ public void unhandledError(String message, Throwable e) {
+ LOG.error("unhandled exception: "+ message,e);
+ }
+ };
+ }
+
+ private void start() throws Exception{
+ curaFramework = CuratorFrameworkFactory.newClient(getZkConnectString(),
+ new ExponentialBackoffRetry(1000, 3));
+ curaFramework.start();
+ curaFramework.setACL().withACL(CONFIG.getAcls());
+ connectionStateListener = getConnectionStateListener();
+ curaFramework.getConnectionStateListenable()
+ .addListener(connectionStateListener);
+ unhandledErrorListener = getUnhandledErrorListener();
+ curaFramework.getUnhandledErrorListenable()
+ .addListener(unhandledErrorListener);
+ cache = new PathChildrenCache(curaFramework, CONFIG.getParentPath(), true);
+ cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
+ closeAbles.add(cache);
+ closeAbles.add(curaFramework);
+ }
+}
diff --git a/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java b/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java
new file mode 100644
index 0000000..8aee177
--- /dev/null
+++ b/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java
@@ -0,0 +1,72 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.queryserver.register;
+
+
+import com.google.common.net.HostAndPort;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf;
+import org.apache.phoenix.queryserver.server.QueryServer;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.data.Stat;
+
+import java.nio.charset.StandardCharsets;
+
+
+public class ZookeeperRegistry implements Registry {
+
+ private static final Log LOG = LogFactory.getLog(ZookeeperRegistry.class);
+ private CuratorFramework client;
+
+ public ZookeeperRegistry(){}
+
+ @Override
+ public void registerServer(LoadBalanceZookeeperConf configuration, int pqsPort,
+ String zookeeperConnectString, String pqsHost)
+ throws Exception {
+
+ this.client = CuratorFrameworkFactory.newClient(zookeeperConnectString,
+ new ExponentialBackoffRetry(1000,10));
+ this.client.start();
+ HostAndPort hostAndPort = HostAndPort.fromParts(pqsHost,pqsPort);
+ String path = configuration.getFullPathToNode(hostAndPort);
+ String node = hostAndPort.toString();
+ this.client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path
+ ,node.getBytes(StandardCharsets.UTF_8));
+ Stat stat = this.client.setACL().withACL(configuration.getAcls()).forPath(path);
+ if (stat != null) {
+ LOG.info(" node created with right ACL");
+ }
+ else {
+ LOG.error("could not create node with right ACL. So, system would exit now.");
+ throw new RuntimeException(" Unable to connect to Zookeeper");
+ }
+
+ }
+
+ @Override
+ public void unRegisterServer() throws Exception {
+ CloseableUtils.closeQuietly(this.client);
+ }
+}
diff --git a/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf b/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf
new file mode 100644
index 0000000..4cc6ea4
--- /dev/null
+++ b/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf
@@ -0,0 +1 @@
+org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConfImpl
\ No newline at end of file
diff --git a/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry b/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry
new file mode 100644
index 0000000..05e1006
--- /dev/null
+++ b/load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry
@@ -0,0 +1 @@
+org.apache.phoenix.queryserver.register.ZookeeperRegistry
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 99040bf..0f87d75 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,7 @@
<modules>
<module>queryserver</module>
<module>queryserver-client</module>
+ <module>load-balancer</module>
<module>assembly</module>
<module>phoenix-client</module>
</modules>
@@ -51,6 +52,7 @@
<!-- Hadoop Versions -->
<hbase.version>1.4.0</hbase.version>
<hadoop-two.version>2.7.5</hadoop-two.version>
+ <curator.version>2.12.0</curator.version>
<phoenix.version>4.15.0-HBase-1.4-SNAPSHOT</phoenix.version>
<!-- Dependency versions -->
@@ -402,13 +404,24 @@
</dependency>
<dependency>
<groupId>org.apache.phoenix</groupId>
+ <artifactId>queryserver</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.phoenix</groupId>
<artifactId>queryserver-client</artifactId>
<version>${project.version}</version>
</dependency>
+
<!-- HBase dependencies -->
<dependency>
<groupId>org.apache.hbase</groupId>
+ <artifactId>hbase-common</artifactId>
+ <version>${hbase.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hbase</groupId>
<artifactId>hbase-testing-util</artifactId>
<version>${hbase.version}</version>
<scope>test</scope>
@@ -489,6 +502,16 @@
<!-- General Dependencies -->
<dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-client</artifactId>
+ <version>${curator.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <version>${curator.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.pig</groupId>
<artifactId>pig</artifactId>
<version>${pig.version}</version>