Introduction
一个优秀的分布式系统应该能做到:
-
高性能(High Performance):分布式代表着大量 CPU、大量内存、以及大量磁盘在并行的运行,应当有着比单机高得多的性能。要做到 高性能 就要通过巧妙的设计,来减少数据同步、数据复制、数据传递等带来的性能消耗。
-
高可用(High Availability):是系统设计中的核心目标,指系统能够在预设的服务水平下持续稳定运行,减少或避免因故障导致的停机时间。实现高可用要考虑:数据冗余、自动故障转移、负载均衡等等。
-
容灾(Disaster Recovery):容灾的目的是应对物理灾难,如:地震、火灾,机房/机架断电等等造成的数据损失。一般的是方式是:异地备份、数据冷备/热备、灾难恢复流程等。
-
容错(Fault Tolerant):容错的目的是容忍组件故障且不中断服务,当组件发生错误时系统可以自己解决不需要人工介入。实现方式一般是:健康检查、状态恢复与数据修复、冗余与故障转移、自动回滚等等。
-
可扩展性(scalability):目标是通过合理的架构设计和技术手段,使系统能够随着用户规模、数据量或计算需求的增长,持续高效地运行,而不会显著降低性能或增加复杂性。其核心在于系统能否灵活扩展资源以满足不断变化的需求,同时保持高可用性、低延迟和合理的成本。
-
数据一致性(Consistency):读取系统的不同节点能够得到相同的数据,系统可以选择实现强一致性或弱一致性,强一致性意味着更新后所有节点立即看到最新数据,弱一致性允许暂时不一致,但要保证最终一致。越强的一致性往往意味着越高的延迟,因为要花更长的时间保证所有节点数据同步。一般是通过一些共识算法实现,如:Paxos、Raft、ZAB 等等。
所以由上面的特征我们可以想到为什么分布式系统很难实现?首先人们设计大型分布式系统或大型存储系统出发点通常是,他们想获取巨大的性能加成,进而利用数百台计算机的资源来同时完成大量工作。性能问题就成为了最初的诉求。之后,很自然的想法就是将数据分割放到大量的服务器上,这样就可以并行的从多台服务器读取数据。我们将这种方式称之为分片(Sharding)。如果你在成百上千台服务器进行分片,你将会遇到常态化的故障。如果你有数千台服务器,那么总是会有一台服务器宕机,每天甚至每个小时都可能会发生错误。所以,我们需要自动化的方法而不是人工介入来修复错误。我们需要一个自动的容错系统,这就引出了容错这个话题(fault tolerance)。实现容错最有用的一种方法是使用复制,只需要维护 2-3 个数据的副本,当其中一个故障了,你就可以使用另一个。所以,如果想要容错能力,就得有复制(replication)。如果有复制,那就有了两份数据的副本。可以确定的是,如果你不小心,它们就会不一致。所以,你本来设想的是,有了两个数据副本,你可以任意使用其中一个副本来容错。但是如果你不够小心,两个数据的副本就不是完全一致,严格来说,它们就不再互为副本了。而你获取到的数据内容也将取决于你向哪个副本请求数据。这对于应用程序来说就有些麻烦了。所以,如果我们有了复制,我们就有不一致的问题(inconsistency)。通过聪明的设计,你可以避免不一致的问题,并且让数据看起来也表现的符合预期。但是为了达到这样的效果,你总是需要额外的工作,需要不同服务器之间通过网络额外的交互,而这样的交互会降低性能。所以如果你想要一致性,你的代价就是低性能。但这明显不是我们最开始所希望的:
性能 -> 分片 -> 容错及可用性 -> 复制 -> 一致性 -> 低性能
现实中,如果你想要好的一致性,你就要付出相应的代价。如果你不想付出代价,那就要忍受一些不确定的行为。我们之后会在很多系统中看到这里介绍的循环。通常,人们很少会乐意为好的一致性付出相应的性能代价。这就是 CAP 理论,现在的系统通常是 CP 或者 AP 的。
本章节的内容是我阅读相关论文的笔记,看看学术界和工程界是如何处理这些问题。