您好,登錄后才能下訂單哦!
小編給大家分享一下springboot使用zookeeper(curator)實現注冊發現與負載均衡的方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
最簡單的實現服務高可用的方法就是集群化,也就是分布式部署,但是分布式部署會帶來一些問題。比如:
1、各個實例之間的協同(鎖)
2、負載均衡
3、熱刪除
這里通過一個簡單的實例來說明如何解決注冊發現和負載均衡。
1、先解決依賴,這里只給出zk相關的依賴,pom.xml如下
org.apache.zookeeper zookeeper 3.4.8 org.apache.curator curator-recipes 2.9.1 org.apache.curator curator-client 2.9.1
2、ZkClient
這里使用的是curator,curator是對zookeeper的簡單封裝,提供了一些集成的方法,或者是提供了更優雅的api,舉例來說
zk的create(path, mode, acl, data)方法 == curator create().withMode(mode).forPath(path)調用鏈
package com.dqa.prometheus.client.zookeeper;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.retry.ExponentialBackoffRetry;import org.apache.zookeeper.CreateMode;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.net.InetAddress;import java.util.ArrayList;import java.util.List;public class ZkClient { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private CuratorFramework client; private String zookeeperServer; private int sessionTimeoutMs; private int connectionTimeoutMs; private int baseSleepTimeMs; private int maxRetries; public void setZookeeperServer(String zookeeperServer) { this.zookeeperServer = zookeeperServer; } public String getZookeeperServer() { return zookeeperServer; } public void setSessionTimeoutMs(int sessionTimeoutMs) { this.sessionTimeoutMs = sessionTimeoutMs; } public int getSessionTimeoutMs() { return sessionTimeoutMs; } public void setConnectionTimeoutMs(int connectionTimeoutMs) { this.connectionTimeoutMs = connectionTimeoutMs; } public int getConnectionTimeoutMs() { return connectionTimeoutMs; } public void setBaseSleepTimeMs(int baseSleepTimeMs) { this.baseSleepTimeMs = baseSleepTimeMs; } public int getBaseSleepTimeMs() { return baseSleepTimeMs; } public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; } public int getMaxRetries() { return maxRetries; } public void init() { RetryPolicy retryPolicy = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries); client = CuratorFrameworkFactory.builder().connectString(zookeeperServer).retryPolicy(retryPolicy) .sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).build(); client.start(); } public void stop() { client.close(); } public CuratorFramework getClient() { return client; } public void register() { try { String rootPath = "/" + "services"; String hostAddress = InetAddress.getLocalHost().getHostAddress(); String serviceInstance = "prometheus" + "-" + hostAddress + "-"; client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(rootPath + "/" + serviceInstance); } catch (Exception e) { logger.error("注冊出錯", e); } } public ListgetChildren(String path) { List childrenList = new ArrayList<>(); try { childrenList = client.getChildren().forPath(path); } catch (Exception e) { logger.error("獲取子節點出錯", e); } return childrenList; } public int getChildrenCount(String path) { return getChildren(path).size(); } public List getInstances() { return getChildren("/services"); } public int getInstancesCount() { return getInstances().size(); } }
2、configuration如下
package com.dqa.prometheus.configuration;import com.dqa.prometheus.client.zookeeper.ZkClient;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; @Configurationpublic class ZkConfiguration { @Value("${zookeeper.server}") private String zookeeperServer; @Value(("${zookeeper.sessionTimeoutMs}")) private int sessionTimeoutMs; @Value("${zookeeper.connectionTimeoutMs}") private int connectionTimeoutMs; @Value("${zookeeper.maxRetries}") private int maxRetries; @Value("${zookeeper.baseSleepTimeMs}") private int baseSleepTimeMs; @Bean(initMethod = "init", destroyMethod = "stop") public ZkClient zkClient() { ZkClient zkClient = new ZkClient(); zkClient.setZookeeperServer(zookeeperServer); zkClient.setSessionTimeoutMs(sessionTimeoutMs); zkClient.setConnectionTimeoutMs(connectionTimeoutMs); zkClient.setMaxRetries(maxRetries); zkClient.setBaseSleepTimeMs(baseSleepTimeMs); return zkClient; } }
配置文件如下
#============== zookeeper =================== zookeeper.server=10.93.21.21:2181,10.93.18.34:2181,10.93.18.35:2181 zookeeper.sessionTimeoutMs=6000 zookeeper.connectionTimeoutMs=6000 zookeeper.maxRetries=3 zookeeper.baseSleepTimeMs=1000
3、注冊發現
是通過上面封裝的ZkClient中的register方法實現的,調用如下。
package com.dqa.prometheus; import com.dqa.prometheus.client.zookeeper.ZkClient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.orm.jpa.EntityScan; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableAsync @EnableScheduling @EntityScan(basePackages="com.xiaoju.dqa.prometheus.model") public class Application { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(Application.class, args); ZkClient zkClient = context.getBean(ZkClient.class); zkClient.register(); } }
注冊代碼說明:
public void register() { try { String rootPath = "/" + "services"; String hostAddress = InetAddress.getLocalHost().getHostAddress(); String serviceInstance = "prometheus" + "-" + hostAddress + "-"; client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(rootPath + "/" + serviceInstance); } catch (Exception e) { logger.error("注冊出錯", e); } }
1、zk中的注冊路徑
/services/prometheus-10.93.21.21-00000000001
2、CreateMode有四種,選擇EPHEMERAL_SEQUENTIAL的原因是,服務關閉的時候session超時,zk節點會自動刪除,同時自增id可以實現鎖和負載均衡,下面再說
1、PERSISTENT 持久化目錄節點,存儲的數據不會丟失。2、PERSISTENT_SEQUENTIAL 順序自動編號的持久化目錄節點,存儲的數據不會丟失,并且根據當前已近存在的節點數自動加 1,然后返回給客戶端已經成功創建的目錄節點名。3、EPHEMERAL 臨時目錄節點,一旦創建這個節點的客戶端與服務器端口也就是session 超時,這種節點會被自動刪除。 4、EPHEMERAL_SEQUENTIAL 臨時自動編號節點,一旦創建這個節點的客戶端與服務器端口也就是session 超時,這種節點會被自動刪除,并且根據當前已近存在的節點數自動加 1,然后返回給客戶端已經成功創建的目錄節點名。
4、負載均衡
/* * 我是第幾個實例, 做負載均衡 * */ ListinstanceList = zkClient.getInstances(); Collections.sort(instanceList); String hostAddress = NetFunction.getAddressHost(); int instanceNo = 0; if (hostAddress != null) { for (int i=0; i waitingTasks = checkTaskDao.getTasks(taskType, TaskStatus.WAITING.getValue()); Iterator waitingIterator = waitingTasks.iterator(); while (waitingIterator.hasNext()) { if (waitingIterator.next().getTaskId().hashCode() % instanceCount != instanceNo) { waitingIterator.remove(); } }
說明:
1、例如有3個實例(zkClient.getInstances()),那么通過IP我們把3個實例按照自增id排序分別標號為0,1,2
2、對第一個實例也就是instanceNo=0,只執行taskId.hashCode() % 3 == 0的任務,其他兩個實例類似
3、當有一個實例掛掉,2個實例,instanceNo=0只執行taskId.hashCode() % 2 == 0的任務,實現熱刪除
以上是springboot使用zookeeper(curator)實現注冊發現與負載均衡的方法的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。