第3章 分布式系统

水桶无论有多高,其盛水的高度取决于其中最短的那块木板,这就是著名的“木桶效应”。架构设计之初要求我们能够估算系统的性能从而权衡不同的设计方法。本章首先介绍分布式系统相关的基础概念和性能估算方法。接着,介绍分布式系统的基础理论知识,包括数据分布、复制、一致性、容错等。最后,介绍常见的分布式协议。

分布式系统面临的第一个问题就是数据分布,即将数据均匀地分布到多个存储节点。另外,为了保证可靠性和可用性,需要将数据复制多个副本,这就带来了多个副本之间的数据一致性问题。大规模分布式存储系统的重要目标就是节省成本,因而只能采用性价比较高的PC服务器。这些服务器性能很好,但是故障率很高,要求系统能够在软件层面实现自动容错。当存储节点出现故障时,系统能够自动检测出来,并将原有的数据和服务迁移到集群中其他正常工作的节点。

分布式系统中有两个重要的协议,包括Paxos选举协议以及两阶段提交协议。Paxos协议用于多个节点之间达成一致,往往用于实现总控节点选举。两阶段提交协议用于保证跨多个节点操作的原子性,这些操作要么全部成功,要么全部失败。理解了这两个分布式协议之后,学习其他分布式协议会变得相当容易。

3.1 基本概念

3.1.1 异常

在分布式存储系统中,往往将一台服务器或者服务器上运行的一个进程称为一个节点,节点与节点之间通过网络互联。大规模分布式存储系统的一个核心问题在于自动容错。然而,服务器节点是不可靠的,网络也是不可靠的,本节介绍系统运行过程中可能会遇到的各种异常。

1.异常类型

(1)服务器宕机

引发服务器宕机的原因可能是内存错误、服务器停电等。服务器宕机可能随时发生,当发生宕机时,节点无法正常工作,称为“不可用”(unavailable)。服务器重启后,节点将失去所有的内存信息。因此,设计存储系统时需要考虑如何通过读取持久化介质(如机械硬盘,固态硬盘)中的数据来恢复内存信息,从而恢复到宕机前的某个一致的状态。进程运行过程中也可能随时因为core dump等原因退出,和服务器宕机一样,进程重启后也需要恢复内存信息。

(2)网络异常

引发网络异常的原因可能是消息丢失、消息乱序(如采用UDP方式通信)或者网络包数据错误。有一种特殊的网络异常称为“网络分区”,即集群的所有节点被划分为多个区域,每个区域内部可以正常通信,但是区域之间无法通信。例如,某分布式系统部署在两个数据中心,由于网络调整,导致数据中心之间无法通信,但是,数据中心内部可以正常通信。

设计容错系统的一个基本原则是:网络永远是不可靠的,任何一个消息只有收到对方的回复后才可以认为发送成功,系统设计时总是假设网络将会出现异常并采取相应的处理措施。

(3)磁盘故障

磁盘故障是一种发生概率很高的异常。磁盘故障分为两种情况:磁盘损坏和磁盘数据错误。磁盘损坏时,将会丢失存储在上面的数据,因而,分布式存储系统需要考虑将数据存储到多台服务器,即使其中一台服务器磁盘出现故障,也能从其他服务器上恢复数据。对于磁盘数据错误,往往可以采用校验和(checksum)机制来解决,这样的机制既可以在操作系统层面实现,又可以在上层的分布式存储系统层面实现。

2.“超时”

由于网络异常的存在,分布式存储系统中请求结果存在“三态”的概念。在单机系统中,只要服务器没有发生异常,每个函数的执行结果是确定的,要么成功,要么失败。然而,在分布式系统中,如果某个节点向另外一个节点发起RPC(Remote Procedure Call)调用,这个RPC执行的结果有三种状态:“成功”、“失败”、“超时”(未知状态),也称为分布式存储系统的三态。

图3-1给出了RPC执行成功但超时的例子。服务器(Server)收到并成功处理完成客户端(Client)的请求,但是由于网络异常或者服务器宕机,客户端没有收到服务器端的回复。此时,RPC的执行结果为超时,客户端不能简单地认为服务器端处理失败。

第3章 分布式系统 - 图1

图 3-1 RPC执行成功但超时

一个更加通俗的例子是2.4.1节介绍的ATM取款。ATM取款时ATM机有时会提示:“无法打印凭条,是否继续取款?”。这是因为ATM机需要和银行服务器端通信,二者之间的网络可能出现故障,此时ATM机发往银行服务器端的RPC请求如果发生超时,ATM机无法确定RPC请求成功还是失败。正常情况下,ATM机会打印凭条,用于后续与银行服务器端对账。如果无法打印凭条,存在资金安全风险,因此,ATM机有一个提示。

当出现超时状态时,只能通过不断读取之前操作的状态来验证RPC操作是否成功。当然,设计分布式存储系统时可以将操作设计为“幂等”的,也就是说,操作执行一次与执行多次的结果相同,例如,覆盖写就是一种常见的幂等操作。如果采用这种设计,当出现失败和超时时,都可以采用相同的处理方式,即一直重试直到成功。