《数据密集型应用系统设计》-分布式挑战、共识

分布式挑战

分布式系统故障可能来自网络问题、时钟与时序问题等。

一、故障与部分失效

对于单节点上,通常程序以确定的方式运行:要么工作,要么出错,不会出现摸棱两可现象。然而对于多节点,可能会出现系统的一部分正常工作,但其他某些部分出现难以预测的故障,称为“部分失效”。

部分失效是不确定的,这种不确定性和部分失效大大提高分布式的复杂性。

二、不可靠的网络

我们假设网络是跨节点通信唯一的途径,每台机器都有自己的内存和磁盘,一台机器不能直接访问另一台机器的内存或磁盘,除非通过网络发送请求。

互联网大多数都是异步的,一个节点可以发送消息给另一个节点,但是网络不保证到达。处理这个问题通常采用超时机制:在等待一段时间后,如果没有收到回复则选择放弃,并且认为响应不会到达。

1.检测故障

许多系统需要检测节点失效的功能,能快速告知远程节点的关闭状态很有用,但不是万能的,例如TCP确认一个数据包已经发送给目标节点,但是应用程序可能在处理完成之前崩溃,此时,想知道请求是否执行成功,需要应用级别的回复。

2.超时与无限期的延迟

超时如果是故障检测唯一可行的方法,超时多久?没有答案。

假设一个虚拟网络,保证数据包最大延迟在一定范围:要么在时间d内交付,要么丢失,此外,非故障节点总能在r时间内完成请求处理,那么 2d+r 是一个理想的超时设置。

然鹅异步网络理论上延迟无限大,多数服务端无法保证在给定时间内完成请求。因此超时设置如果太小,只需要一个短暂的网络延迟就会导致包超时进而将系统标记为失效。

较好的做法是,超时设置不是一个不变的常量,而是持续测量响应时间及其变化,然后根据最新的响应时间自动调整。

3.同步与异步网络

固定电话与TCP连接不同,电路方式会预留固定带宽,在电路建立滞后其他人无法使用;而TCP连接的数据包会尽可能使用所有网络带宽。而当TCP空闲时,不暂用任何带宽。

三、不可靠的时钟

分布式系统同步机器之间的时钟,最常用的方法是网络时间协议NTP,根据一组专门的时间服务器来调整本地时间。

1.单调时钟与墙上时钟

计算机内部一般有两种时钟:墙上时钟和单调时钟。

墙上时钟

可用于与NTP同步,但会存在一些奇怪问题。例如本地时钟快于NTP,则会时间跳跃。

单调时钟

适合测量持续时间段,例如超时或服务的相应实现:Linux的clock-geitime返回的就是单调时间。可以在一个时间点读取单调时间,完成某工作,然后再次检查时钟,二者之差就是时间间隔。

单调时钟的绝对值没有任何意义。

2.时钟同步与准确性

NTP同步会受限于当时的网络环境特别是延迟。

对于闰秒的处理,最好是NPT服务器汇报时间时故意做出调整。

对于未完全可控的设备,需要留意,不能完全信任,用户可能会故意调整时钟为错误时间。

3.依赖同步的时钟

如果应用需要精确同步的时钟,最好仔细监控所有节点上的时钟偏差,如果某节点时钟漂移超出上限,应将其宣告为失效,并从集群中移除。

时间戳与事件顺序

LWW无法区分连续快速发生的连续写操作和并发写,需要额外的因果关系跟踪机制(例如版本向量)来防止因果冲突。

对于排序来讲,基于递增计数器而不是振荡石英晶体的逻辑时钟是更可靠的方式。

时钟的置信区间

全局快照与同步时钟

Google Spanner根据TrueTime API返回的时钟置信区间来实现跨数据中心的快照隔离。:根据两个置信区间的最早和最新可能的时间戳,并且两个区间没有重叠来判断事件顺序。

Spanner在提交事务前故意等待置信区间的长度,确保所有读事务足够晚才发生,避免与先前的事务的置信区间重叠。

4.进程暂停

假设数据库每个分区一个主节点,主节点才接受写入,其他节点如何确信主节点没有被宣告失效?一个方法是,主节点从其他节点获得一个租约,类似带有超时的锁,一个时间只有一个节点能拿到租约,为了维持主节点,节点必须到期前去续约,如果续约失败,则另一个节点接管。

但是,如果主节点被暂停一个时间段,暂停期间其他节点宣布它失效并选出新的节点,而前主节点不知道,暂停后回来就会产生问题。

响应时间保存

调整垃圾回收的影响

比较新的想法是把GC暂停视为节点一个计划内的临时离线,当节点启动垃圾回收,通知其他节点来接管客户端的请求。此外,系统可以提前为前端应用发出预警,应用等待当前请求完成,但停止向该节点发送新的请求,这样垃圾回收可以在无干扰情况下高效运行。

另一个方法,只对短期对象(可以快速回收)执行垃圾回收,然后在其变为长期存活对象前,采取定期重启的策略从而避免对长期存活对象执行全面回收。每次选择一个节点重新启动。重启前重新平衡节点间流量。

四、知识、真相与谎言

1.真相由多数决定

节点不能根据自己的信息来判断自身状态,因此分布式系统不能依赖单一节点。依靠的是法定票数,即节点间进行投票(quorum)。任何决策都需要来自多个节点的最小投票时。

最常见的法定票数是去系统节点半数以上,如果某些节点故障,quorom机制可以使系统继续工作。

主节点与锁

持有租约的客户端被暂停太久直到租约到期,然后另一个客户端已经获得了文件的锁租约,并开始写文件。当暂停的客户端重新回来,他仍然错误地认为合法持有锁并尝试写入文件,结果导致错误。

Fencing令牌

假设每次锁服务在授予锁或者租约时,还返回一个fencing令牌,令牌(数字)每授予一次就会递增,然后客户端每次向存储系统发送写请求,都必须包含fencing令牌。

只靠客户端自己检查锁是不够的,要求资源本身必须主动检查所持令牌信息,如果发现已经处理过更高令牌的请求,必须拒绝低令牌的写请求。

2.拜占庭故障

解决拜占庭容错的系统协议异常复杂,因此在绝大多数服务器端数据系统中,部署拜占庭容错解决方案基本不太可行。只有在没有中央决策机制的点对点网络中,拜占庭容错才更为必要。

大多数拜占庭容错算法要求系统超过三分之二的节点要功能正常。

弱的谎言形式

对于硬件问题、软件bug等不是完整的拜占庭式容错,可以采用:

-应用层添加校验和,校验TCP/UDP 中网络数据包的问题。

-NTP客户端配置多个时间服务器。

3.理论系统模型与现实

三个系统模型:

-同步模型:假定有上界的网络延迟。

-部分同步模型:系统大多数情况像一个同步系统运行,但有时会超出网络延迟,进程暂停和时钟飘逸的预期上界。

-异步模型:一个算法不会对时机做任何假设,甚至里面根本没有时钟,也没有超时机制。

三个节点失效系统模型:

-崩溃—中止模型:节点可能在任何时候突然停止,且该节点以后永远消失,无法恢复。

-崩溃—恢复模型:节点可能会在任何时候崩溃,且可能会在一段未知的时间后恢复并再次响应。

-拜占庭失效模式:节点可能发生任何事情,包括试图作弊和欺骗其他节点。

算法的正确性

例如对于fengcing令牌生成算法,要求具有:

-唯一性:两个令牌请求不能获得相同的值

-单调递增:

-可用性:请求令牌的节点如果不发生崩溃则最终一定会收到响应。

安全与活性

安全性可以理解为“没有发生意外”,活性类似于“预期的事情最终一定会发生”(最终一致性也是一种活性)。

将系统模型映射到现实

五、小结

部分失效可能是分布式系统的关键特征,我们的目标是建立能容忍部分失效的系统软件。

为了容忍错误,第一步检测错误。多数系统没有检测节点故障的机制,因此分布式算法更多依靠超时来确定远程节点是否可用,但超时无法区分网络延迟和节点故障,且网络延迟有时会导致节点被误认为发生错误。

检测错误后,后面也很难呀。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值