- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
我们平常的开发过程中,经常会碰到这样的需求:系统中需要一些通用的配置信息,如一些运行时的开关、前端需要展示的通知信息、数据库配置信息等等。这些需求通常都要求具备3个特性:
我们假设把这些数据存储在应用的内存中,那么数据共享是一个问题,数据变更的通知又是一个问题。
那我们使用Zookeeper怎么实现呢?
我们可以先把数据存储在Zookeeper的一个节点上。如/app/database_config
2. 配置获取
应用启动时,首先会去前面存储的节点上去拿数据,并且在这个节点上注册一个数据变更的Watcher监听。一旦发送数据变化,集群中所有应用都能收到通知
3. 配置变更
我们需要修改的时候,就利用Zookeeper的修改内容接口对节点上的数据进行修改即可。Zookeeper会自动帮我们发送数据变更通知。
命名服务是分布式系统中比较常见的一个场景。比如我们需要在创单的时候给这个订单生成一个全局唯一的订单号。如果是单体应用那么还比较好做,数据库就有自增ID,再拼上一些订单号前缀就可以了。但是如果是分布式环境下,就会麻烦一些。
那我们使用Zookeeper怎么实现呢?
我们有时候有这样的一个需求,在集群环境下,只需要一个应用来处理某个耗时资源。我们可以怎么处理呢?
先假设我们通过数据库来处理,我们向一个表中插入同样的一个id的数据,根据数据库主键的唯一特性,只有一个应用能够操作成功,那么这个应用就可以被选中成为Master,来执行这个耗时的操作。
但是我们考虑下面这个问题:如果被选中的这个Master机器宕机了,怎么告诉其他机器重新选举呢?不好实现。
利用Zookeeper可以实现这样的需求。
Zookeeper是一个比较知名的实现分布式锁的一个方案。我们分排他锁和共享锁两类来讲解。
排他锁
排他锁,又称写锁或独占锁。如果事务T1对数据对象A加了排他锁,那么整个加锁期间,其他事务都不能对这个对象A进行任何类型的操作,知道事务T1释放了排他锁。
下⾯我们就来看看如何借助ZooKeeper实现排他锁:
也可以创建临时有序节点,只监听比自己小一位的那个子节点。避免持有锁的节点执行完释放锁的时候就需要通知所有监听着的应用(羊群效应)。
共享锁
共享锁,又称读锁。如果事务T1对对象A加了共享锁,那么当前事务只能对A进行读操作。其他事务T2、T3也能对这个对象加共享锁。
分布式队列
分布式队列可以简单分为两⼤类:⼀种是常规的FIFO先⼊先出队列模型,还有⼀种是等待队列元素聚集后统⼀安排处理执⾏的Barrier模型
FIFO(First Input First Output)
使用Zookeeper实现FIFO队列,也是依赖于Zookeeper的顺序节点特性。思路如下:
Barrier:分布式屏障
分布式屏障特指系统的一个协调条件,规定队列中的元素聚齐后才能进行统一安排。比如所有的员工都把工作做完了,才一起下班去吃饭。
设计思路如下:
创建一个/queue_barrier节点,并且给这个节点赋值数字n,这个n代表只有当/queue_barrier节点下有n个子节点时,才能进行下一步操作。
zookeeper就是使用了ZAB协议来实现的分布式数据一致性。ZAB协议是专门为zookeeper设计的一种支持崩溃恢复的原子广播协议。
ZAB核心
ZAB协议定义了那些会改变Zookeeper服务器数据状态的事务请求的处理方式。
所有这些会修改状态的事务请求必须由一个全局唯一的服务器来协调处理,也就是Leader服务器。Leader服务器负责将客户端请求转化为事务Proposal(提议),并将Proposal分发给集群中所有的Follower服务器,之后Leader服务器需要等待所有Follower服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,Leader接下来就会再次向所有的Follower服务器发Commit消息,把刚才的Proposal进行提交。
ZAB两种模式:崩溃恢复和消息广播
消息广播
在消息⼴播过程中,Leader服务器会为每⼀个Follower服务器都各⾃分配⼀个单独的队列,然后将需要⼴播的事务Proposal依次放⼊这些队列中去,并且根据 FIFO策略进⾏消息发送。每⼀个Follower服务器在接收到这个事务Proposal之后,都会⾸先将其以事务⽇志的形式写⼊到本地磁盘中去,并且在成功写⼊后反馈给Leader服务器⼀个Ack响应。当Leader服务器接收到超过半数Follower的Ack响应后,就会⼴播⼀个Commit消息给所有的Follower服务器以通知其进⾏事务提交,同时Leader⾃身也会完成对事务的提交,⽽每⼀个Follower服务器在接收到Commit消息后,也会完成对事务的提交。
我们考虑如下两个问题:
解决这个问题需要ZAB的崩溃恢复模式
崩溃恢复
Leader宕机后
针对上面两个要求,如果让Leader选举算法能够保证新选举出来的Leader服务器拥有集群中所有机器最⾼编号(即ZXID最⼤)的事务Proposal,那么就可以保证这个新选举出来的Leader⼀定具有所有已经提交的提案。他成了Leader后他有的事务肯定是已提交的所有事务了。
新Leader产生后,在正式开始⼯作(即接收客户端的事务请求,然后提出新的提案)之前,
Leader服务器会⾸先确认事务⽇志中的所有Proposal是否都已经被集群中过半的机器提交了,即是否完成数据同步。
数据同步
它会为每一个Follower服务器准备一个队列,将那些没有被各Follower服务器同步的事务以Proposal消息的方式发送给Follower服务器,并在每一个Proposal消息后紧接着再发送一个Commit消息。等到Follower服务器将所有尚未同步的事务都成功应用到本地数据库后,Leader服务器就会将该Follower服务器加入真正可用的Follower列表中。
运⾏时状态分析
在ZAB协议的设计中,每个进程都有可能处于如下三种状态之⼀
所有进程初始状态都是LOOKING状态,此时不存在Leader。接下来,进程会试图选举出⼀个新的Leader,如果进程发现已经选举出新的Leader了,那么它就会切换到FOLLOWING状态,并开始和Leader保持同步。处于FOLLOWING状态的进程称为Follower,LEADING状态的进程称为Leader,当Leader崩溃或放弃领导地位时,其余的Follower进程就会转换到LOOKING状态开始新⼀轮的Leader选举。
⼀个Follower只能和⼀个Leader保持同步,Leader进程和所有的Follower进程之间都通过⼼跳检测机制来感知彼此的情况。若Leader能够在超时时间内正常收到⼼跳检测,那么Follower就会⼀直与该Leader保持连接,⽽如果在指定时间内Leader⽆法从过半的Follower进程那⾥接收到⼼跳检测,或者TCP连接断开,那么Leader会放弃当前周期的领导,并转换到LOOKING状态,其他的Follower也会选择放弃这个Leader,同时转换到LOOKING状态,之后会进⾏新⼀轮的Leader选举。
ZAB与Paxos的联系和区别
联系:
区别:
总的来说,ZAB协议和Paxos算法的本质区别在于,两者的设计⽬标不太⼀样。ZAB协议主要⽤于构建⼀个⾼可⽤的分布式数据主备系统,⽽Paxos算法则⽤于构建⼀个分布式的⼀致性状态机系统。
最终,我们讨论一个问题
Zookeeper是属于强一致性还是弱一致性?
答案:写入是强一致,读取是顺序一致性。Zookeeper官方说是顺序一致性。
因为客户读连接ZooKeeper集群后,所有的写操作都必须发送给集群唯一的leader,这个leader在内部同步块中赋予每个写操作一个顺序序列号(内部称为zxid,是单调增加的),上一个写操作不commit,下一个写操作就不执行,这一点实际上已经实现了写入的强一致性(线性化)了
通过严格按照ZXID的顺序生效提案保证其顺序一致性的。
Zookeeper它还为我们提供sync()方法,强制读取在时候从Leader同步数据。
书山有路勤为径,学海无涯苦作舟
我正在尝试使用来自 Serge Zab 的 optgroup 下拉帮助器,可以找到 here . 这是我的类别表: 如您所见,我有一个类别,类别也可以是类别的类别父级。我希望将父类别作为 optgro
早上好 我是 ZooKeeper 及其协议(protocol)的新手,我对它的广播协议(protocol) Zab 很感兴趣。 能否提供一个使用Zookeeper的Zab协议(protocol)的简单
我是一名优秀的程序员,十分优秀!