微服务架构 | 3.3 Apache Zookeeper 注册中心
@
前言
参考资料:
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服务原理与实战》
《B站 尚硅谷 SpringCloud 框架开发教程 周阳》
《Zookeeper 教程》
《Zookeeper 官网》
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等;
1. Zookeeper 基础知识
1.1 Zookeeper 是什么
- Zookeeper 是一个分布式协调工具,可以实现注册中心功能;
- 是 Apache Hadoop 的一个子项目,用来解决分布式应用中经常遇到的一些数据管理问题。包括:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等;
- 简单来说:zookeeper=文件系统+监听通知机制;
- ZooKeeper 的架构通过冗余服务实现高可用性;
- 【注意】ZooKeeper 本身并不是注册中心,只是基于 ZooKeeper 本身的特性可以实现注册中心这个场景;
1.2 Zookeeper 的数据结构
系统概述:
- ZooKeeper 的数据模型和分布式文件系统类似,是一种层次化的属性结构;
- 和文件系统不同的是,ZooKeeper 的数据是结构化存储的,并没有在物理上体现出文件和目录;
- ZooKeeper 上的每个节点的数据都是允许读和写,且必须要按照层级创建;
Znode 节点:
- Zookeeper 中的所有存储的数据是由 Znode 组成,并以 key/value 形式存储数据;
- ZooKeeper 只是管理和协调有关的数据,所以 value 的数据大小不建议设置得非常大,较大的数据会带来更大的网络开销;
- Znode 维护一个 stat 状态信息,其中包含数据变化的时间和版本等;
stat 状态信息:
属性 说明 cZxid 创建节点时的事务 ID ctime 创建节点时的时间 mZxid 最后修改节点时的事务 ID mtime 最后修改节点时的时间 pZxid 表示该节点的子节点列表最后一次修改的事务 ID(包括增删子节点,不包括改子节点内容) cversion 子节点版本号,子节点每次修改版本号加 1 dataversion 数据版本号,数据每次修改该版本号加 1 aclversion 权限版本号,权限每次修改该版本号加 1 ephemeralOwner 创建该临时节点的会话的 sessionID(持久节点,该属性值为 0) dataLength 该节点的数据长度 numChildren 该节点拥有直接子节点的数量 Znode 的节点类型:
- 持久化节点:节点的数据会持久化到磁盘;
- 临时节点:节点的生命周期和创建该节点的客户端的生命周期保持一致。客户端会话结束,则该临时节点删除;
- 有序节点:在创建的节点后增加一个递增的序列,该序列在同一级父节点之下是唯一的;
- 容器节点:容器节点下最后一个子节点被删除时,容器节点自动删除(3.5.3版本后);
- TTL 节点:设置一个存活时间,如果在存活时间之内该节点没有任何修改并且没有子节点,则自动删除(3.5.3版本后);
一个示例图:
1.3 Watcher 机制
- 一种针对 Znode 的订阅/通知机制;
- 当 Znode 节点状态发生变化时或者 ZooKeeper 客户端连接状态发生变化时,会触发事件通知;
- 该机制在服务注册与发现中,用于服务调用者及时感知到服务提供者的变化;
- ZooKeeper 提供了三种 JavaAPI 机制进行对 Znode 进行注册监听:
- getData():用于获取指定节点的 value 信息,并且可以注册监听,当监听的节点进行创建、修改、删除操作时,会触发相应的事件通知;
- getChildren():用于获取指定节点的所有子节点,并且允许注册监听,当监听节点的子节点进行创建、修改、删除操作时,触发相应的事件通知;
- exists():用于判断指定节点是否存在,同样可以注册针对指定节点的监听,监听的时间类型和 getData() 相同
- Watcher 事件的触发都是一次性的,客户端在发现节点修改后需要在事件回调中再次注册事件;
1.4 常见应用场景分析
- 分布式锁:
- 排他性:避免在同一时刻多个进程同时访问某一个共享资源;
- 基于节点的性质:临时节点、同级节点的唯一性;
- 获得锁的过程:在获得排他锁时,所有客户端可以去 ZooKeeper 服务器上
/Exclusive_Locks
节点下创建一个临时节点/lock
。只有一个客户端能创建成功; - 释放锁的过程:有两种情况:
- 获得锁的客户端因为异常断开了和服务端的连接,基于临时节点的特性,
/lock
节点会被自动删除; - 获得锁的客户端执行完业务逻辑之后,主动删除了创建的
/lock
节点;
- 获得锁的客户端因为异常断开了和服务端的连接,基于临时节点的特性,
- Master 选举:
- 当集群机器中有一个机器宕机后,其他机器会接替故障机器继续工作;
- 基于节点的性质有两种实现方式:
- 唯一性:类似分布式锁。在 ZooKeeper 服务器上创建一个临时节点
/master-election
,只有成功创建的机器工作。其他机器针对该节点注册 Watcher 事件; - 临时有序节点:所有参与选举的客户端在 ZooKeeper 服务器的
/master
节点下创建一个临时有序节点,编号最小的节点表示 Master,后续的节点可以监听前一个节点的删除事件,用于触发重新选举。如下图所示:
- 唯一性:类似分布式锁。在 ZooKeeper 服务器上创建一个临时节点
1.5 Zookeeper 的版本冲突问题
- Zookeeper 的依赖如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
- 如果我们直接添加这个依赖可能会出现以下问题,出现以下日志信息是说明出现 Zookeeper 版本冲突问题:
- 原因是:上述依赖自带 3.5.3beta 的版本,与本地的下载的 zookeeper 版本对应不上;
- 可以通过修改 pom.xml 文件解决;
- 修改后的示例请见本篇《2.1 引入 pom.xml 依赖》;
1.6 Zookeeper 注册中心的实现原理
本篇或《12.1 使用 Apache Dubbo 实现远程通信》里的《5. Dubbo 使用 Zookeeper 作为注册中心》构建了如下示例;
- 当 Dubbo 服务启动时:
- 在 Zookeeper 服务器上的
/dubbo/com.dlhjw.dubbo.service.impl.TestServiceImpl/providers
目录下创建当前服务的 URL; com.dlhjw.dubbo.service.impl.TestServiceImpl
表示发布服务的接口全路径名称;providers
表示服务提供者的类型;dubbo://ip:port
表示该服务发布的协议类型及访问地址;- URL 是临时节点,其他皆为持久化节点;
- 在 Zookeeper 服务器上的
- 当 Dubbo 服务消费者启动时:
- 对
/dubbo/com.dlhjw.dubbo.service.impl.TestServiceImpl/providers
目录下子节点注册 Watcher 监听; - 服务消费者会在
/dubbo/com.dlhjw.dubbo.service.impl.TestServiceImpl/consumers
目录下写入自己的 URL; - 服务消费者如果需要调用 TestServiceImpl 服务,它会先去
/dubbo/com.dlhjw.dubbo.service.impl.TestServiceImpl/providers
路径下获得所有该服务的提供方 URL 列表,然后通过负载均衡算法计算出一个地址进远程访问;
- 对
1.7 下面示例的相关说明
- 客户端(在这里体现不出来)调用服务消费者的
http://consumer/zk
接口,请求消费者的资源; - 接着服务消费者通过负载均衡算法调用
http://zkcloud-provider/provider/zk
接口,请求服务提供者的资源;
2. 安装并运行 Zookeeper 服务器
基于 Win10 下的 Zookeeper 服务器安装;
2.1 下载 Zookeeper
- 访问连接:https://zookeeper.apache.org/releases.html;
- 下载解压后:
2.2 修改配置
- 到
apache-zookeeper-3.7.0-bin\apache-zookeeper-3.7.0-bin\conf
目录下,备份一份 zoo_sample.cfg 配置文件;
- tickTime:Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每隔 tickTime 时间就会发送一个心跳;
- dataDir:Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里;
- dataLogDir:Zookeeper 保存日志文件的目录;
- clientPort:客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求;
- 注意:查看 bin 目录下的 zkEvn.cmd 里的 JAVA_HOME 名字对不对;
2.3 运行 Zookeeper 服务器
- 到 bin 目录下:
- 双击 zkServer.cmd,会启动一个 java 进程,即服务端;
- 双击 zkCli.cmd,会启动一个客户端 ;
3. 使用 Zookeeper 管理服务提供者
使用 Zookeeper 构建服务提供者大致与 Nacos 和 Consul 相同; Nacos 与 Consul 的构建方式详情请见《3.2 Alibaba Nacos 注册中心》与《3.4 HashiCorp Consul 注册中心》;
3.1 引入 pom.xml 依赖
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本,这里可根据自己本地的下载的 zookeeper 版本进行配置-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
- Spring 管理的依赖自带 3.5.3beta 版本,与本地的下载的 zookeeper 版本对应不上,可以通过修改 pom 文件解决;
3.2 修改 boostrap.yml 配置文件
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: zkcloud-provider
cloud:
zookeeper:
connect-string: 192.168.111.144:2181
3.3 在主启动类上添加注解
- @EnableDiscoveryClient:使用其他组件(Nacos、zookeeper、Consul)作为注册中心;
3.4 编写业务类,并在 controller 层开放接口
这里编写一个简单接口仅作为示例;
@RestController
public class providerController{
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/provider/zk")
public String providerzk(){
return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();
}
}
4. 使用 Zookeeper 管理服务消费者
使用 Zookeeper 构建服务消费者大致与 Nacos 和 Consul 相同; Nacos 与 Consul 的构建方式详情请见《3.2 Alibaba Nacos 注册中心》与《3.4 HashiCorp Consul 注册中心》;
4.1 引入 pom.xml 依赖
同服务提供者端的依赖;
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
4.2 修改 boostrap.yml 配置文件
server:
port: 80
spring:
application:
name: zkcloud-consumer
cloud:
#注册到zookeeper地址
zookeeper:
connect-string: 192.168.111.144:2181
4.3 主启动类上不需要添加额外注解
4.4 编写业务类,调用提供者接口
- 由于我们使用 Ribbon + RestTemplate 的负载均衡策略,因此需要在 IoC 容器中添加一个 RestTemplate JavaBean;
- 详情请见《4.1 基于 Ribbon 的负载均衡详解》;
- 该 Bean 可以在主启动类中添加;也可以在主启动类所在包或子包的 config 包中添加,如下:
@Configuration
public class ApplicationContextBean{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 我们在 controller 层开放接口给客户端,并在该接口里调用提供者的 API;
@RestController
public class ComsumerZKController{
public static final String INVOKE_URL = "http://zkcloud-provider";
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/zk")
public String paymentInfo(){
String result = restTemplate.getForObject(INVOKE_URL+"/provider/zk", String.class);
System.out.println("消费者调用提供者获取服务--->result:" + result);
return result;
}
}
5. Dubbo 使用 Zookeeper 作为注册中心
- 详情请见:本系列另外一篇文章《12.1 使用 Apache Dubbo 实现远程通信》里的《5. Dubbo 使用 Zookeeper 作为注册中心》;
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!
微服务架构 | 3.3 Apache Zookeeper 注册中心的更多相关文章
- 微服务架构 | 3.2 Alibaba Nacos 注册中心
目录 前言 1. Nacos 基础知识 1.1 Nacos 命名方式 1.2 Nasoc 是什么 1.3 Nacos 的 4 个关键特性 1.4 Nacos 生态图 1.5 Nacos 架构图 1.6 ...
- 微服务架构 | 3.4 HashiCorp Consul 注册中心
目录 前言 1. Consul 基础知识 1.1 Consul 是什么 1.2 Consul 的特点 2. 安装并运行 Consul 服务器 2.1 下载 Consul 2.2 运行 Consul 服 ...
- 微服务架构 | 3.1 Netflix Eureka 注册中心
目录 前言 1. Eureka 基础知识 1.1 Eureka 模型中的服务器与客户端 1.2 Eureka 的 30s 启动机制 1.3 Eureka 为什么注册服务的 IP ,而不是主机名 1.4 ...
- 基于docker部署的微服务架构(四): 配置中心
原文:http://www.jianshu.com/p/b17d65934b58%20 前言 在微服务架构中,由于服务数量众多,如果使用传统的配置文件管理方式,配置文件分散在各个项目中,不易于集中管理 ...
- Spring Cloud构建微服务架构(四)分布式配置中心(续)
先来回顾一下,在前文中我们完成了什么: 构建了config-server,连接到Git仓库 在Git上创建了一个config-repo目录,用来存储配置信息 构建了config-client,来获取G ...
- SpringCloud微服务实战:一、Eureka注册中心服务端
1.项目启动类application.java类名上增加@EnableEurekaServer注解,声明是注册中心 1 import org.springframework.boot.SpringAp ...
- 历史上最详细的SpringCloud搭建微服务的过程。(包括注册中心,服务提供者和服务消费者)
首先搭建注册中心,创建一个springboot的maven工程. 工程创建完成之后,先在资源文件中的application.properties中写配置文件. server.port= spring. ...
- Spring Cloud构建微服务架构(四)分布式配置中心
Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持.配置服务器为各应用的所有环境提供了一个中心化的外部配置.它实现了对服务端和客户端对Spring Environm ...
- Spring Cloud构建微服务架构(二)分布式配置中心
注:此文不适合0基础学习者直接阅读,请先完整的将作者关于微服务的博文全部阅读一遍,如果还有疑问,可以再来阅读此文,地址:http://blog.csdn.net/sosfnima/article/d ...
随机推荐
- Notepad++ 常用功能:批量取消替换换行、强制刷新数据
批量取消替换换行 换行批量替换成空格 Ctrl+F 打开查找替换窗口,使用:\r\n 替换成 空格,全部替换 强制刷新数据源,重新加载数据 快捷键:Ctrl+R 或者 Alt+F 然后 L 或者点击菜 ...
- 『与善仁』Appium基础 — 25、APP模拟手势高级操作
目录 1.手指轻敲操作 2.手指按下和抬起操作 3.等待操作 4.手指长按操作 5.手指移动操作 6.综合练习 APP模拟手势的动作都被封装在TouchAction类中,TouchAction是App ...
- 如何完成符合ISO 26262要求的基于模型设计(MBD)的测试
背景介绍 随着汽车行业的迅速发展,汽车的复杂程度不断增加,越来越多的汽车电子控制系统具有与安全相关的功能,因此对ECU的安全要求也越来越高.复杂的软件功能,将会带来大量的软件风险问题,如何保证软件的安 ...
- WPF之交互触发器(CallMethodAction)学习
需求背景: 当我们需要制作画板时,我们的VM需要记录我们的坐标并保存到Path的Data中,用我们普通的Command是无法办到的,这时我们就衍生出来了一个交互触发器CallMethodAction ...
- 金山云 KS3 Python SDK 多线程并发上传文件;下载断点续传 参考脚本
并发上传 基于py自带模块 concurrent.futures import ThreadPoolExecutor #!/usr/bin/env python3 # -*- coding:utf-8 ...
- python2升级到python3 yum不可用解决方案
/usr/libexec/urlgrabber-ext-down /usr/bin/yum 这两个文件解释器 写 /usr/bin/python2
- Tornado 的安全性保障机制Cookie XSRF跨站请求伪造阻断 &用户验证机制
6.1 Cookie 对于RequestHandler,除了在第二章中讲到的之外,还提供了操作cookie的方法. 设置/获取 注意:Cookie 在浏览器调试时, 只有在第一次访问该网站的时候获取到 ...
- flexpaper上传带中文名字的文档,在页面显示若出现404错误时,请在server.xml文件中进行编码utf-8
flexpaper上传带中文名字的文档,在页面显示若出现404错误时,请在server.xml文件中进行编码utf-8
- SpringCloud微服务实战——搭建企业级开发框架(三十五):SpringCloud + Docker + k8s实现微服务集群打包部署-集群环境部署
一.集群环境规划配置 生产环境不要使用一主多从,要使用多主多从.这里使用三台主机进行测试一台Master(172.16.20.111),两台Node(172.16.20.112和172.16.20.1 ...
- 【机器学*】k-*邻算法(kNN) 学*笔记
[机器学*]k-*邻算法(kNN) 学*笔记 标签(空格分隔): 机器学* kNN简介 kNN算法是做分类问题的.思想如下: KNN算法的思想总结一下:就是在训练集中数据和标签已知的情况下,输入测试数 ...