手撕zookeeper:作为注册中心负载均衡
钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>
作者:潘吉祥
要说最开始接触zookeeper,已经是很久很久以前了,应该是学习dubbo的时候了解的,简单地安装、启动一下,作为dubbo的注册中心。
那个时候觉得挺神奇的,居然能服务注册与发现!但是也仅限于这样的感觉,因为我觉得具体实现对于我来说太遥远了,那种感觉就像我在学习Java基础的时候听到负载均衡、集群这类概念。这么说可能还是没有确切地表达出那种感觉,尤其是作为一个文科生而言。
虽说如此,但是我还是有些不自量力地在简历上写了“熟悉zookeeper”……当然了,打脸的时候总会出现,只是迟早问题,大概一年后:那你说说zk有几种节点类型?我……
不争馒头争口气,自己挖的坑自己得填好,这下怎么也得深入了解一下了。大概也是自己视野开阔的原因,此时抛开zookeeper不说,仔细想想注册中心简单点来说也就是存放对应关系的一个容器而已,再简单点就是一个map映射。有了思路,深入学了学zookeeper,于是开始试着把自己的服务注册到zookeeper。
这里关于zookeeper的知识就不再赘述,你可以把他当做一个存放键值对的数据库,当然zookeeper的功能远不限此。我们直接进入正题:把自己的服务注册到zookeeper并实现负载均衡(关于节点的操作不懂得小伙伴可以先学习一下zookeeper的基本操作)。
开拔之前我们先来理一下思路,这往往是最重要的:
使用maven依赖有zkClient,httpClient.服务均采用了springboot方式创建。
生产者1(注册方)代码(yml配置了服务端口9001),为方便阅读,controller也放到了启动类中:
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
register();
SpringApplication.run(Application.class,args);
}
@GetMapping("/name")
public String getName(){
return "9001服务器返回:"+"吉祥君";
}
public static void register(){
//建立连接
ZkClient zkClient = new ZkClient("192.168.1.23:2181", 5000);
//创建父节点
String rootNode = "/name_server";
if(!zkClient.exists(rootNode)){
zkClient.createPersistent(rootNode);
}
//为了方便观看直接在此定义
//子节点的名称
String sonNode = rootNode+"/name_01";
//子节点的value
String sonNodeVal = "127.0.0.1:9001";
//如果不存在
if(!zkClient.exists(sonNode)){
zkClient.createEphemeral(sonNode,sonNodeVal);
}
System.out.println(sonNode+"服务注册成功!地址:"+"---->"+sonNode);
}
}
服务提供者二的代码几乎一样,修改的只是controller返回值("9002服务器返回:"+"吉祥君";)、注册子节点的名称(/name_02)和val(127.0.0.1:9001),yml端口:9002。
启动两个服务,我们可以使用zookeeper客户端可视化工具查看节点信息:
此时再看消费者(服务拉取方,当然他也可以把自己注册到zookeeper)端代码,这里没有把controller放在一起因此服务启动时获取的ip集合通过注入bean的方式保存,yml端口8001。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
@Bean
public List<String> serversList(){
List<String> list = new ArrayList<>();
//建立连接,此处连接为自己电脑的zookeeper连接
ZkClient zkClient = new ZkClient("192.168.1.23:2181", 5000);
String rootNode = "/name_server";
//得到下面所有的子节点,也就是注册的服务
List<String> childrens = zkClient.getChildren(rootNode);
for (String children : childrens) {
//得到子节点全路径
String sonPath = rootNode+"/"+children;
//获取对应的val也就是对应服务的ip
String sonVal = zkClient.readData(sonPath);
list.add(sonVal);
}
//监听节点变化
//如果监听到节点变化就刷新服务列表重新拉取
zkClient.subscribeChildChanges(rootNode, (parentPath,childrensList) ->{
list.clear();
for (String children : childrensList) {
//得到子节点全路径
String sonPath = rootNode+"/"+children;
//获取对应的val也就是对应服务的ip
String sonVal = zkClient.readData(sonPath);
list.add(sonVal);
}
});
return list;
}
}
Controller层代码:
@RestController
public class ConsumerController {
@Autowired
private List<String> serversList;
private AtomicInteger init = new AtomicInteger(0);
@GetMapping("/name")
public String getName() throws Exception{
//第一次是0(使用httpclient来请求)
String s = serversList.get(init.get());
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet("http://"+s+"/name");
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
If(serversList.size()==1){
return EntityUtils.toString(entity);
}
//第一次是0,size=2
if(init.get() < serversList.size()-1){
init.getAndIncrement();
return EntityUtils.toString(entity);
}
//如果init不小于serversList.size()-1,重置为0
init.set(0);
return EntityUtils.toString(entity);
}
}
这里使用简单的轮训算法来请求不同的服务,由于springbean默认是单实例的,为了保证线程安全使用了原子类来代替了基本类型操作。当前访问返回结果之前将最终效果如下:如果其中一个服务挂掉了,由于是创建得临时节点,会自动清除,并通知消费者,消费者重新拉取存在的节点信息,达到服务可用。
注意测试的时候由于是强制停掉服务,所以zookeeper的节点通知会延迟,必须等到节点刷新后再访问。
这里注册到zookeeper的rootNode其实就相当于我们微服务中的applicationName,下面的sonNode就相当于一个服务的多个实例喽。
Zookeeper作为注册中心的操作,你看懂了吗?看懂就关注一下呗
Ps(工程Git地址https://github.com/rockit-ba/zookeeper-dubbo.git)
END
【推荐阅读】
贼好用的Java工具类库,GitHub星标10k+,你在用吗?
感谢阅读,请扫码关注
明天见
- 手撕zookeeper:作为注册中心负载均衡
- sringcloud2.0学习-7-springcloud整合zookeeper作注册中心+ribbon负载均衡
- spring cloud使用zookeeper作为服务注册中心和配置中心
- Zookeeper最常用的作用,作为dubbo的注册中心
- Spring Cloud使用zookeeper作为服务注册中心与配置中心
- NET(C#)接入Dubbo服务,Zookeeper作为Dubbo服务的注册中心,实现thrift协议访问接口(2)
- springboot使用zookeeper(curator)实现注册发现与负载均衡
- 为什么zookeeper能作为注册中心?内部是怎么样运作的?
- zookeeper作为注册中心,使用dubbo
- NET(C#)接入Dubbo服务,Zookeeper作为Dubbo服务的注册中心,实现thrift协议访问接口(2)
- 【架构】SpringCloud 注册中心、负载均衡、熔断器、调用监控、API网关示例
- 作为服务注册中心,Eureka比Zookeeper好在哪里
- 通过RestTemplate的负载均衡配置和eureka注册中心来实现服务间默认规则调用
- 用zookeeper作为Dubbo的注册中心发布服务
- 使用Zookeeper作为注册中心和配置中心
- NET(C#)接入Dubbo服务,Zookeeper作为Dubbo服务的注册中心,实现thrift协议访问接口(3)
- IDEA下搭建maven管理的DUBBO项目,Zookeeper作为注册中心
- 【DUBBO】zookeeper在dubbo中作为注册中心的原理结构
- Zookeeper最常用的作用,作为dubbo的注册中心
- 作为服务注册中心,Eureka比Zookeeper好在哪里?