9471447a86fc0f8871e6c28f12029439
漫谈分布式系统(5) -- 再也不怕算得慢

这是《漫谈分布式系统》系列的第 3 篇,预计会写 30 篇左右。欢迎订阅,听我娓娓道来。也欢迎转发朋友圈分享给更多人。

系列第一篇中,我们提到,为了解决算得慢的问题,必须让计算并行起来。

本质上还是分治法,先把计算拆分成一个个小任务执行,再合并这些任务的结果得到最终结果。

虽然理论上没有关联,但在实践上,计算的分治,是以存储的分治为前提的。否则,每个任务都要处理全量的数据,这个性能和资源开销是接受不了的。所以前面两篇我们讲了分布式存储作为前置知识。

今天这篇,我们就一起看看一个最简单的分布式计算系统是个什么样子。

1

计算的分治,其实可以从两个角度理解:

  • 计算逻辑的分治
  • 计算结果的分治

计算逻辑的分治,说白了,就是代码的并行执行。

并且很显然,为了保证结果的正确性,多机/多进程并行运行的代码是完全一样的。

区别只是在于处理的数据不同。这也是为什么前面说计算的分治是以存储的分治为前提。

所以,其实计算逻辑的分治,只是同样代码的不同实例,在相互独立地并行执行而已。

前面我们讲到分布式存储引擎的时候,探讨过怎么切分数据的问题。那分布式计算框架呢,又该怎么切分计算逻辑?

刚才已经说了,计算逻辑的分治区别只在处理的数据不同,所以计算逻辑的切分也就等价于数据的切分。

当然,这里对数据的切分,目的已经不同于我们在分布式存储里,为了更均衡的存储海量数据而切分到 block 这个粒度了。

我们的目的只是为了提高计算的并行度,再考虑到计算逻辑处在应用层,所以通常以文件为基本单位做切分。

比如,如果文件太小,可以几个文件合在一起处理;如果文件太大,又可以一个文件拆成几份并行处理(见上篇文章提到的文件的压缩和切分)。

2

而计算结果的分治就不一样了。

我们处理数据的目的是为了得到结果。为了提高性能,采用了分布式计算的方法,使得同样的代码被并行运行起来,每个代码实例都处理一部分的数据。

但是最终结果只能有一个,所以必须把每个实例处理的结果合并起来。

这也就导致原本单机单线程顺序执行的逻辑,被迫切分成了两部分。

看一个简单的例子。

如果我们有一个 100 万亿的整数数组,想要对每个元素乘 2 之后求和。方便起见,以 Python 为例,并且只展示 9 个数字的情况。

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

数据量小的时候,我们可以单机单线程处理,直接一个循环搞定:

top Created with Sketch.