分布式系统的烦恼------《Designing Data-Intensive Applications》读书笔记11

使用分布式系统与在单机系统中处理问题有很大的区别,分布式系统带来了更大的处理能力和存储容量之后,也带来了很多新的"烦恼"。在这一篇之中,我们将看看分布式系统带给我们新的挑战。

1.故障

当我们在使用单机系统时,它通常以一种相当可预测的方式工作:要么它正常工作,要么不工作。

而当我们在使用分布式系统时,情况就不同了。在分布式系统中,系统的某些部分可能以某种不可预知的方式被破坏,即使系统的其他部分工作正常。这种故障通常是不确定的:如果你想做涉及多个节点和网络的东西,可能甚至不知道某个消息是否成功,因为消息穿越网络所需的时间也是不确定的。

这种故障的不确定性,使得分布式系统的变得复杂而脆弱。一个系统越大,它的组件就越有可能出现故障。在一个有成千上万个节点的系统中,某些东西总是会出现故障。而错误处理策略仅仅是简单的放弃的话,一个大系统可能会花费大量时间从故障中恢复,而不是做有用的工作。所以我们需要分布式系统能够容忍失败的节点,并且仍然保持整体工作,将容错机制建立到软件中。换句话说,分布式系统需要从不可靠的组件中建立一个可靠的系统。

2.不可靠的网络

分布式系统是一组由网络连接的机器组成的。网络是这些机器通信的唯一方式,每台机器都有自己的内存和磁盘,一台机器不能访问另一台机器的内存或磁盘。在网络中,一个节点可以向另一个节点发送消息,但是网络不能保证它何时到达或是否到达,所以网络是不可靠的。

不可靠的网络系统

如上图所示,如果发送的请求并没有得到响应,则无法区分 (a)请求丢失 (b)远程节点失效 (c)响应丢失。 处理这个问题的通常方法是超时:一段时间后,发送方放弃等待,并假定响应不会到达。但是,当超时发生时,远程节点可能已经得到请求并进行了处理。

故障检测

由于网络的不确定性使得很难判断一个节点是否工作。分布式系统当中常用的便是超时检测的机制。如果超时检测是检测故障的方法,那么超时应该是多长时间呢?不幸的是,没有简单的答案。

长的超时时间意味着需要等待一个节点被宣告死亡。短的超时时间会更快地检测到故障,但是事实上节点并没有停止工作(例如由于节点或网络过载)时,会错误地检测一个节点失效。如果节点实际上是活着的,在执行某些操作的时,工作另一个节点接管,则该操作可能最终执行两次。而且当一个节点失效时,它的责任需要转移到其他节点,这将额外的负载放到其他节点和网络上。如果系统已经处于高负载之下,过早检测节点失效会使问题变得更糟。特别是,它可能发生的是节点实际上没有时效,但由于过载而响应缓慢,将其负载转移到其他节点会导致级联故障。

目前学界和业界的趋势是:不使用常数配置的超时,而是系统可以连续测量的响应时间和响应时间的抖动,并自动调整超时时间根据所观察到的响应时间动态分布。如Akka的超时器,Cassandra的动态检测,TCP的超时重传。

3.不可靠的时间

在分布式系统中,时间是一件棘手的事情,因为通信不是瞬时的:消息穿越网络从一台机器转到另一台机器需要时间。消息接收的时间总是比发送的时间晚,但由于网络中的可变延迟,我们不知道以后会有多少延迟。很难确定多台机器处理的逻辑与顺序。

每台机器都有自己的时钟,通常是一个石英晶体振荡器。这些设备并不完全准确,所以每台机器都有自己的时间,它可能比其他机器稍快或慢一些。存在同步时钟的网络协议:最常用的机制是网络时间协议(NTP),它允许计算机时钟根据一组服务器报告的时间进行调整。服务器可以从更精确的时间源获取时间。

时钟:

UTC时间以1970年1月1日为开始,根据公历,忽略闰秒,来计算当前时间。计算机时钟通常与NTP同步,这意味着一台机器的时间戳(理想情况下)意味着与另一台机器上的时间戳相同。

单调的时间:

您可以在一个时间点检查时钟的值,然后再一次检查时钟。两个值之间的差异告诉你这两个检查之间要花多少时间。在分布式系统中,通过一个单调的时钟测量时间(如超时)通常是好的,因为它不承担不同的节点的时钟之间的同步的细微误差。

事件的时间戳排序

跨多个节点的事件排序是一个令人头疼的问题。例如,如果两个客户机向分布式数据库写入,谁首先到达?哪个是最近写的? 如下图所示:

node2 会通过时间戳检验规则,丢弃x=2的结果

写x = 1的时间戳是42.004秒,但写x = 2的时间戳42.003秒。当Node 2接收到这两个事件时,它会错误地得出结论:x = 1是最新的值,忽略x=2的写入。Client B的增量操作将会丢失。这种冲突解决策略被称为最后写者胜(LWW),会导致一个具有滞后时钟的节点无法覆盖以前用一个快速时钟写入的节点的值,直到节点之间的时钟偏差消失。

所以对于有严格时序要求的系统,需要使用逻辑时钟(比如:Lamport Clock,Lanport老爷子真的是分布式领域的上古神牛啊~~~),这是基于递增计数器是一个来判断事件的更迭顺序。逻辑时钟不测量每天的时间或经过的秒数,只有事件的相对顺序,也就是判断一个事件是否发生在另一个事件之前或之后。

4.不可靠的租约

在分布式系统之中,有时需要确保在存储服务文件只能同时被一个客户端访问,因为如果多个客户端试图写它,文件会被损坏。您需要通过在访问文件之前从锁服务获得租约来实现分布式锁。但是有时这个锁并非有我们想象的可靠,如下图所示:

不正确的执行分布式租约

如果持有租约的客户端 1 因为GC等原因暂停太久,而它的租约到期了。另一个客户端 2 可以获取租约,并开始向文件写入数据。当暂停的客户端1返回时,它仍然认为自己拥有一个有效的租约,并且继续写入数据。于是造成了写入冲突。

栅栏令牌

我们可以使用栅栏令牌的方式,让不可靠的租约变的更加可靠,如下图所示:

通过栅栏令牌来确保写入安全

锁服务器可以在每次授予租约时,返回一个令牌,它是一个在每次授予锁时增加的数字ID。每次客户端发出一个写请求时,必须包含当前的租约令牌。而存储服务会记录写入的租约令牌,成为一个栅栏,旧的令牌写入将被存储服务拒绝。

小结:

分布式系统最大的挑战是我们需要在不可靠的组件与复杂的多节点交互之中建立起一个可靠的系统,所以也需要我们付出更多的努力。我这里略过了拜占庭问题的讲解,通常我们开发的数据系统认为是拜占庭安全的,节点是可以信任的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Thinks

SEO杂谈(2)

站点地图,作为补充,仅仅作为补充,不要把希望都寄托在他的身上,不过从实践来看,他一旦被搜索引擎认可,他确实是一个可以依赖的方法。

6510
来自专栏北京马哥教育

分布式与集群的联系与区别

集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务平台。在客户端看来,一个集群就象是一个服务实体,但事实上集群由一组服务实体组成。与单...

29230
来自专栏Web 开发

额,算是半个轻量级WEB开发软件-WebMatirx

Microsoft WebMatrix 是微软最新的 Web 开发工具,它包含了构建网站所需要的一切元素。您可以从开源 Web 项目或者内置的 Web 模板开始...

7310
来自专栏高性能服务器开发

C++ 高性能服务器网络框架设计细节(节选)

这篇文章我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高并发的服务器程序。需要注意的是一般大型服务器,其复杂程度在于其业务,而不是在于其代码工程的基...

67440
来自专栏GA小站

UTM参数使用30问——既UTM参数使用指南(2018)

有很多缺少Google Analytics的UTM参数而导致的跟踪错误案例,我在Google Analytics Community和 Quora 看到过成千上...

42220
来自专栏HBStream流媒体与音视频技术

做了一个电驴 p2p资源搜索小软件

64170

3种提升云可扩展性的方法

如果只为计算资源付费,在Amazon云上部署业务可以实现高拓展性。但是要怎样利用Amazon的相关技术才能获得最好的可拓展性呢?

21090
来自专栏Java架构师学习

用一个简单的方法构建高可用服务端

24540
来自专栏运维小白

18.1 集群介绍

Linux集群概述 根据功能划分为两大类:高可用和负载均衡 高可用集群通常为两台服务器,一台工作,另外一台作为冗余,当提供服务的机器宕机,冗余将接替继续提供服...

19680
来自专栏Crossin的编程教室

一键下载:将知乎专栏导出成电子书

老是有同学问,学了 Python 基础后不知道可以做点什么来提高。今天就再用个小例子,给大家讲讲,通过 Python 和爬虫,可以完成怎样的小工具。

31610

扫码关注云+社区

领取腾讯云代金券