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

本文深入浅出地解析了分布式计算系统的两大核心概念:计算逻辑的分治与计算结果的分治,通过实例阐述了MapReduce框架如何实现计算任务的并行化,以及其背后的资源分配与调度机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是《漫谈分布式系统》系列的第 5 篇,预计会写 30 篇左右。每篇文末有为懒人准备的 TL;DR,还有给勤奋者的关联阅读。扫描文末二维码,关注公众号,听我娓娓道来。也欢迎转发朋友圈分享给更多人。  


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

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

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

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

 1

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

  • 计算逻辑的分治

  • 计算结果的分治

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

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

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

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

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

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

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

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

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

 2

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

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

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

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

看一个简单的例子。

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

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

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

result = 0
for i in a:
    result += i*2

但是在分布式的场景下,就不得不拆成两步去做了(只是示意,下面的代码仍然是单机运行)。

第一步,做乘 2 的处理:

b = map(lambda x: x*2, a)
// output:  [2, 4, 6, 8, 10, 12, 14, 16, 18]

第二步,汇总结果:

reduce(lambda x,y: x+y, b) 
// output: 90

不难看出,map 和 reduce 这两个函数,顾名思义,就很好的描述了自己的职责。

map 和 reduce 是典型的函数式编程的概念。主流分布式框架 Hadoop 的组成部分 -- 分布式计算框架 MapReduce 就得名于此。本质上就是先 map 再 reduce 这个分治思想的多机版本实现。

 3

那到底 MapReduce 是以什么粒度来拆分任务的呢?

map 和 reduce 有不同的处理方式。

对于 map,上面已经讲了,计算逻辑的分治取决于输入数据在文件层面的分治。

具体来说,输入一共有多少个 split,就会自动启动多少个 map 任务。

而 split 数,由文件格式和 block 大小决定。比如,如果一个文件可以切分(splittable),那这个文件就会被拆分成 file_size/block_size 这么多份;如果一个文件没法被拆分,哪怕大小是 block_size 的 100 倍,也只能被一个 map 任务处理(所以要尽量避免)。

而 reduce 就不一样了。

map 阶段的输出就是 reduce 阶段的输入。map 阶段的输入我们往往不能控制,但 map 的输出是完全在我们掌控之下的。所以 reduce 的输入就不像 map 的输入那样受限了,自然,reduce 阶段的并行度 -- 也就是 reducer 的数量,就是可以设置的了。

recucer 的数量,通常就是最终结果文件的数量。reducer 数量设置为 0 时,就会省略 reduce 阶段,跑完 map 阶段,程序就结束了。

reducer 数量具体设置成多少,就是运行速度和资源消耗的权衡了,可以根据实际情况灵活调整。

TL;DR

最简单的分布式计算系统,和分布式存储引擎一样,本质上仍然是分治法的运用:

  • 为了节省资源,计算的分治,是以存储的分治为前提的

  • 计算的分治,可以从两个角度理解:计算逻辑的分治和计算结果的分治

  • 计算逻辑的分治,只是相同代码的多机并行执行,区别只是处理的数据不同

  • 计算的分布式导致了计算过程被切分为 map 和 reduce 两个阶段

  • 计算结果的分治,是计算过程被切割后自然的影响

  • map 阶段的并行度取决于输入数据的切分度,和文件格式、压缩方式、block 大小等有关

  • reduce 阶段的并行度可以自行设置,是运行速度和资源消耗的权衡



算的快还不够,还要算的好。海量计算资源,如果管理不善,带来的就是巨大的浪费。下一篇,我们就一起看下,海量计算资源的管理和调度。

关联阅读

漫谈分布式系统(3) -- 再也不怕存不下

漫谈分布式系统(1) --  为什么要有分布式系统

原创不易

关注/分享/赞赏

给我坚持的动力

点在看,给大家好看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值