服务注册中心组件Zookeeper
1 基础知识
1 Zookeeper概述
Zookeeper是一个为分布式应用提供一致性服务的中间件。它可以用于维护配置信息,命名,提供分布式同步和服务治理功能。
Zookeeper包括客户端和服务器两部分,服务器(服务器集群)负责提供服务,客户端通过连接服务器进行增删改查,监视等相关操作。
1.2 Zookeeper的特性
原子性:事务要么成功要么失败,不会局部化。
单一视图:客户端连接集群中的任一Zookeeper节点,数据都是一致的。
实时性:客户端可以读取到Zookeeper服务端的最新数据。
可靠性:每次对Zookeeper的操作状态都会保存在服务端。
1.3 Zookeeper的数据模型
Zookeeper是树形结构模型,每一个节点都可以有子节点,也可以有数据。节点分为临时节点和永久节点,临时节点在客户端断开后消失。
每当节点数据发生变化,该节点版本号会累加。删除/修改过时节点,版本号不匹配则会报错。每个Zookeeper节点存储的数据不宜过大(小于1M)。
节点可以设置权限,可以通过权限来限制用户的访问。
2 环境搭建及配置
2.1 环境搭建
单机环境:需要在zoo.cfg中配置相关的基本参数。基本参数包括各个心跳频率,端口号,数据文件地址DataDir和日志文件地址DataLogDir。
集群环境:需要在zoo.cfg中配置相关的基本参数和集群参数,集群参数的格式如下:server.id=host:port1:port2 。这个id是DataDir目录下Myid文件的内容。
host是该Zookeeper所在的IP地址,port1表示follower和leader交换消息所使用的端口,port2表示选举leader所使用的端口。
2.2环境配置
Zookeeper除了基本参数配置以外还有很多高级参数配置,这些高级参数都有默认值,我们也可以根据实际的业务环境进行手动配置。
2.3管理控制台搭建:
开源的Dubbo服务管理控制台主要包含:路由规则/动态配置/服务降级/访问控制/权重调整/负载均衡等管理功能。
在访问管理控制台之前,我们首先需要启动zookeeper的服务器,然后运行管理控制台的web项目即可。
管理控制台默认访问路径(默认账户密码为root/root)
3 客户端API操作
3.1使用Xshell操作zkCli
使用linux指令分别启动服务器和客户端,然后可以进行相关操作。注意:Zookeeper在创建节点的时候可以创建临时,持久,临时有序,持久有序四种节点,
临时有序节点在分布式锁和服务治理中有具体应用;Delete只能删除不包含子节点的节点,删除带子节点的节点应该使用rmr指令。
Zookeeper创建的节点包含了很多信息:
3.2 Java操作zkCli
使用java操作Zookeeper服务器,首先需要添加相关依赖并进行相应的配置,在进行操作的时候需要注意避免出现相同的节点名称,如果相同要记得删除,否则会产生异常。
3.3 Java操作Curator
Curator在原生API的基础上做了封装和改进,现已成为最流行的Zookeeper客户端之一。它提供了Zookeeper的各种应用场景:共享锁服务、Master选举机制和分布式计数器等。详情可参考demo:zk_curator或者:
3.4 Java操作Watcher
Zookeeper的watcher机制,数据结构和acl机制是zookeeper商用落地的重要前提。
client 端连接后会注册一个事件,然后客户端会保存这个事件,通过zkWatcherManager 保存客户端的事件注册, 服务端处理完成以后,由于客户端中有个线程不断地轮询Selector(NioSocket),当通知服务端 Watcher 为 true,然后服务端会通过WahcerManager 回调绑定path对应的事件。
创建时机:在创建节点时默认创建监听器。也可以实现watcher接口创建监听器。
创建流程:watcher先去服务器注册,注册成功之后将watcher存储到watchManager,然后返回结果给客户端。当事件触发的时候,客户端异步获取变更信息,然后开启线程从watchManager中回调watcher执行相应的功能。
触发条件:节点变化(节点新增,删除,修改,以及子节点的变化)会触发监听机制。
触发后的返回值:Zookeeper维护了两个Watch列表,一个节点数据Watch列表,另一个是子节点Watch列表。getData()和exists()监听节点数据,getChildren()监听子节点数据。事件触发后,
getData()和exists()返回节点的内容,getChildren()返回子节点列表。不同的通知状态代表的含义:
注意:
NodeDataChanged事件:无论节点数据发生变化还是数据版本发生变化都会触发,即使被更新数据与新数据一样,数据版本dataVersion都会发生变化
AuthFailed:客户端会话没有权限,访问失败可触发
详见请参考demo:zk_watcher或者:
3.5 Java操作Acl
Zookeeper的权限控制是基于每个节点的,需要对每个节点设置权限。每个节点支持设置多种权限控制方案和多个权限。子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点。
Zookeeper具有多种授权方式。正是acl权限机制保证了zookeeper的数据安全,因为API都不难,这里就不再赘述。详情请参考demo:zk_acl或者:
4 核心原理
4.1 ZAB协议:
4.2 FLE算法:
5 主要应用场景
Zookeeper主要包含以下几种应用场景:维护配置信息,命名服务,分布式协调统一,服务治理功能和实现分布式锁。由于市面上已经存在更好的分布式配置框架,所以我们只研究了后四种场景。
5.1命名服务:
5.1.1使用场景
分布式环境下将服务注册在zookeeper上,调用服务时可以依据服务的名称来找到对应的地址及端口号,简化了服务间调用的过程。在该场景下需要确保生成的节点具有唯一的编号。
5.1.2 如何保证
Zookeeper服务器中的数据模型是树形结构的,这就为节点的唯一性提供了保证。同时Zookeeper服务器可以创建临时有序节点,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建节点过程中,zookeeper会自动为给定节点名加上数字后缀,作为新的节点名。这样就保证了节点编号的唯一性和自增性。
5.1.3 参考资料
5.2分布式协调统一
5.2.1使用场景
对于一个分布式系统,通常都需要一个协调者来控制整个系统的运行流程。比如分布式事务、机器间的互相协调等。这样能将分布式协调的职责能从应用中分离出来,达到减少系统间的耦合性,提高系统的可扩展性。
5.2.2如何保证
ZAB协议是为zookeeper专门设计的一种支持崩溃恢复的原子广播协议。在zookeeper中,主要依赖ZAB协议来实现分布式数据一致性。
5.2.3 ZAB,FLE理论
5.3 负载均衡
5.3.1使用场景
适用于高访问量的业务,能提高应用程序的可用性和可靠性。应用于高访问量的业务可以提高访问效率;能更方便的扩展应用程序;消除单点故障同时具备了容灾能力。
5.3.2负载均衡策略
1随机负载均衡算法:每一次请求随机分配到各服务器,请求次数越大,分布越均匀。
2基于权重的负载均衡算法:根据权重确定轮循比率,支持手动配置权重。
3最小活动数算法:请求返回速度较慢的提供者将收到较少的请求。
4一致的哈希算法:根据一致性哈希算法,始终将请求参数相同的请求发送到同一个应用。当该应用崩溃时,基于虚拟节点算法将该请求路由到其他应用,不会引起负载上的剧烈变化。
5.3.3参考资料
5.4 分布式锁
5.4.1使用场景:
分布式锁是控制同步访问共享资源的一种方式。使用互斥的手段来防止彼此之间的干扰,以保证一致性。
5.4.2技术选型:
1数据库实现(性能差、线程出现异常时,容易出现死锁)
2 redis实现(使用redission实现,锁的失效时间难控制、容易产生死锁、非阻塞式、不可重入)
3 Zookeeper实现(实现相对简单、可靠性强、使用临时节点,失效时间容易控制)
4 Spring Cloud 实现全局锁(内置的)
5.4.3 关键代码及原理
什么时候获取锁:当前节点在所有的子节点中编号最小时获取锁。
什么时候释放锁:调用服务结束或者出现异常时会断开与zookeeper服务器的连接,此时临时有序节点会被删除即释放了锁。
其逻辑原理图如下: