小编给大家分享一下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 List getChildren(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、负载均衡
/*
* 我是第几个实例, 做负载均衡
* */
List instanceList = 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)实现注册发现与负载均衡的方法的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注天达云行业资讯频道!