学习分布式系统跟学习其它技术非常不一样,分布式系统涵盖的面非常广,具体来说涵盖如下几方面:
  • **服务调度**,涉及服务发现、配置管理、弹性伸缩、故障恢复等。
  • **资源调度**,涉及对底层资源的调度使用,如计算资源、网络资源和存储资源等。
  • **流量调度**,涉及路由、负载均衡、流控、熔断等。
  • **数据调度**,涉及数据复本、数据一致性、分布式事务、分库、分表等。
  • **容错处理**,涉及隔离、幂等、重试、业务补偿、异步、降级等。
  • **自动化运维**,涉及持续集成、持续部署、全栈监控、调用链跟踪等。
  • 所有这些形成了分布式架构的整体复杂度,也造就了分布式系统中的很多很多论文、图书以及很多很多的项目。要学好分布式系统及其架构,我们需要大量的时间和实践才能真正掌握这些技术。 这里有几点需要你注意一下。
  • **分布式系统之所以复杂,就是因为它太容易出错了**。这意味着,**你要把处理错误的代码当成正常功能的代码来处理**。
  • **开发一个健壮的分布式系统的成本是单体系统的几百倍甚至几万倍**。这意味着,**我们要自己开发一个,需要能力很强的开发人员**。
  • **非常健壮的开源的分布式系统并不多,或者说基本没有**。这意味着,**如果你要用开源的,那么你需要hold得住其源码**。
  • **管理或是协调多个服务或机器是非常难的**。这意味着,**我们要去读很多很多的分布式系统的论文**。
  • **在分布式环境下,出了问题是很难debug的**。这意味着,**我们需要非常好的监控和跟踪系统,还需要经常做演练和测试**。
  • **在分布式环境下,你需要更科学地分析和统计**。这意味着,**我们要用P90这样的统计指标,而不是平均值,我们还需要做容量计划和评估**。
  • **在分布式环境下,需要应用服务化**。这意味着,**我们需要一个服务开发框架,比如SOA或微服务**。
  • **在分布式环境下,故障不可怕,可怕的是影响面过大,时间过长**。这意味着,**我们需要花时间来开发我们的自动化运维平台**。
  • 总之,在分布式环境下,一切都变得非常复杂。要进入这个领域,你需要有足够多的耐性和足够强的心态来接受各式各样的失败。当拥有丰富的实践和经验后,你才会有所建树。这并不是一日之功,你可能要在这个领域花费数年甚至数十年的时间。 # 分布式架构入门 学习如何设计可扩展的架构将会有助于你成为一个更好的工程师。系统设计是一个很宽泛的话题。在互联网上,关于架构设计原则的资源也是多如牛毛。所以,你需要知道一些基本概念,对此,这里你先阅读下面两篇文章。
  • [Scalable Web Architecture and Distributed Systems](http://www.aosabook.org/en/distsys.html) ,这篇文章会给你一个大概的分布式架构是怎么来解决系统扩展性问题的粗略方法。
  • [Scalability, Availability & Stability Patterns](http://www.slideshare.net/jboner/scalability-availability-stability-patterns) ,这个PPT能在扩展性、可用性、稳定性等方面给你一个非常大的架构设计视野和思想,可以让你感受一下大概的全景图。
  • 然后,我更强烈推荐GitHub上的一篇文档 - [System Design Primer](https://github.com/donnemartin/system-design-primer) ,这个仓库主要组织收集分布式系统的一些与扩展性相关的资源,它可以帮助你学习如何构建可扩展的架构。 目前这个仓库收集到了好些系统架构和设计的基本方法。其中包括:CAP理论、一致性模型、可用性模式、DNS、CDN、负载均衡、反向代理、应用层的微服务和服务发现、关系型数据库和NoSQL、缓存、异步通讯、安全等。 我认为,上面这几篇文章基本足够可以让你入门了,因为其中基本涵盖了所有与系统架构相关的技术。这些技术,足够这世上90%以上的公司用了,只有超级巨型的公司才有可能使用更高层次的技术。 # 分布式理论 下面,我们来学习一下分布式方面的理论知识。 首先,你需要看一下 [An introduction to distributed systems](https://github.com/aphyr/distsys-class)。 这只是某个教学课程的提纲,我觉得还是很不错的,几乎涵盖了分布式系统方面的所有知识点,而且辅以简洁并切中要害的说明文字,非常适合初学者提纲挈领地了解知识全貌,快速与现有知识结合,形成知识体系。这也是一个分布式系统的知识图谱,可以让你看到分布式系统的整体全貌。你可以根据这个知识图Google下去,然后你会学会所有的东西。 然后,你需要了解一下拜占庭将军问题([Byzantine Generals Problem](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance))。这个问题是莱斯利·兰波特(Leslie Lamport)于1982年提出用来解释一致性问题的一个虚构模型([论文地址](https://www.microsoft.com/en-us/research/uploads/prod/2016/12/The-Byzantine-Generals-Problem.pdf))。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。 对于拜占庭问题来说,假如节点总数为 `N`,叛变将军数为 `F`,则当 `N >= 3F + 1` 时,问题才有解,即拜占庭容错(Byzantine Fault Tolerant,BFT)算法。拜占庭容错算法解决的是,网络通信可靠但节点可能故障情况下一致性该如何达成的问题。 最早由卡斯特罗(Castro)和利斯科夫(Liskov)在1999年提出的实用拜占庭容错(Practical Byzantine Fault Tolerant,PBFT)算法,是第一个得到广泛应用的BFT算法。只要系统中有2/3的节点是正常工作的,则可以保证一致性。PBFT算法包括三个阶段来达成共识:预准备(Pre-Prepare)、准备(Prepare)和提交(Commit)。 这里有几篇和这个问题相关的文章,推荐阅读。
  • [Dr.Dobb’s - The Byzantine Generals Problem](http://www.drdobbs.com/cpp/the-byzantine-generals-problem/206904396)
  • [The Byzantine Generals Problem](http://blog.jameslarisch.com/the-byzantine-generals-problem)
  • [Practicle Byzantine Fault Tolerance](http://pmg.csail.mit.edu/papers/osdi99.pdf)
  • 拜占庭容错系统研究中有三个重要理论:CAP、FLP和DLS。
  • [CAP定理](https://en.wikipedia.org/wiki/CAP_theorem),CAP理论相信你应该听说过不下N次了。CAP定理是分布式系统设计中最基础也是最为关键的理论。CAP定理指出,分布式数据存储不可能同时满足以下三个条件:一致性(Consistency)、可用性(Availability)和 分区容忍(Partition tolerance)。 “在网络发生阻断(partition)时,你只能选择数据的一致性(consistency)或可用性(availability),无法两者兼得”。 论点比较直观:如果网络因阻断而分隔为二,在其中一边我送出一笔交易:“将我的十元给A”;在另一半我送出另一笔交易:“将我的十元给B”。此时系统要不是,a)无可用性,即这两笔交易至少会有一笔交易不会被接受;要不就是,b)无一致性,一半看到的是A多了十元而另一半则看到B多了十元。要注意的是,CAP理论和扩展性(scalability)是无关的,在分片(sharded)或非分片的系统皆适用。
  • [FLP impossibility](http://the-paper-trail.org/blog/a-brief-tour-of-flp-impossibility/),在异步环境中,如果节点间的网络延迟没有上限,只要有一个恶意的节点存在,就没有算法能在有限的时间内达成共识。但值得注意的是, [“Las Vegas” algorithms](https://en.wikipedia.org/wiki/Las_Vegas_algorithm)(这个算法又叫撞大运算法,其保证结果正确,只是在运算时所用资源上进行赌博,一个简单的例子是随机快速排序,它的pivot是随机选的,但排序结果永远一致)在每一轮皆有一定机率达成共识,随着时间增加,机率会越趋近于1。而这也是许多成功的共识算法会采用的解决问题的办法。
  • 容错的上限,从[DLS论文](http://groups.csail.mit.edu/tds/papers/Lynch/jacm88.pdf) 中我们可以得到以下结论: