计算系统的设计其实就是在玩约束条件的游戏。一个设计良好的系统就像是个定制化的运输箱:它的外部有锁扣和手柄,但从里面装的东西来看其内部设计,却往往给人印象不佳。如果要设计一个优雅简洁的容器,你应该聚焦在那些最重要的因素上:尺寸、重量、;平衡和移动。这些因素以及它们之间的相关影响就构成了设计中的有效约束条件。
在这篇文章中,我将描述了一种对系统数据的形状和流的约束条件进行分析的方法,并将它应用在真实世界的例子中。基于约束条件的方法和物流领域中的 格德拉特(Goldratt)理论 相似。根据我的经验,最成功的系统设计师和容量规划师倾向于依据具体的约束条件来思考计算系统,即使他们可能没有说出声来。
相比从基准(benchmark)外推,或者争论“并发用户”的定义,使用约束条件方法要有用的多。它能在编码之前揭示可能的系统瓶颈及其相互的依赖关系。这些知识对于理性地选择设计方案至关重要。通过实践你甚至可以对别人,比如竞争对手的系统做出敏锐的猜测,而这也很简单,只需要你观察它是如何运行的。
这个技巧在于先建立数据的尺寸和重量,然后聚焦于它是如何流动的。计算机其实只做两件事情:读入数据和写出数据。性能决定了多少数据可以移动,以及它们移动到哪里来完成任务。说起来似乎很容易,但这需要掌握基础的计算理论。每个计算机等同于一个 图灵机(Turing Machine) ,而所有图灵机做的事情就是在磁带上移动符号,所以它的吞吐量取决于符号移动的速度。从小的微米级的CPU内部到大的横跨世界的分布式数据库,这个推论仍然成立。幸运的是,这里的数学方法简单明了。
可以迅速丢弃坏的方案,而无需实际创建它们,这种能力对于好的系统编程有决定性的意义。它部分是靠直接,还有一些经验,但最主要的是算法。
— Keith Adams
我认为描述系统最有用的八个因素如下:
找到一个你想分析的系统,然后填写出上述的那些约束条件,并且草拟一个方案能满足这些条件。下来问自己最后一个问题:决定性的操作是什么?换句话说,最基本的瓶颈在什么地方?哪些部分必须仔细考量?
当你大声说出来答案时,虽然听起来可能平淡无奇,但是确定一个系统的真正瓶颈对于 认知事物有极大的帮助 。偶发性的瓶颈往往会形成堆积,修正一个会激活另一个,但是它们不会对你设计的基本前提形成颠覆性的威胁。基础性的瓶颈则难于修复,也很难识别,因为它们是由创建系统时基于的一些自然事实或者一个强假定引起的。一个无穷快的网址仍然受限于光的速度,火箭也会受限于提升自身燃料重量的需求。保持这种思考性的实验直到你完全理解最基础的瓶颈是什么?以及为什么?
我们可以打个比方,你有个披萨店,想赚更多的钱。如果购买的人排长队,你可以把订单登记的数量增加一倍。如果是披萨送货时迟到,你可以规划一个更好的工作节奏,或者为送货员配备车辆。甚至你可以尝试提高烤箱的温度。但从根本上说,披萨店的瓶颈是烤箱的尺寸。即使你把其他事情都做好,如果烤箱容量不扩张,你也无法生产出更多的披萨。当然你也可以再购买一个烤箱,不过你必须事情想清楚,把这个新家伙放到什么地方。
如果你不能清晰地发现系统的基本瓶颈,那么就去改变系统的约束条件,看看它的响应有什么变化。比如你必须将延迟降低10倍,看看会发生什么?比如你只用一半数量的计算机?如果放松一致性的约束,又要靠什么样的技巧才能侥幸成功?通常认为初始约束是真实和静止的,但实际中它们很少如此。问题中的创造力远比答案中的创造力更有利用价值。
如果你想了解某件事情,把它放在极端条件下观察或者检查它的对立面。
——Col. John Boyd
让我们将上面的方法应用到比披萨店更复杂的案例中,即视频流服务。可以想象它是一个小规模的Hulu或Netflix,视频库容量为十万个,平均60分钟的时长,500 kbps的比特率。在高峰时间,大约会有一百万人观看。
现在让我们来概述一下可以满足这些约束条件的系统。总共20TB需要保存的数据量,看上去不算太大;500Gbps的请求速率,看上去数据服务量还是挺多。如果我们使用当前(2015年)16核的文件服务器,它可以轻松完成7 Gbps的有效网络数据吞吐,所以我们需要至少50个这样的服务器,每个上面配置128 GB的RAM,还有2 TB的存储,这样很容易容纳整个的工作集数据。
虽然我们可以把数据存储起来,但我们可以移动它们吗?让我们再来看看欢迎度曲线,前100个视频占了总需求的10%,所以你会想要在每个服务器存储这100个视频的副本。实际中你可能会对前一个视频都这样做,它们占了总带宽的三分之一,但只用掉了10%的存储空间。如果有足够的RAM和一点运气,那么受欢迎的视频几乎完全可以从内存中提供服务。
这样,还剩下9万个视频,处于长尾右端的3万个视频观看次数很少,所以无关紧要。但长尾中间的6万个视频占了总业务流量的2/。所以需要考虑如何为它们服务,同时保持延迟条件的约束?由于RAM已经被最受欢迎的视频占用,所以接下来就要算算存储层额可以支持多少500 kbps的业务流量并发。具体的设计可能要进行测试后才会出来,但最终很可能是几百个磁盘驱动器并行工作来达到好的结果。
从这里我们可以得出结论: 视频服务的基本瓶颈 是随机寻道时间,在设计上这等同于那些小的金属机械臂可以来回移动的速度。起控制作用的约束条件是人们观看视频的欢迎度曲线,这个是你无法改变的。
还有其他的设计方案可能会解决这个问题。例如,在每个服务器上配置1 TB的RAM,而不是2 TB的磁盘。使用今天或明天的SSD技术也可以圆满的解决这个问题。这里用到的数字可能不是很准确,而且肯定会随着时间的推移而改变。关键是发现那些最重要的具体细节,并重点讨论它们。
有时候,系统会被一个特定操作严重主导,以至于几乎其它操作相比它都无足轻重。可以举一个有趣的案例,即人脸识别。记住不是人脸检测,人脸检测仅仅是在图像中找到人脸,而决定在给定照片中的人是谁,则需要和照片库中照片进行比较。
人脸识别首先需要对已知人群的照片进行预处理,以便对每个人的基本特性生成一种抽象描述,这种抽象描述有个非常奇怪的名字,叫“ 特征脸(eigenface) ”。一个特征脸是一个固定大小的数据块,通常小于100 kB,它可以由 一些聪明的算法 生成。生成特征脸的主要好处是可以 相对低廉的计算 任意两个人脸之间的相似度得分。得分越高,两个人脸轮廓特征就越接近,从而你识别出这个人是谁的可能性更高。
假设你有一个对应五千万个体的人脸特征库,它们可能来自国民护照,或者驾照数据库,或者是世界上最大的年鉴。系统每秒会有数百个查询照片流请求进来,这些实时地流请求来自边境机构的护照控制需求。必须在1秒或更少的时间内为每张照片找到相似度排名前十的匹配者。好了,我们开始分析:
满足低延迟需求的唯一方法是在执行在给定的搜索时,大幅减少特征脸全面对比的数量。但正如肠道检查那样,这涉及到可能性的范畴,即在这个问题上是否可以投入足够的计算资源?答案很可能是No。每秒特征脸对比的次数=5000万* 10毫秒* 300,这大约需要每秒5000 CPU-years的计算能力。我看过一些大型集群,但都达不到这样的规模要求。
所以我们需要用些聪明的方法来减少工作。这个领域中比较活跃的研究是一种快速搜索【特征脸索引】的方案,但是通过摘要我们知道其加速线性而不是对数的(所以可能无法满足我们的性能需求)。谷歌有一个通用的 图像相似度搜索 方案,这个理论上也许是可行的,但是不一定是可用的技术。现在我们先停止调查,尝试一下别的东西吧。也许我们可以基于人的眼睛颜色、年龄或性别来消除大部分的候选人。举个例子来说,对比一个30岁的女人和一个男孩子的照片是没有意义的。
假设可以通过启发式和低成本的技巧来缩小候选人的数量,比如对于一个给定的查询照片只需要对比1000个候选人。这相当于用10个CPU来解决10,000毫秒(译者注:1000个候选人乘以10毫秒)的计算问题以让延迟控制在1秒,如果添加更多的资源,完成任务就没有问题。如果每个用12个CPU,那么300 * 12意味着我们总共需要3600个CPU来处理请求,这大约是250台服务器或是六个机架。这样的计算机集群其重量大概是三吨,其计算能力以任何标准衡量都是相当高的,但为了这个重要的项目还是值得的。
我们现在可以计算它了,但是我们可以保存数据吗?5TB对于RAM来说是相当多的。但从另一方面来说,我们有服务器集群来提供这些内存。将库中的特征脸数据分布到集群的RAM中有点类似Memcached的方案。
好了,现在让它动起来吧。噢。它看起来走不了。
我们可以存储它,但是我们可以移动它吗?我们忘记更新平均请求尺寸了。如果单个请求访问1000个特征脸,这些特征脸数据是随机分布的,这相当于将100 MB的数据从它所在的Memcached服务器移动到另一个负责特征脸对比的CPU所在的服务器上。假如那个时间每秒有300个请求,那我们就会面临240gbps网络带宽消耗,这是个致命的风险。对于每台服务器来说,这接近于1gbps这个令人不安的数据,而且此时CPU已经忙于特征脸的比较而无法应对这么高的网络传输负载。
我们需要将计算放在数据存储的地方,而不是将数据传输到计算节点。在开始比较之前,我们准确地知道哪1000个特征脸需要对比。Memcached对特征脸键值采用直接哈希的方式,所以特征脸存储的服务器是很容易得知的,下来就可以将具体的请求路由到这个特定的服务器上。每个服务器基于本地数据会做4或5次比较,并返回它们的相似度得分。整体的相似度得分的列表可以很容易地组装起来并进行排序。这种方案下,唯一的网络流量将是查询时特征脸照片所占的100 KB,乘以服务器的数量250,估算成300倍,总共60gbps,这个数字虽然很高,但是是可行的。进一步,可以使用更聪明的数据分布方案来避免数据查询展开到整个集群中。
系统的基本瓶颈就是扫描那些特征脸,到目前这点可能看得还不是很清晰。这是个比较难的问题,我们几乎没找到一个合理的解决方案,甚至我们还没有考虑识别的准确性是否足够有用。这种人脸识别的分析在重要细节几乎肯定会出错,但从一些懂行的人 给出的评论 来看,方案大致是正确的。我故意选择了这个我不太了解的用例来演示如何约束分析如何帮助你分析系统,即使(特别)你不是一个专家。
想象一个专家过来告诉你“为什么不利用GPU呢?他们可以将特征脸的对比提速十倍!”你可以回答“听上去很有趣,但是它对网络带宽问题有何帮助呢?”(实际上可能会有帮助,如果它能减少机器数量)。如果有人说“我有一个办法来索引特征脸!”你可以回答“这很有趣,但前提是它能帮助我执行不到1000次完整的比较。顺便说一下,你应该和懂GPU的那帮家伙聊聊。”你也知道应该密切注意说这样话的一些人,即 “我可以使用比100KB更小的尺寸来准确地代表一个人的脸。”
这其是基于约束条件分析方法的真正价值,即帮助你更好理解问题的物理意义,从而揭示出那些需要创造性的地方。像特征脸技巧那样,它允许你通过标准形式来呈现复杂的图片,从而可以在对比中很快地接受或拒绝。
科学不仅仅是探索为什么(Why),而是为什么不(Why not)?
— Cave Johnson
类似这种大数据系统分析的工作有几个技巧值得去练习。能够通过不完整的数据进行 快速评估 是至关重要的。例如,谷歌拥有多少台服务器呢?(可以按照 电力消耗 来估算)。另一个很好的技能是能丢弃推理中那些有缺陷的思路,并及时对 大脑中的想法进行刷新 。Jeff Dean有许多非常好的在线谈论包括“ 你应该知道的数字 ”以及如何考虑大型系统的设计。
可以在现有系统上进行约束条件分析,然后来查找答案,这对于掌握技能是个很好的方式。在本文中,我回避了那些有高更新速率或高一致性约束条件的案例。但你可以花一个小时左右的时间来分析一些类似的商业系统以增强了解,比如2004年左右时的AdWords、2005年时的YouTube或者2005年的Flickr。关于这些系统都有一些很好的评论和讨论,而且是系统的创建者写的。但是建议你在独立的解答之前先不要看这些文章。
Carlos Bueno 在 数据库公司MemSQL 工作,之前他是Facebook、Yahoo和几个初创公司的性能工程师。Carlos写了一本计算机科学小说《 Lauren Ipsum 》,深受孩子们喜爱。他还是《 Mature Optimization 》的作者,这是一本Facebook性能分析的手册。
查看英文原文: Shaping Big Data Through Constraints Analysis