分布式数据一致性的解决方案
架构
客户端<------------->ZooKeeper集群(至少三台,建议奇数)
ZooKeeper 客户端库将选择一个任意服务器并尝试连接到它。如果此连接失败,或者客户端因任何原因与服务器断开连接,客户端将自动尝试列表中的下一个服务器,直到(重新)建立连接。
架构
Server角色:Leader、Follower和Observer
- Leader:
- 事务请求的唯一调度和处理者,保证集群事务处理的顺序性
- 集群内部各服务的调度者
- Follower
- 处理客户端非事务请求,转发事务请求给Leader服务器
- 参与事务请求Proposal的投票
- 参与Leader选举投票
- Observer:观察ZooKeeper集群的最新状态变化并将这些状态变更同步过来
- 处理客户端的非事务请求,转发事务请求给 Leader 服务器
- 不参与任何形式的投票
Server工作状态
- LOOKING:寻找Leader状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。
- FOLLOWING:跟随者状态。表明当前服务器角色是Follower。
- LEADING:领导者状态。表明当前服务器角色是Leader。
- OBSERVING:观察者状态。表明当前服务器角色是Observer。
主从节点一致
- Leader服务器挂了,所有集群中的服务器进入LOOKING状态
- 首先,它们会选举产生新的Leader服务器
- 接着,新的Leader服务器与集群中Follower服务进行数据同步
- 当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式
- Leader 服务器开始接收客户端的事务请求生成事务Proposal进行事务请求处理。
选举机制
(1)启动时
选举
- 服务器1(myid=1)启动,当前只有一台服务器,无法完成Leader选举
- 服务器2(myid=2)启动,此时两台服务器能够相互通讯,开始进入Leader选举阶段
- 每个服务器发出一个投票
包含zxid、myid,zxid表示当前节点最新存储的数据的事务编号 - 接受来自各个服务器的投票
- 每个服务器都会接受来自其他服务器的投票。同时,服务器会校验投票的有效性,是否本轮投票、是否来自LOOKING状态的服务器。
- 处理投票
- 收到其他服务器的投票,会将被人的投票跟自己的投票PK,PK规则如下:
优先检查ZXID。ZXID比较大的服务器优先作为leader。
如果ZXID相同的话,就比较myid,myid比较大的服务器作为leader。 服务器1的投票是(1,0),它收到投票是(2,0),两者zxid都是0,因为收到的myid=2,大于自己的myid=1,所以它更新自己的投票为(2,0),然后重新将投票发出去。对于服务器2呢,即不再需要更新自己的投票,把上一次的投票信息发出即可。
- 统计投票
- 每次投票后,服务器会统计所有投票,判断是否有过半的机器接受到相同的投票信息。服务器2收到两票,少于3(n/2+1,n为总服务器),所以继续保持LOOKING状态
- 服务器3(myid=3)启动,继续进入Leader选举阶段
- 跟前面流程一致,服务器1和2先投自己一票,因为服务器3的myid最大,所以大家把票改投给它。此时,服务器为3票(大于等于n/2+1),所以服务器3当选为Leader。 服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
- 服务器4启动,发起一次选举。
- 此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。选票信息结果:服务器3为3票,服务器4为1票。服务器4并更改状态为FOLLOWING;
- 服务器5启动,发起一次选举。
- 同理,服务器也是把票投给服务器3,服务器5并更改状态为FOLLOWING;
- 投票结束,服务器3当选为Leader
(2)Leader挂了,重新选举
其中第二步仅限于余下的非Observer服务器
重新选举
数据模型:层次模型(文件系统模型)
分层命名空间
节点类型
- 持久节点
- 持久顺序节点
- 临时节点
- 临时顺序节点
分布式锁(临时顺序节点)
- 获取锁过程 (创建临时节点,检查序号最小)
- 释放锁 (删除临时节点,监听通知)
分布式锁和Redis的对比
Zookeeper是强一致性(CP),Redis是最终一致性(AP),而且前者当获取不到锁时,只需添加一个监听器即可,不用一直轮询,性能消耗小。更推荐Zookeeper
1.获取锁
- 当第一个客户端请求过来时,Zookeeper客户端会创建一个持久节点/locks。如果它(Client1)想获得锁,需要在locks节点下创建一个顺序节点lock1
- 客户端Client1会查找locks下面的所有临时顺序子节点,判断自己的节点lock1是不是排序最小的那一个,如果是,则成功获得锁
-
这时候如果又来一个客户端client2前来尝试获得锁,它会在locks下再创建一个临时节点lock2
创建临时节点
- 客户端client2一样也会查找locks下面的所有临时顺序子节点,判断自己的节点lock2是不是最小的,此时,发现lock1才是最小的,于是获取锁失败。获取锁失败,它是不会甘心的,client2向它排序靠前的相邻节点lock1注册Watcher事件,用来监听lock1是否存在,也就是说client2抢锁失败进入等待状态。
2.释放锁
- Client1会显式调用删除lock1的指令,如果是客户端故障了,根据临时节点得特性,lock1是会自动删除的
- lock1节点删除,Client2立刻收到通知,也会查找locks下面的所有临时顺序子节点,发下lock2是最小,就获得锁
节点存储的数据(尽量小于1k,不能超过1M)
存储数据、访问权限、子节点引用、节点状态信息
节点数据
使用场景
- 命名服务:通过「指定的名字」来获取资源或者服务地址
Zookeeper可以创建一个「全局唯一的路径」,这个路径就可以作为一个名字。被命名的实体可以是「集群中的机器,服务的地址,或者是远程的对象」等。一些分布式服务框架(RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据特定的名字来获取资源的实体、服务地址和提供者信息等。 - 配置管理:
把程序的配置信息「保存在zk的znode节点」下,当你要修改配置,即znode会发生变化时,可以通过改变zk中某个目录节点的内容,利用「watcher通知给各个客户端」,从而更改配置。 - 集群管理
实时监控znode节点的变化,一旦发现有机器挂了,该机器就会与zk断开连接,对用的临时目录节点会被删除,其他所有机器都收到通知。新机器加入也是类似酱紫,所有机器收到通知:有新兄弟目录加入啦。
有条件的更新和监视
ZooKeeper支持 watch 的概念。客户端可以在 znode 上设置监视,并与server建立长连接。当 znode 发生变化时,watch 被触发时,server通过长连接向客户端发送消息,客户端会收到一个数据包,说明 znode 已更改。如果客户端和其中一个 ZooKeeper 服务器之间的连接断开,客户端将收到本地通知。
ACL访问控制
- 仅适用于特定的znode,不适合child_node,不是递归的
- 权限有:
- CREATE:您可以创建一个子节点
- READ:您可以从节点获取数据并列出其子节点。
- WRITE:您可以为节点设置数据
- DELETE:您可以删除一个子节点
- ADMIN:您可以设置权限
- 对象类型:
- world有一个 id,anyone,它代表任何人。
- auth是一个特殊的方案,它忽略任何提供的表达式,而是使用当前用户、凭据和方案。在持久化 ACL 时,ZooKeeper 服务器会忽略提供的任何表达式(无论是使用 SASL 身份验证的用户还是使用DIGEST 身份验证的user:password )。但是,仍必须在 ACL 中提供表达式,因为 ACL 必须匹配格式scheme:expression:perms。提供此方案是为了方便,因为它是用户创建 znode 然后将对该 znode 的访问限制为仅该用户的常见用例。如果没有经过身份验证的用户,使用 auth 方案设置 ACL 将失败。
- 摘要使用用户名:密码字符串生成 MD5 哈希,然后将其用作 ACL ID 身份。通过以明文形式发送用户名:密码来完成身份验证。在 ACL 中使用时,表达式将是username:base64编码的SHA1密码摘要。
- ip使用客户端主机 IP 作为 ACL ID 身份。ACL 表达式的格式为addr/bits,其中addr的最高有效位与客户端主机 IP的最高有效位相匹配。
- x509使用客户端 X500 Principal 作为 ACL ID 身份。ACL 表达式是客户端的确切 X500 主体名称。使用安全端口时,客户端会自动进行身份验证,并设置 x509 方案的身份验证信息。
一致性保证
- 顺序一致性:来自客户端的更新将按照它们发送的顺序应用。
- 原子性:更新成功或失败——没有部分结果。
- 单一系统映像:客户端将看到相同的服务视图,而不管它连接到哪个服务器。即,即使客户端故障转移到具有相同会话的不同服务器,客户端也永远不会看到系统的旧视图。
- 可靠性:一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来。
- 及时性:保证系统的客户端视图在一定的时间范围内(大约几十秒)是最新的。客户端将在此范围内看到系统更改,或者客户端将检测到服务中断。








网友评论