《从0开始学大数据》之ZooKeeper是如何保证数据一致性的

背景

在分布式集群系统中,比如两个应用程序都需要对一个文件路径进行写操作,但是如果两个应用程序对于哪台服务器是主服务器的判断不同,就会分别连接到两个不同的 NameNode 上,并都得到了对同一个文件路径的写操作权限,这样就会引起文件数据冲突,同一个文件指向了两份不同的数据。这种不同主服务器做出不同的响应,在分布式系统中被称作“脑裂”。光看这个词你也可以看出问题的严重性,这时候集群处于混乱状态,根本无法使用。那我们引入一个专门进行判断的服务器当“裁判”,让“裁判”决定哪个服务器是主服务器不就完事了吗?但是这个做出判断决策的服务器也有可能会出现故障不可访问,同样整个服务器集群也不能正常运行。所以这个做出判断决策的服务器必须由多台服务器组成,来保证高可用,任意一台服务器宕机都不会影响系统的可用性。

比较常用的多台服务器状态一致性的解决方案就是 ZooKeeper

分布式一致性原理

CAP 定理,一个提供数据服务的分布式系统无法同时满足数据一致性(Consistency)、可用性(Availibility)、分区耐受性(Patition Tolerance)这三个条件,如下图所示。
极客时间《从0开始学大数据》
一致性
每次读取的数据都应该是最近写入的数据或者返回一个错误(Every read receives the most recent write or an error),而不是过期数据,也就是说,数据是一致的。

可用性
每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过这个响应不需要保证数据是最近写入的(Every request receives a (non-error) response, without the guarantee that it contains the most recent write),也就是说系统需要一直都是可以正常使用的,不会引起调用者的异常,但是并不保证响应的数据是最新的。

分区耐受性
即使因为网络原因,部分服务器节点之间消息丢失或者延迟了,系统依然应该是可以操作的(The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes)。当网络分区失效发生的时候,我们要么取消操作,这样数据就是一致的,但是系统却不可用;要么我们继续写入数据,但是数据的一致性就得不到保证。

对于一个分布式系统而言,网络失效一定会发生,也就是说,分区耐受性是必须要保证的,那么在可用性和一致性上就必须二选一。当网络分区失效,也就是网络不可用的时候,如果选择了一致性,系统就可能返回一个错误码或者干脆超时,即系统不可用。如果选择了可用性,那么系统总是可以返回一个数据,但是并不能保证这个数据是最新的。

ZooKeeper 架构

zookeeper官网

ZAB算法

ZooKeeper 主要提供数据的一致性服务,其实现分布式系统的状态一致性依赖一个叫 Paxos 的算法。Paxos 算法在多台服务器通过内部的投票表决机制决定一个数据的更新与写入。

但Paxos 算法有点过于复杂、实现难度也比较高,所以 ZooKeeper 在编程实现的时候将其简化成了一种叫做 ZAB 的算法(Zookeeper Atomic Broadcast, Zookeeper 原子广播)。

极客时间《从0开始学大数据》
ZAB 算法的目的,同样是在多台服务器之间达成一致,保证这些服务器上存储的数据是一致的。ZAB 算法的主要特点在于:需要在这些服务器中选举一个 Leader,所有的写请求都必须提交给 Leader。由 Leader 服务器向其他服务器(Follower)发起 Propose,通知所有服务器:我们要完成一个写操作请求,大家检查自己的数据状态,是否有问题。

如果所有 Follower 服务器都回复 Leader 服务器 ACK,即没有问题,那么 Leader 服务器会向所有 Follower 发送 Commit 命令,要求所有服务器完成写操作。这样包括 Leader 服务器在内的所有 ZooKeeper 集群服务器的数据,就都更新并保持一致了。如果有两个客户端程序同时请求修改同一个数据,因为必须要经过 Leader 的审核,而 Leader 只接受其中一个请求,数据也会保持一致。

在实际应用中,客户端程序可以连接任意一个 Follower,进行数据读写操作。如果是写操作,那么这个请求会被这个 Follower 发送给 Leader,进行如上所述的处理;如果是读操作,因为所有服务器的数据都是一致的,那么这个 Follower 直接返回自己本地的数据给客户端就可以了。

Zookeeper如何为大数据系统选举主服务器

ZooKeeper 通过一种树状结构记录数据,如下图所示。

极客时间《从0开始学大数据》
应用程序可以通过路径的方式访问 ZooKeeper 中的数据,比如 /services/YaView/services/stupidname 这样的路径方式修改、读取数据。ZooKeeper 还支持监听模式,当数据发生改变的时候,通知应用程序。

因为大数据系统通常都是主从架构,主服务器管理集群的状态和元信息(meta-info),为了保证集群状态一致防止“脑裂”,所以运行期只能有一个主服务器工作(active master),但是为了保证高可用,必须有另一个主服务器保持热备(standby master)。那么应用程序和集群其他服务器如何才能知道当前哪个服务器是实际工作的主服务器呢?

所以很多大数据系统都依赖 ZooKeeper 提供的一致性数据服务,用于选举集群当前工作的主服务器。一台主服务器启动后向 ZooKeeper 注册自己为当前工作的主服务器,而另一台服务器就只能成为热备主服务器,应用程序运行期都和当前工作的主服务器通信。如果当前工作的主服务器宕机(在 ZooKeeper 上记录的心跳数据不再更新),热备主服务器通过 ZooKeeper 的监控机制发现当前工作的主服务器宕机,就向 ZooKeeper 注册自己成为当前工作的主服务器。应用程序和集群其他服务器跟新的主服务器通信,保证系统正常运行。

利用 ZooKeeper 选主服务器的伪代码如下:


//读取path路径/servers/leader的值
//第二个参数true,表示监听这个path的变化。
1 value = getdata(/servers/leader”, true) 

//如果有返回值,表示主服务器已经产生(即path中记录的value,为当前主服务器的机器名)
//当前函数退出
2 if(value != null){exit}

//执行到这里,表示还没有主服务器,将自己的主机名写入/servers/leader
//EPHEMERAL表示这是一个临时路径,如果当前程序崩溃,即主服务器崩溃,ZooKeeper会删除这个path
3 result = create(/servers/leader”, hostname, EPHEMERAL) 

//如果上一步创建path成功,当前函数退出
4 if result = successful{exit}

//执行到这里,表示既没有主服务器,自己也没有成功成为主服务器,从头再来
5.goto step 1

使用 ZooKeeper 提供的 API 接口,代码非常简单。所有要选举成为主服务器的服务器在启动的时候都在自己的服务器上执行上面这段伪代码的逻辑,其中的 getdata、create 会连接到 ZooKeeper 集群去处理。但是根据 ZAB 算法,只有一个服务器能将自己的 hostname 写入到 ZooKeeper 的主服务器路径 /servers/leader 中,保证集群只有一个主服务器。

而成功成为主服务器的服务器在创建 /servers/leader 路径的时候,已指定当前路径为 EPHEMERAL,即临时路径。如果当前的主服务器宕机,那么该服务器和 ZooKeeper 的长连接也就中断了,ZooKeeper 据此判断该服务器宕机,删除这个路径。其他监听这个路径的服务器(即在伪代码 1 中,第二个参数设置为 true)就会收到通知,所有服务器重新执行以上的伪代码,重新选举出新的、唯一的主服务器。

小结

ZooKeeper 通过 ZAB 算法实现数据一致性,并为各种大数据系统提供主服务器选举服务。虽然 ZooKeeper 并没有什么特别强大的功能,但是在各类分布式系统和大数据系统中,ZooKeeper 的出镜率非常高,因此也是很多系统的基础设施。

该笔记摘录自极客时间课程
《从0开始学大数据》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值