ZooKeeper
- ZooKeeper如何解决分布式系统面临的问题
ZooKeeper存储了任务的分配,完成情况等共享信息,每个分布式应用的节点就是组员,订阅这些共享信息。当主节点对某个从节点的任务分工信息作出改变时,相关订阅的从节点得到ZooKeeper的通知,取得自己最新的任务分配。完成工作后,把完成情况存储到ZooKeeper。主节点订阅了该任务的完成情况信息,所以将得到ZooKeeper的完工的通知。
ZooKeeper的基础概念
集群角色
ZK引入了Leader、follower、Observer三种角色。Zk集群中所有机器通过Leader选举来选定一台被称为Leader的机器,Leader服务器为客户端提供读和写服务,除Leader外,其他机器包括follower和Observer,都能提供读服务,唯一区别在于Observer不参与Leader选举过程,不参与写操作的过半写成功策略,因为Observer可以在不影响写性能的情况下提升集群的性能。
角色联动图:

其实就是paxos协议的原理
- follower接收到客户端发送的写请求,会把该请求转发给leader来处理
- leader接收到follower发送的写请求后,会把该请求转换成带有各种状态的事务,会把该事务进行广播。(发送proposal)
- 所有接收到proposal的follower就要进行投票,都需要想leader返回ACK,如果多数同意。
- leader发送事务提交请求。
全程只有leader和follower会参与写和投票,Observer只在接收到事务提交请求后执行leader发布的对应的操作。Observer的出现可以减少投票的成本,提高性能。
- 会话(Session)
一个客户端连接是指客户端和服务器之间的一个TCP长连接。
客户端能够心跳检测与服务器保持有效的会话,也能够向ZK服务器发送请求并接收响应,同时还能够通过该连接接受服务器的watch事件通知。
- 数据节点(Znode)
数据模型中的数据单元
每个Znode都会保存自己的数据内容,同时还会保存一系列属性信息。
- 版本
ZK的每个Znode上都会存储数据,对于每个Znode,ZK都会为其维护一个Stat的数据结构,Stat记录了这个Znode的三个版本数据,version(当前Znode的版本)、cversion(当前Znode子节点的版本)、aversion(当前Znode的ACL版本)
- Watcher(事件监听)
ZK非常重要的特性,ZK允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZK服务端会将事件通知到感兴趣的客户端。
ACL
ZK的五种权限
- CREATE:创建子节点的权限
- READ:获取节点和子节点列表的权限
- WRITE:更新节点数据的权限
- DELETE:删除子节点的权限
- ADMIN:设置节点ACL的权限
ZK的环境搭建
- 单机模式:只运行在一台服务器上
- 集群模式:运行在一个集群上
- 伪集群模式:在一台服务器上运行多个ZK实例
集群搭建时,需要配置客户端访问端口和集群服务器IP列表
server.1=10.211.55.4:2881:3881
server.2=10.211.55.4:2882:3882
server.3=10.211.55.4:2883:3883
server.服务器ID=服务器IP地址:服务器之间的通讯端口:服务器之间的投票选举端口
ZooKeeper系统模型
Znode
持久性节点:
ZK最常见的节点类型,节点被创建后就一直存在服务器,直到删除操作主动删除
持久顺序节点:
就是有顺序的持久节点,在创建节点的时候,在节点名后面加上一个数字用来表示顺序。
临时节点:
会被自动清理的节点。生命周期和客户端会话保持在一起,客户端会话结束,节点会被删除。
临时节点不能创建子节点
临时顺序节点:
有顺序的临时节点,在创建的时候名字后面加上数字后缀
事务ID
一般事务:
ACID特性:原子性,一致性,隔离性和持久性。
ZK事务:
事务是改变ZK服务器状态的操作,节点更新,删除,创建。对于每一个事务,ZK会为其分配一个全局唯一的ZXID,每个ZXID对应一次更新操作,从这些ZXID可以识别出ZK处理这些操作的顺序。
Watcher-数据变动通知

ACL-保障数据的安全
可以从三个方面来理解ACL机制:通常使用“scheme:id :permission”来标识一个有效的ACL信息。
- 权限模式:Scheme
用来确认权限验证过程中使用的检测策略
IP
通过IP地址粒度来进行权限控制,可以配置网段。
Digest(最常用)
使用“username:password"来进行权限控制,用于区分不同应用。
World
开放模式,权限控制几乎没有任何作用,数据节点的访问控制权限对所有用户开放。
Super
超级权限,可以对任意节点进行任何操作。
- ID(授权对象)
权限赋予的用户或者实体,例如IP地址或是机器等。
- 权限
CREATE:创建子节点的权限
READ:获取节点和子节点列表的权限
WRITE:更新节点数据的权限
DELETE:删除子节点的权限
ADMIN:设置节点ACL的权限
ZK应用场景
- 数据发布订阅
ZK采用推拉相结合的模式,客户端向服务器注册自己需要关注的节点,一旦该节点的数据发生改变,服务器会想相应的客户端发送Watcher事件通知。客户端接收到这个消息通知之后,主动到服务器获取最新的数据。
可以把服务器公用的一些配置信息都配置到ZK上,如果需要改变,只需要改变ZK上的配置信息,其他应用服务器接收到对应的watcher事件,自动更新配置信息。
- 命名服务
分布式ID,可以利用ZK创建一个顺序节点,每次需要生成时,客户端根据自己的任务类型来请求ZK创建一个顺序节点,来做一个全局唯一的ID。
- 集群管理
客户端对ZK的数据节点注册Watcher,当该节点的内容和其子节点发生变化时,ZK服务器会向订阅的客户端发送变更通知。
在ZK上创建的临时节点,一旦服务器和客户端之间的会话失效,那么临时节点也会自动删除。
利用上面的两个特性,可以用ZK实现集群管理。
所有客户端都监听同一个节点,然后每个客户端都在此节点下面创建一个临时节点,节点的内容是自己的服务器信息。
- 分布式日志收集系统
主要工作,收集不同服务器上的系统日志。
- 使用ZK来进行日志系统收集器的注册,在ZK上创建一个节点作为收集器的根节点,每个收集器在启动的时候都在这个节点下创建自己的节点
- 系统根据注册在ZK上的收集器节点个数,来把所有的日志分组,然后将不同的组分给不同的收集器。开始日志收集。
- 这些机器随时有可能挂掉,因此要有任务汇报机制,每个收集器在自己创建的节点下面在创建一个stat节点,定期在stat节点里写入状态信息,可以把这样看成是一种心跳检测机制。可以根据stat节点更新的时间判断是否存活。
- 如果有机器挂掉了,或者扩容,都需要进行任务的动态分配。所有机器都检测ZK的节点,一旦新增或者缺少了一个节点,所有机器都重新分配任务。
分布式锁
不同的系统之间共享一块相同的资源。为了安全就需要使用分布式锁。有与日常生产中数据库负载较大,所以如果轻易的给数据库增加一个锁,会极大的影响系统的性能。所以需要引入第三方工具来控制锁。
排它锁
简称X锁,独占锁,只能有一个事务读取和释放锁。
- 定义锁
通过ZK的数据节点来表示一个锁。创建一个demo-lock节点
- 获取锁
当所有客户端想要尝试获取锁时,都会在上面创建的demo-lock节点下创建一个临时子节点lock,所有客户端创建的节点名字相同,最终只能有一个客户端可以成功创建这个子节点。其他客户端都监听demo-lock,当之前的lock被释放后,这些客户端再尝试获取锁。
- 释放锁
当获取锁的客户端主动删除节点,或者获取锁的客户端挂掉,对应的临时节点自动删除。此锁被释放。

共享锁
S锁,又被称为读锁。
如果一个事务对O1上共享锁,当前事务只能读取操作,其他事务也只能读取,当其他事务的共享锁都释放,此事务才能更改O1、
- 定义锁
在一个节点下创建一个临时顺序节点,这个节点代表共享锁。/shared_lock/host_1-R-000001;
- 获取锁
所有客户端都会在shared_lock目录下创建一个临时节点,如果是读请求,就创建-R节点,如果是写请求,就创建-W节点。
- 创建节点后,获取/shared_lock节点下所有子节点,并注册监听这些节点。
- 确认自己的节点序号在所有节点中的顺序。
- 对于读请求:若没有比自己序号小的子节点或所有比自己序号小的子节点都是读请求,那么表明自己已经成功获取到共享锁,同时开始执行读取逻辑,若比自己序号小的有写请求,则需要等待。对于写请求,若为写请求,自己不是序号最小的子节点,就需要等待。
- 接收到Watcher通知后,重复步骤1.
- 释放锁
与排它锁一样。
- 共享锁存在问题,羊群效应
假设一个锁节点下注册着大量的客户端,当编号为1的节点被删除,ZK会通知所有监听这个节点事件的客户端,但实际上,只有编号2的客户端可以进行操作,其他编号的客户端没有受到影响。这样会产生大量的网络开销,如果短时间内,多个节点消失,ZK会向所有客户端发送大量的事件通知。
优化方案,每个客户端新建节点是,不用订阅目录下所有的节点,只需要订阅比自己序号小节点就可以。
读请求:订阅比自己序号小的最后一个节点就可以。
写请求:向比自己序号小1的节点注册Watcher事件监听。

分布式队列
分布式队列主要分两大类
FIFO:先入先出队列模型
Barrier:等待队列元素聚集后统一安排处理执行。
- FIFO:先入先出队列
类似于一个全写的共享锁模型、
所有的客户端都会在一个节点下创建顺序临时节点
确定执行步骤:
- 获取节点下的所有子节点,节点列表
- 确定自己的节点的序号在所有节点中的顺序
- 判断自己的节点是否为最小,如果不是就等待,向比自己小的最后一个节点注册Watcher监听。
- 接收Watcher通知,重复步骤1.
- Barrier 分布式屏障
一个队列的所有元素必须都聚集后才能统一进行安排,否则一直等待。
新建一个节点,给这个节点赋值,例如10,就是有十个是客户端节点入队后,这个队列才会执行
- 客户端获取节点的数据内容(10)
- 获取该节点下的所有临时节点,同时注册这个节点的Watcher监听,
- 统计子节点个数
- 如果子节点不足十个,就等待。
- 达到十个就执行。
ZAB协议
ZK并没有完全采用paxos算法,而是使用ZAB协议作为数据一致性的核心算法。
ZAB是一种特别为ZK设计的支持崩溃回复的原子广播协议。
- 概念
ZK使用一个单一的主进程来接收并处理客户端所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以事务的形式广播到孙哦在的副本进程中,ZAB协议保证了同一时刻集群中只能够有一个主进程广播服务重启的状态变更,因此可以很好的处理客户端大量的并发请求,但是主进程在任何时候都有可能会出现崩溃,退出重启的现象,ZAB协议还做到了,当前主进程出现上述情况时,依然能正常工作。
- ZAB核心
定义了对于那些会改变ZK服务器数据的事务请求的处理方式
所有事务请求必须由一个全局唯一的服务器来协调处理,这个服务器被称为leader服务器,余下的服务器称为Follower服务器,Leader服务器负责把客户端事务请求转化成一个事务Proposal(提议),并将该事务分发给集群中所有的follower,leader服务器需要等待所有follower服务器的反馈,一旦超过半数同意(ACK),那么Leader服务器就会再次向所有的follower服务器发出Commit消息,表示提交这个事务。

- 崩溃恢复模式
leader服务器出现网络中断,异常情况时,会重新选举leader服务器,选举的新leader服务器的到半数以上的服务器和该机器同步了数据,就认定新机器为新的leader服务器。
选举leader时,会优先选举拥有最高事务编号的服务器成为新的leader。
- ZAB和paxos的联系和区别
相同:
- 都存在一个类似于leader的角色,其负责协调多个Follower进程的运行。
- Leader进程都会等待超过半数的Follower作出正确的反馈后,才会提交事务。
- 每个任期中,都包含一个值,代表当前Leader的周期。
不同:
paxos算法中,新选举产生的主进程会进行两个阶段的工作,第一阶段为读,新的主进程和其他进程通信来收集主进程提出的提议,并将他们提交。第二阶段写,当前主进程开始提出自己的提议。
ZAB协议在paxos的基础上添加了同步阶段,新的Leader会确保存在过半的Follower已经提交了之前的Leader周期中的所有事务。这一同步阶段的引入,能够有效的保证新的Leader在新周期中提出事务之前,所有进程已经完成了对之前所有事务的提交。
总体来说,ZAB协议和paxos算法在设计目标上不太一样,ZAB协议主要为了构建一个高可用的分布式数据主备系统,而paxos主要为了构建一个分布式的一致性状态机系统。
- 启动过程
- 配置文件解析
- 初始化数据管理器
- 初始化网络I/O管理器
- 数据恢复
- 对外服务

Dubbo
一款高性能的java RPC 框架
- 分布式SOA系统

- Dubbo的三大特新
面向接口的远程方法调用
智能容错和负载均衡
服务自动注册和发现
- 调用关系说明

虚线代表异步调用,实线代表同步调用,
蓝色虚线表示启动时完成的,红色虚线表示程序运行中执行的
节点说明:
| 节点 | 角色名称 |
|---|---|
| Provider | 暴露服务的服务器提供方 |
| Consumer | 调用远程服务的服务消费方 |
| Registry | 服务器注册与发现的注册中心 |
| Monitor | 统计服务的调用次数和调用时间的监控中心 |
| Container | 服务运行容器,负责启动,加载,运行服务提供者 |
- 流程
- 服务提供者启动时在注册中心注册自己提供的服务
- 消费者在启动时向注册中心订阅自己所需的服务
- 注册中心给消费者返回服务提供者的地址,如果服务变更,注册中心会基于TCP长连接给消费者推送更新的服务列表
- 服务消费者从服务提供者列表中,基于负载均衡算法,选一台调用如果调用失败,就重新选择一台
- 服务的提供者和消费者,定时每分钟把调用次数和调用时间发给监控中心