系统设计的万能解法:SNAKE原则

2017/12/13 posted in  工作方法

首先什么是系统设计?

The process of defining the architecture, components, modules, interfaces, and data for a system to satisfy specified requirements.

系统设计有四大要素。 第一,是要满足一个需求即Requirements;第二,对内容进行一个定义;第三,从不同维度去考虑宏观的架构层、组件层、模块层;第四,也要考虑到互相间交流的接口和相关传递的数据。所以这些内容一起构成了整个系统设计。

系统设计有什么层次呢? 从上向下是从概念层到逻辑层再到物理层,从清晰度来看,会从不清晰,到越来越清晰,到最清晰,角度则是从宏观到微观。换句话理解,如果系统设计时,我们从顶层向下做设计,那就是一个自上而下的方法;如果是自下层往顶层设计,就是一个自下而上的方法。在后文中我们分别称之为宏观设计与微观设计。我们以Netflix为例来讲这两个方法。

如何设计Netflix

现在我们通过设计Netflix,来具体了解什么是系统设计的SNAKE原则。

这是Netflix的官方网页,上面有各种用户信息、搜索功能、以及列出的各个频道:Netflix流行的电影(Popular on Netflix)、当前的趋势(Trending Now)、惊险刺激电影(Exciting Movies)、漫画动画(Goofy Comedies)等等。每个电影类目下面会有很多具体的电影,如果点击可以看到详细内容,相信大家十分熟悉。

宏观设计

Scenario(场景):用例/接口

  • 第一步:枚举在Netflix里面,到底有哪些场景

  • 第二步:选出里面最重要的排序

    • 基本需求:播放电影

    • 获得频道

    • 获得频道内电影

    • 播放频道内电影

这是三个基本需求的排序。

Necessary(限制):查看需求/假设

  • 第一步:询问

  • 第二步:预测

- 通过日活用户,计算平均并发用户

=日活用户/每日秒数*平均在线时长(假设为30min)

= 5,000,000 / (24 * 60 * 60) * (30 * 60)

= 104,167

  • 高峰并发用户,通常是平均用户的2-10倍,这里假设为6倍

高峰并发用户 = 平均并发用户 * 6 = 625,000

  • 假设未来3个月,Netflix用户涨2倍

- 3月后高峰并发用户 = 高峰并发用户 * 2 = 1,250,000

* *流量*

* - 单用户流量 = 3mbps(假设数据,满足看电影基本需求)

* - 3月后高峰流量 = 1,250,000 * 3 mbps = 3.75 Tb/s

* *内存*

- 单用户内存 = 10KB(假设用户数据不清空)

  • 3月后高峰内存 = 5,000,000 * 2 * 10 KB= 100GB(当前日活用户500万,3个月后日活用户为2倍)

    • 硬盘

      • 电影数=14,000份,每部电影=50G(假设数据,且每部电影需要存储不同清晰度版本)
      • 总硬盘=电影数单电影空间=14,00050GB=700TB

Application(应用):服务/算法

具体来看,我们有用户服务、频道服务和电影服务三种需求,在上面有一个接待员可以获得各种服务请求,接待员把所有服务接受完以后发送给后台的服务,就可以满足需求。

Kilobit(数据)

  • 第一步:为每个请求添加服务模块

  • 第二步:选择存储方式。对于用户数据用MySQL;频道数据用MongoDB;电影服务由于只是从文件出来,所以往往采取Movies的方式。

Evolve(进化)

  • 第一步:分析

    • 三个方向

      • 更好:限制性条件,10个用户变为100个

      • 更广:场景,是否还有支付场景等

      • 更深:细节,是否用CDN,如何部署

    • 三个角度

      • 性能:单个点的计算能力如何,或某个算法的性能如何

      • 扩展:如果机器或者用户量翻倍怎么办

      • 鲁棒:发生各种危险,崩溃时服务器能不能处理

  • 第二步:根据场景回溯并进化

以上是我们SNAKE五步原则在宏观设计中的应用。

微观设计

因为Netflix里推荐电影是最基本的一个需求,那我们就做一个具体的微观设计模块——推荐模块

如何设计推荐模块?
[image:31D5BBBD-90C1-46A7-83FF-770ECDF000DB-18349-00003D57A76D6211/46EF94A2-E9B2-4202-80F2-FCA3D3A6B0F1.png]

我们可以看到用户1和用户2重复喜欢的电影数有3个:m3、m5、m7。

我们的需求是:寻找一个用户的最相似用户。

Scenario(场景)

[image:380CD6F7-214C-4F59-BDAC-A58B8307980F-18349-00003D59219C3908/33B15465-DA6E-42B6-B1FF-E6C43C3CBFFF.png]

我们可以定义一个接口,定义之后直接找到我最相似的用户,输入一个用户ID,输出一个用户ID,接口就出来了。

Necessary(限制)

在微观设计里我们可以继续做预测,比如针对这个请求,它的QPS即每秒请求量是多少?
[image:CFBBE35B-6C6D-47B2-B0A9-5B28334709AC-18349-00003D5ABD820D5D/EAEC4D4C-2F47-4849-ACD7-EFEE87AC5101.png]

Algorithm(算法)&Kilobit(数据)

算法和数据在微观设计里往往可以放到一起。具体做时,不同的算法和不同的数据结构性能差异很大。

比如有3个用户u1,u2,u3,最简单的方法是两两比较。想算出与u1最相似的用户,就先把u1、u2比,发现相似度是1;u1、u3比,发现相似度是2。最终我们发现,这个算法的性能非常差,可能每一个计算都需要200毫秒,相当于每个计算节点只能计算5个QPS,而我们需要2000多QPS,明显无法达到。
[image:6506D45F-90F3-465D-8D5A-0BE95D72D5AC-18349-00003D5CE1C444B1/4AC1E2CF-B647-43CB-AFDD-8122AB3989B5.png]

Evolve(进化)

我们先看一下当前的架构:原始数据给推荐模块,推荐模块返回请求。
[image:B1DDDB7E-FBA0-4051-95CD-D4E4E35083BD-18349-00003D5E7BC647B2/D4119C6C-32B7-46BE-8719-286C8344BFFE.png]

因此我们需要从性能、扩展、鲁棒三个维度来进化。

1. 提升性能

怎么提升性能?提升单点的计算能力?

我们通过建立倒排索引,能够非常简单地优化算法的性能。比如现在把由用户建立改为由电影建立,即先计算出每个电影被哪些用户喜欢。比如m3被用户1、2、3喜欢。我们先找u1喜欢的电影,这里是m1、m3、m7,然后轮流遍历这些电影,每当这个电影还被其他用户喜欢,则相似度+1。于是我们就可以降低n的复杂度,计算所有的相似度。这样复杂度就从n的三次方降为了n的平方。所以性能大大提升,变成了每个20毫秒,能实现单机50QPS,但仍然无法达到需要的2000+QPS。
[image:52D38FB3-1AC2-41E4-B3C4-43C222EB23BF-18349-00003D615DC545A3/3C6C80AB-74BD-40A8-92A4-7581CB75C7A4.png]

这时的架构已经做了提升:通过加入一个准备器,将原始数据输入进来,并且创建索引返回给推荐器。
[image:BA00E10D-18EE-43EB-88F8-03A22DF3A0BB-18349-00003D6308699FB7/4986DC9F-D5BB-41F8-A6E0-031BE0709349.png]

2. 提升扩展性

之前有了一个简单的架构,能计算出所有索引,现在需要将推荐模块全部平行地放进来。现在不仅有一个推荐模块,还可以有好几个推荐模块,同时上面还有一个分配器,把整个推荐模块的请求分配给不同推荐器来进行计算。
[image:320CC916-AE69-43F0-9A53-E9341637317B-18349-00003D65221072D7/9BFD0854-7C09-4F51-82CF-3370785AD744.png]

那么问题是:需要多少个推荐器来满足2083QPS呢?

其实很简单,因为刚才单个推荐模块能满足50QPS,所以用2083除以50就可以得出答案,当然也可以多算几个来进行缓冲。

3. 提高鲁棒性

提高鲁棒性,防止服务器崩溃,需要怎么办呢?答案是做热备。

之前的数据有1个人管理,推荐器有一个模块在运行,上面是管理者在管理。

现在可以热备出另外一个数据集,把它们放一起;同时也热备出一个推荐模块放在一起。下图中每个橙色的虚框表示一个集群组合在一起。顶层可以用Apache接外部服务器顶住请求。还会有一些记录日志,比如Big Brother。它们中间通过一个消息分配者把消息分配出去。

如果要给系统进行升级,我们可以通过添加模块来轻松地实现。比如想加入一个Feed流,相当于新浪微博这样的架构,那只需要把这个模块添加到系统中。
[image:D0A434A5-4272-41AE-A3DF-42A409E16763-18349-00003D675BED419B/2AE5AFC8-6C0C-4FEF-9849-EF96568249A9.png]

上图可以看到,绿色的虚线表示它们之间进行消息传递;而绿色粗线表示它们之间有一个数据的快速通道,这样就不用所有消息都通过中间的消息传递者传输,避免影响效率。

总结:SNAKE原则

  • Scenario(场景)

  • Necessary(限制)

  • Application(应用)

  • Kilobit(数据)

  • Evolve(进化)

通过项目的搭建,建立Solid的系统设计思维,真正了解系统设计中会遇到的问题,并亲手解决这些问题,提升50%你的学习效率。

欢迎了解BitTiger大数据工程师、全栈工程师、大数据工程师直通车

BitTiger直通车特色

三个月、三个工业级别大项目

全面提升编程实力与简历背景

硅谷一线IT公司导师、了解痛点的助教

全方位指导及答疑

修改简历、模拟面试、职业咨询

Career Service全程护航

独家面试题库精讲

上百小时基础及面试视频资源助

点击“阅读原文”查看BitTiger直通车

http://t.cn/RYD2Pb3

系统设计的万能解法:SNAKE原则