分布式系统面临的首要问题就是数据分布,即将数据均匀地分布到多个存储点。其中,为了保证可靠性和可用性,需要将数据复制多个副本,这就产生了多个副本之间数据一致性的问题。大规模分布式存储系统还有一个重要的目标,那就是在完成既定任务的同时尽可能的减少成本,因此有必要使用性价比较高的PC服务器,这些服务器性能良好,但是故障率较高,这就要求系统能在软件层面实现自动容错,即存储节点出现故障时,系统能够自动检测出来,并将原有的数据和服务迁移到集群中其他正常工作的节点。
在分布式系统中有以下基本概念:
a) 异常
我们往往将服务器上运行的一个进程称为一个节点,节点和节点之间通过网络连接。然而服务器节点和网络都是不可靠的,这就导致了各种异常的发生。
i. 服务器宕机
宕机后,服务器“不可用”,当其重启之后,节点将失去所有的内存信息。再恢复的时候通过读取持久化介质中的数据恢复内存信息。
ii. 网络异常
原因可能是消息丢失、消息乱序或者数据错误。还有一种特殊的被称为“网络分区”的网络异常,即将节点划分为若干区域,区域内部正常通信,而区域之间通信失败。
通常来说,有一个基本原则即网络永远是不可靠的,任何消息只有对方回复后才可认为发送成功。
由于该异常的存在,系统中的请求返回结果通常有三态,即成功、失败和超时,其中超时是不可知状态。【比如RPC执行成功但返回结果时网络异常或者成功后服务器宕机等等】
超时出现时,只能通过不断读取之前的操作的状态来验证RPC是否成功。这里我们可以引入“幂等”的概念,即一次执行和多次执行结果相同,当发生失败或者超时的时候,都可以通过该种方式重试直到成功。
iii. 磁盘故障
发生概率很高,一般是磁盘损坏和磁盘数据错误两种情况。前者发生,磁盘上的数据将丢失,因此一个分布式系统多是冗余的,保证磁盘损坏不会造成该数据在系统中丢失。后者往往通过校验和机制解决。
b) 一致性
由于异常的存在,分布式系统往往将数据冗余存储多份,当某一个节点出现错误,可以从其他副本上读到数据。副本可以说是分布式存储系统唯一的容错手段,多个副本之间保持一致性也就成了分布式系统的理论核心。
首先定义这样一个场景,包含四个部分,存储系统(一个黑盒,提供可用性和持久性)、相互独立的客户端A,B,C,对存储系统进行读写操作。这样从客户端的角度来看,一致性共包含以下三种情况:
- 强一致性:A先写一个值到存储系统,存储系统保证后续客户端的读写操作都能读到最新值
- 弱一致性:A先写一个值到存储系统,存储系统不保证后续客户端的读写操作能读到最新值
- 最终一致性:A先写一个值到存储系统,存储系统保证如果后续没有写操作更新同样的值,后续客户端的读写操作“最终”都能读到最新值。“最终”一致性存在“不一致窗口”,长度取决于交互延迟、系统负载、复制协议要求同步的副本数。
最终一致性又可以细分为读写一致性【A写入最新值,A立即看到,而B、C过一会看到】、会话一致性【原有会话维持期间保证读写一致性】、单调读一致性【若A已经读到对象的某个值,之后操作不会读取到更早的值】和单调写一致性【对于同一个客户端,存储系统的多个副本需要按照与客户端相同顺序完成】。
而所有这些一致性,在存储系统看来分为两类:副本一致性和更新顺序一致性。存储系统可以支持强一致性或者最终一致性,而从客户端的角度来看,不满足读写,会话,单调读,单调写等特性的话会导致使用麻烦,使用场景有限的问题。
c) 衡量指标
i. 性能
系统吞吐能力和系统响应时间两个指标。前者指系统在某一段时间内可以处理的请求总数,用QPS和TPS衡量。后者指从某个请求发出到接收到返回结果消耗的时间,通常用平均延时来衡量。两个目标互相矛盾,设计系统时需权衡这两个目标。
ii. 可用性
指系统面对各种异常时可以提供正常服务的能力,用系统停服务时间与正常服务时间的比例来衡量。【可用性4个9,则一年停服务的时间不超过52.26min】
iii. 一致性
iv. 可扩展性
通过扩展集群服务器规模来提高系统存储容量、计算量和性能的能力,理想的系统应该实现“线性可扩展”。