赞
踩
来,上菜。
命名服务就是:
配置管理就是:
.properties
或者xml
需要配置很多信息,如数据库连接信息、fps地址端口等等。集群管理就是:
这个其实是zookeeper很经典的一个用法,简单来说,就好比,你A系统发送个请求到MQ,然后B系统消息消费之后处理了,那A系统如何知道B系统的处理结果?用 zookeeper 就可以实现分布式系统之间的协调工作。A系统发送请求之后可以在zookeeper 上对某个节点的值注册个监听器,一旦B系统处理完就修改zookeeper 那个节点的值,A系统立马就可以收到通知,完美解决。
举个栗子。对某一个数据连续发出两个修改操作,两台机器同时收到了请求,但是只能一台机器先执行完另外一个机器再执行。
那么此时就可以使用 zookeeper 分布式锁,一个机器接收到了请求之后先获取 zookeeper 上的一把分布式锁,就是可以去创建一个 znode,接着执行操作;然后另外一个机器也尝试去创建那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等着,等第一个机器执行完了自己再执行。
这个应该是很常见的,比如 hadoop、hdfs、yarn 等很多大数据系统,都选择基于 zookeeper 来开发 HA 高可用机制,就是一个重要进程一般会做主备两个,主进程挂了立马通过 zookeeper 感知到切换到备用进程。
zookeeper的视图数据结构,很像Unix文件系统,也是树状的,这样可以确定每个路径都是唯一的,zookeeper的节点统一叫做znode
,它是可以通过路径来标识,结构图如下
根据节点的生命周期,znode可以分为4种类型,分别是持久节点(PERSISTENT)、持久顺序节点(PERSISTENT_SEQUENTIAL)、临时节点(EPHEMERAL)、临时顺序节点(EPHEMERAL_SEQUENTIAL)
这类节点被创建后,就会一直存在于zookeeper服务器上,直到手动删除。
它的基本特性同持久节点,不同在于增加了顺序性,父节点会维护一个自增整型数字,用于子节点的的创建的先后顺序。
临时节点的生命周期跟客户端的会话绑定,一旦客户端会话失效(非TCP连接断开),那么这个节点就会被自动清理掉,zk规定临时节点只能作为叶子节点。
基本特性同临时节点,添加了顺序的特性。
znode节点里面存储的是什么?
public class DataNode implements Record {
byte data[];
Long acl;
public StatPersisted stat;
private Set<String> children = null;
}
Znode包含了存储数据,访问权限,子节点引用,节点状态信息,如图
data
:znode存储的业务数据信息。acl
:记录客户端对znode节点的访问权限,如IP等。stat
:包含znode节点的状态信息,比如事务id,版本号,时间戳等等。children
:当前节点的子节点引用。为了保证高吞吐和低延迟,以及数据的一致性,znode只适合存储非常小的数据,不能超过1M
,最好都小于1K
。
Zookeeper允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。
可以把Watcher理解成客户端注册在某个Znode上的触发器,当这个Znode节点发生变化时(增删改查),就触发Znode对应的注册事件,注册的客户端就会收到异步通知,然后做出业务的改变。
Zookeeper 保证了如下分布式一致性特性:
这道题可以看下这篇文章(本题答案来自该文章):聊一聊ZooKeeper的顺序一致性
需要了解事务ID,即zxid,ZooKeeper在选举时通过比较各节点的zxid和机器ID选出新的主节点,zxid由Leader节点生成,有新写入事件时,Leader生成新zxid并随提案一起广播,每个结点本地都保存了当前最近一次事务的zxid,zxid是递增的,所以谁的zxid越大,就表示谁的数据是最新的。
ZXID的生成规则如下:
ZXID有两部分组成:
ZXID的低32位是计数器,所以同一任期内,ZXID是连续的,每个结点又都保存着自身最新生效的ZXID,通过对比新提案的ZXID与自身最新ZXID是否相差“1”,来保证事务严格按照顺序生效的。
Zookeeper 集群中,有Leader,Follower和Observer三种角色。
Leader服务器是整个Zookeeper 集群工作机制中的核心,其主要工作:
Follower服务器是Zookeeper 集群状态的跟随者,其主要工作:
Observer是3.3.0 版本开始引入的一个服务器角色,它充当一个观察者角色——观察ZooKeeper集群的最新状态变化并将这些状态变更同步过来。其工作:
服务器具有四种状态,分别是LOOKING,FOLLOWING,LEADING,OBSERVING。
ZooKeeper集群是一主多从的结构:
我们知道集群是主从部署架构,要保证主从节点一致性问题,无非就是两个主要问题:
ZooKeeper是采用ZAB协议(Zookeeper Atomic Broadcast,Zookeeper原子广播协议)来保证主从节点数据一致性的,ZAB协议支持崩溃恢复和消息广播两种模式,很好的解决了这两个问题。
Leader服务器挂了,所有集群中的服务器进入LOOKING状态,首先,它们会选举产生新的Leader服务器;接着,新的Leader服务器与集群中Follower服务进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式。Leader 服务器开始接收客户端的事务请求生成事务Proposal进行事务请求处理。
服务器启动或者服务器运行期间(Leader挂了),都会进入Leader选举,我们来看一下~ 假设现在ZooKeeper集群有五台服务器,它们myid分别是服务器1、2、3、4、5,如图:
ZooKeeper集群初始化阶段,服务器(myid=1-5)依次启动,开始ZooKeeper选举Leader。
服务器1和服务器2都将自己作为Leader服务器进行投票,投票的基本元素包括:服务器的myid和ZXID,我们以(myid,ZXID)形式表示。初始阶段,服务器1和服务器2都会投给自己,即服务器1的投票为(1,0),服务器2的投票为(2,0),然后各自将这个投票发给集群中的其他所有机器。
每个服务器都会接受来自其他服务器的投票。同时,服务器会校验投票的有效性,是否本轮投票、是否来自LOOKING状态的服务器。
收到其他服务器的投票,会将别人的投票跟自己的投票PK,PK规则如下:
服务器1的投票是(1,0),它收到投票是(2,0),两者zxid都是0,因为收到的myid=2,大于自己的myid=1,所以它更新自己的投票为(2,0),然后重新将投票发出去。对于服务器2呢,即不再需要更新自己的投票,把上一次的投票信息发出即可。
每次投票后,服务器会统计所有投票,判断是否有过半的机器接受到相同的投票信息。服务器2收到两票,少于3(n/2+1,n为总服务器5),所以继续保持LOOKING状态
跟前面流程一致,服务器1和2先投自己一票,因为服务器3的myid最大,所以大家把票改投给它。此时,服务器为3票(大于等于n/2+1),所以服务器3当选为Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。选票信息结果:服务器3为3票,服务器4为1票。服务器4并更改状态为FOLLOWING;
同理,服务器也是把票投给服务器3,服务器5并更改状态为FOLLOWING;
zookeeper集群的五台服务器(myid=1-5)正在运行中,突然某个瞬间,Leader服务器3挂了,这时候便开始Leader选举~
Leader 服务器挂了之后,余下的非Observer服务器都会把自己的服务器状态更改为LOOKING,然后开始进入Leader选举流程。
每个服务器都把票投给自己,因为是运行期间,所以每台服务器的ZXID可能不相同。假设服务1,2,4,5的zxid分别为333,666,999,888,则分别产生投票(1,333),(2,666),(4,999)和(5,888),然后各自将这个投票发给集群中的其他所有机器。
投票规则是跟Zookeeper集群启动期间一致的,优先检查ZXID,大的优先作为Leader,所以显然服务器zxid=999具有优先权。
Zookeeper就是使用临时顺序节点特性实现分布式锁的。
当第一个客户端请求过来时,Zookeeper客户端会创建一个持久化节点/locks,如果它(Client1)想获得锁,需要在locks节点下创建一个顺序节点lock1,如图
接着,客户端Client1会查找locks下面的所有临时顺序子节点,判断自己的节点lock1是不是排序最小的那个,如果是则成功获得锁。
这时候如果又来一个客户端Client2前来尝试获取到锁,它会在locks下再创建一个临时节点lock2。
客户端client2一样也会查找locks下面的所有临时顺序子节点,判断自己的节点lock2是不是最小的,此时,发现lock1才是最小的,于是获取锁失败。获取锁失败,它是不会甘心的,client2向它排序靠前的节点lock1注册Watcher事件,用来监听lock1是否存在,也就是说client2抢锁失败进入等待状态。
此时,如果再来一个客户端Client3来尝试获取锁,它会在locks下再创建一个临时节点lock3
同样的,client3一样也会查找locks下面的所有临时顺序子节点,判断自己的节点lock3是不是最小的,发现自己不是最小的,就获取锁失败。它也是不会甘心的,它会向在它前面的节点lock2注册Watcher事件,以监听lock2节点是否存在。
我们再来看看释放锁的流程,zookeeper的「客户端业务完成或者故障」,都会删除临时节点,释放锁。如果是任务完成,Client1会显式调用删除lock1的指令
如果是客户端故障了,根据临时节点的特性,lock1是会自动删除的
lock1节点被删除后,Client2可开心了,因为它一直监听着lock1。lock1节点删除,Client2立刻收到通知,也会查找locks下面的所有临时顺序子节点,发下lock2是最小,就获得锁。
同理,Client2获得锁之后,Client3也对它虎视眈眈~
dubbo的注册中心可以选Zookeeper,memcached,redis等。为什么选择Zookeeper,因为它的功能特性咯~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。