极客时间已完结课程限时免费阅读

52 | 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药

52 | 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药-极客时间

52 | 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药

讲述:徐文浩

时长11:53大小13.60M

如果你一讲一讲跟到现在,那首先要恭喜你,马上就看到胜利的曙光了。过去的 50 多讲里,我把计算机组成原理中的各个知识点,一点一点和你拆解了。对于其中的很多知识点,我也给了相应的代码示例和实际的应用案例。
不过呢,相信你和我一样,觉得只了解这样一个个零散的知识点和案例还不过瘾。那么从今天开始,我们就进入应用篇。我会通过两个应用系统的案例,串联起计算机组成原理的两大块知识点,一个是我们的整个存储器系统,另一个自然是我们的 CPU 和指令系统了。
我们今天就先从搭建一个大型的 DMP 系统开始,利用组成原理里面学到的存储器知识,来做选型判断,从而更深入地理解计算机组成原理。

DMP:数据管理平台

我们先来看一下什么是 DMP 系统。DMP 系统的全称叫作数据管理平台(Data Management Platform),目前广泛应用在互联网的广告定向(Ad Targeting)、个性化推荐(Recommendation)这些领域。
通常来说,DMP 系统会通过处理海量的互联网访问数据以及机器学习算法,给一个用户标注上各种各样的标签。然后,在我们做个性化推荐和广告投放的时候,再利用这些这些标签,去做实际的广告排序、推荐等工作。无论是 Google 的搜索广告、淘宝里千人千面的商品信息,还是抖音里面的信息流推荐,背后都会有一个 DMP 系统。
那么,一个 DMP 系统应该怎么搭建呢?对于外部使用 DMP 的系统或者用户来说,可以简单地把 DMP 看成是一个键 - 值对(Key-Value)数据库。我们的广告系统或者推荐系统,可以通过一个客户端输入用户的唯一标识(ID),然后拿到这个用户的各种信息。
这些信息中,有些是用户的人口属性信息(Demographic),比如性别、年龄;有些是非常具体的行为(Behavior),比如用户最近看过的商品是什么,用户的手机型号是什么;有一些是我们通过算法系统计算出来的兴趣(Interests),比如用户喜欢健身、听音乐;还有一些则是完全通过机器学习算法得出的用户向量,给后面的推荐算法或者广告算法作为数据输入。
基于此,对于这个 KV 数据库,我们的期望也很清楚,那就是:低响应时间(Low Response Time)、高可用性(High Availability)、高并发(High Concurrency)、海量数据(Big Data),同时我们需要付得起对应的成本(Affordable Cost)。如果用数字来衡量这些指标,那么我们的期望就会具体化成下面这样。
低响应时间:一般的广告系统留给整个广告投放决策的时间也就是 10ms 左右,所以对于访问 DMP 获取用户数据,预期的响应时间都在 1ms 之内。
高可用性:DMP 常常用在广告系统里面。DMP 系统出问题,往往就意味着我们整个的广告收入在不可用的时间就没了,所以我们对于可用性的追求可谓是没有上限的。Google 2018 年的广告收入是 1160 亿美元,折合到每一分钟的收入是 22 万美元。即使我们做到 99.99% 的可用性,也意味着每个月我们都会损失 100 万美元。
高并发:还是以广告系统为例,如果每天我们需要响应 100 亿次的广告请求,那么我们每秒的并发请求数就在 100 亿 / (86400) ~= 12K 次左右,所以我们的 DMP 需要支持高并发。
数据量:如果我们的产品针对中国市场,那么我们需要有 10 亿个 Key,对应的假设每个用户有 500 个标签,标签有对应的分数。标签和分数都用一个 4 字节(Bytes)的整数来表示,那么一共我们需要 10 亿 x 500 x (4 + 4) Bytes = 4 TB 的数据了。
低成本:我们还是从广告系统的角度来考虑。广告系统的收入通常用 CPM(Cost Per Mille),也就是千次曝光来统计。如果千次曝光的利润是 0.10 美元,那么每天 100 亿次的曝光就是 100 万美元的利润。这个利润听起来非常高了。但是反过来算一下,你会发现,DMP 每 1000 次的请求的成本不能超过 0.10 美元。最好只有 0.01 美元,甚至更低,我们才能尽可能多赚到一点广告利润。
这五个因素一结合,听起来是不是就不那么简单了?不过,更复杂的还在后面呢。
虽然从外部看起来,DMP 特别简单,就是一个 KV 数据库,但是生成这个数据库需要做的事情更多。我们下面一起来看一看。
在这个系统中,我们关心的是蓝色的数据管道、绿色的数据仓库和 KV 数据库
为了能够生成这个 KV 数据库,我们需要有一个在客户端或者 Web 端的数据采集模块,不断采集用户的行为,向后端的服务器发送数据。服务器端接收到数据,就要把这份数据放到一个数据管道(Data Pipeline)里面。数据管道的下游,需要实际将数据落地到数据仓库(Data Warehouse),把所有的这些数据结构化地存储起来。后续,我们就可以通过程序去分析这部分日志,生成报表或者或者利用数据运行各种机器学习算法。
除了这个数据仓库之外,我们还会有一个实时数据处理模块(Realtime Data Processing),也放在数据管道的下游。它同样会读取数据管道里面的数据,去进行各种实时计算,然后把需要的结果写入到 DMP 的 KV 数据库里面去。

MongoDB 真的万能吗?

面对这里的 KV 数据库、数据管道以及数据仓库,这三个不同的数据存储的需求,最合理的技术方案是什么呢?你可以先自己思考一下,我这里先卖个关子。
我共事过的不少不错的 Web 程序员,面对这个问题的时候,常常会说:“这有什么难的,用 MongoDB 就好了呀!”如果你也选择了 MongoDB,那最终的结果一定是一场灾难。我为什么这么说呢?
MongoDB 的设计听起来特别厉害,不需要预先数据 Schema,访问速度很快,还能够无限水平扩展。作为 KV 数据库,我们可以把 MongoDB 当作 DMP 里面的 KV 数据库;除此之外,MongoDB 还能水平扩展、跑 MQL,我们可以把它当作数据仓库来用。至于数据管道,只要我们能够不断往 MongoDB 里面,插入新的数据就好了。从运维的角度来说,我们只需要维护一种数据库,技术栈也变得简单了。看起来,MongoDB 这个选择真是相当完美!
但是,作为一个老程序员,第一次听到 MongoDB 这样“万能”的解决方案,我的第一反应是,“天底下哪有这样的好事”。所有的软件系统,都有它的适用场景,想通过一种解决方案适用三个差异非常大的应用场景,显然既不合理,又不现实。接下来,我们就来仔细看一下,这个“不合理”“不现实”在什么地方。
上面我们已经讲过 DMP 的 KV 数据库期望的应用场景和性能要求了,这里我们就来看一下数据管道数据仓库的性能取舍。
对于数据管道来说,我们需要的是高吞吐量,它的并发量虽然和 KV 数据库差不多,但是在响应时间上,要求就没有那么严格了,1-2 秒甚至再多几秒的延时都是可以接受的。而且,和 KV 数据库不太一样,数据管道的数据读写都是顺序读写,没有大量的随机读写的需求。
数据仓库就更不一样了,数据仓库的数据读取的量要比管道大得多。管道的数据读取就是我们当时写入的数据,一天有 10TB 日志数据,管道只会写入 10TB。下游的数据仓库存放数据和实时数据模块读取的数据,再加上个 2 倍的 10TB,也就是 20TB 也就够了。
但是,数据仓库的数据分析任务要读取的数据量就大多了。一方面,我们可能要分析一周、一个月乃至一个季度的数据。这一次分析要读取的数据可不是 10TB,而是 100TB 乃至 1PB。我们一天在数据仓库上跑的分析任务也不是 1 个,而是成千上万个,所以数据的读取量是巨大的。另一方面,我们存储在数据仓库里面的数据,也不像数据管道一样,存放几个小时、最多一天的数据,而是往往要存上 3 个月甚至是 1 年的数据。所以,我们需要的是 1PB 乃至 5PB 这样的存储空间。
我把 KV 数据库、数据管道和数据仓库的应用场景,总结成了一个表格,放在这里。你可以对照着看一下,想想为什么 MongoDB 在这三个应用场景都不合适。
在 KV 数据库的场景下,需要支持高并发。那么 MongoDB 需要把更多的数据放在内存里面,但是这样我们的存储成本就会特别高了。
在数据管道的场景下,我们需要的是大量的顺序读写,而 MongoDB 则是一个文档数据库系统,并没有为顺序写入和吞吐量做过优化,看起来也不太适用。
而在数据仓库的场景下,主要的数据读取时顺序读取,并且需要海量的存储。MongoDB 这样的文档式数据库也没有为海量的顺序读做过优化,仍然不是一个最佳的解决方案。而且文档数据库里总是会有很多冗余的字段的元数据,还会浪费更多的存储空间。
那我们该选择什么样的解决方案呢?
拿着我们的应用场景去找方案,其实并不难找。对于 KV 数据库,最佳的选择方案自然是使用 SSD 硬盘,选择 AeroSpike 这样的 KV 数据库。高并发的随机访问并不适合 HDD 的机械硬盘,而 400TB 的数据,如果用内存的话,成本又会显得太高。
对于数据管道,最佳选择自然是 Kafka。因为我们追求的是吞吐率,采用了 Zero-Copy 和 DMA 机制的 Kafka 最大化了作为数据管道的吞吐率。而且,数据管道的读写都是顺序读写,所以我们也不需要对随机读写提供支持,用上 HDD 硬盘就好了。
到了数据仓库,存放的数据量更大了。在硬件层面使用 HDD 硬盘成了一个必选项。否则,我们的存储成本就会差上 10 倍。这么大量的数据,在存储上我们需要定义清楚 Schema,使得每个字段都不需要额外存储元数据,能够通过 Avro/Thrift/ProtoBuffer 这样的二进制序列化的方存储下来,或者干脆直接使用 Hive 这样明确了字段定义的数据仓库产品。很明显,MongoDB 那样不限制 Schema 的数据结构,在这个情况下并不好用。
2012 年前后做广告系统的时候,我们也曾经尝试使用 MongoDB,尽管只是用作 DMP 中的数据报表部分。事实证明,即使是已经做了数据层面的汇总的报表,MongoDB 都无法很好地支撑我们需要的复杂需求。最终,我们也不得不选择在整个 DMP 技术栈里面彻底废弃 MongoDB,而只在 Web 应用里面用用 MongoDB。事实证明,我最初的直觉是正确的,并没有什么万能的解决方案。

总结延伸

好了,相信到这里,你应该对怎么从最基本的原理出发,来选择技术栈有些感觉了。你应该更多地从底层的存储系统的特性和原理去考虑问题。一旦能够从这个角度去考虑问题,那么你对各类新的技术项目和产品的公关稿,自然会有一定的免疫力了,而不会轻易根据商业公司的宣传来做技术选型了。
因为低延时、高并发、写少读多的 DMP 的 KV 数据库,最适合用 SSD 硬盘,并且采用专门的 KV 数据库是最合适的。我们可以选择之前文章里提过的 AeroSpike,也可以用开源的 Cassandra 来提供服务。
对于数据管道,因为主要是顺序读和顺序写,所以我们不一定要选用 SSD 硬盘,而可以用 HDD 硬盘。不过,对于最大化吞吐量的需求,使用 zero-copy 和 DMA 是必不可少的,所以现在的数据管道的标准解决方案就是 Kafka 了。
对于数据仓库,我们通常是一次写入、多次读取。并且,由于存储的数据量很大,我们还要考虑成本问题。于是,一方面,我们会用 HDD 硬盘而不是 SSD 硬盘;另一方面,我们往往会预先给数据规定好 Schema,使得单条数据的序列化,不需要像存 JSON 或者 MongoDB 的 BSON 那样,存储冗余的字段名称这样的元数据。所以,最常用的解决方案是,用 Hadoop 这样的集群,采用 Hive 这样的数据仓库系统,或者采用 Avro/Thrift/ProtoBuffer 这样的二进制序列化方案。
在大型的 DMP 系统设计当中,我们需要根据各个应用场景面临的实际情况,选择不同的硬件和软件的组合,来作为整个系统中的不同组件。

推荐阅读

如果通过这一讲的内容,能让你对大型数据系统的设计有了兴趣,那就再好不过了。我推荐你去读一读《数据密集型应用系统设计》这本书,深入了解一下,设计数据系统需要关注的各个核心要点。

课后思考

这一讲里,我们讲到了数据管道通常所使用的开源系统 Kafka,并且选择了使用机械硬盘。在 Kafka 的使用上,我们有没有必要使用 SSD 硬盘呢?如果用了 SSD 硬盘,又会带来哪些好处和坏处呢?
请你仔细思考一下,也可以和周围的朋友分享讨论。如果你觉得有所收获,也请你把你的想法写在留言区,分享给其他的同学。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 29

提建议

上一篇
51 | 分布式计算:如果所有人的大脑都联网会怎样?
下一篇
53 | 设计大型DMP系统(下):SSD拯救了所有的DBA
unpreview
 写留言

精选留言(23)

  • 胖头小C
    2019-09-02
    SSD硬盘好处是读写更快,但是使用寿命不长,在Kafka经常擦除情况下,机械盘更耐用,经济,而且是顺序读写,机械盘也是很快的,综合还是机械盘更好

    作者回复: 👍

    60
  • 鱼向北游
    2019-09-02
    不差钱可以用ssd呀 ssd的顺序写速度更快 但是 kafka这种应该会频繁擦写 ssd的寿命扛不住 对于存档 hdd普遍容量大 存档成本低 组raid价格也便宜 对于和ssd顺序读写的性能差距 可以用扩大partition数量来做些弥补 怎么感觉说到底最后是钱的问题呢

    作者回复: 👍哈哈,你抓到关键了。 这个还真是钱的问题,从2019年的应用场景来看,SSD的确还没有太大必要。从数据量的角度,搞很多块HDD已经可以满足目前的高并发的需求了,从成本上和使用寿命也比SSD更划算了。 但是SSD和几年前比已经便宜了很多了,而且在PCI-E接口普及的情况下,顺序读写速度比起HDD也能拉开差距了,所以逐步我们也看到业界开始直接用SSD来部署Kafka也变得比较常见了。

    29
  • 随心而至
    2019-10-24
    1.重视底层知识,核心知识,万丈高楼平地起。 2.使用场景。没有一招鲜,吃遍天的技术。 3.要有量级的概念。kv数据库,数据管道,数据仓库,就根本不是一个量级的事情,每个量级都应该有自己的最优方案。 刚工作一年多一点,不对之处请老师指出
    展开
    26
  • 许童童
    2019-09-02
    我觉得没有必要使用SSD,Kafka主要利用PageCache来提高系统写入的性能,而且Kafka对磁盘大多是顺序读写,在磁盘上提高IOPS,并不能显著的提升Kafka的性能。

    作者回复: 👍的确Kafka用SSD的必要性不大。

    16
  • 逍遥法外
    2019-09-02
    看的真过瘾
    共 1 条评论
    11
  • webmin
    2019-09-02
    Kafka使用SSD硬盘: 好处: Kafka是顺序追加写,比较适合SSD硬盘的特性; 坏处: Kafka的落盘数据类似于日志,顺序追加写SSD比机械硬盘没有太多的优势,再者擦写太频繁SSD硬盘有擦写寿命,使用SSD的性价比不如机械硬盘。
    展开

    作者回复: 👍 优缺点找的很对,最后的选择我们一般会从综合成本来考虑。

    共 2 条评论
    10
  • leslie
    2019-09-04
    以下是个人对此的理解:希望老师可以在下节课把这节课的答案公布。 分成两部分分别阐述个人对此的理解 一.机械硬盘 机械硬盘的好处是寿命:不过机械硬盘的问题在于速度,不同的机械硬盘有不一样的特性,即使用机械硬盘也要选择缓存偏大且读性能较好的蓝盘。由于kafka是充分利用缓存,毕竟kafka只是消息队列-只是中间件,我们不可能把数据放在kafka中,还是会使用的NOSQL数据库,故而其实际需求是对读性能要求较高的存储设备。 二.SSD SSD读写性能比其实是相对固定的:无论是哪个厂商,其实最终发现这是一个定值;有能力其实SSD确实是一个不错的选择。不过我们在讨论SSD的寿命时其实忽略了一个问题,什么操作影响SSD的寿命?SSD存在的硬件条件和场景是什么? 1.SSD的寿命问题:其实这个问题就像早期说液晶屏一样,额定寿命大概是3年左右,其实大多数实际情况都在5年左右;真正影响SSD寿命的不是读,而是写,这个问题其实机械硬盘同样有。 2.SSD存在的硬件条件是什么:服务器、PC;现在一台PC或者服务器基本上5-6年就各种硬件出现问题,SSD如果使用场景和HDD类似其实寿命是几乎一样的;我们不太可能在服务器都出问题的情况下还去使用使用吧。我自己笔记本电脑是单双硬盘:不过由于市场提供的尺寸不一样,大小略有区别,使用场景几乎完全一样,都各自有一个300G的空间跑虚机做测试,目前已经使用了4年多了,性能和4年前没区别,唯一的区别是当时HDD的代价是SSD的一半左右;现实中服务器的使用也就不超过5-6年,此时其实主板、电源、CPU的散热系统已经基本出问题且厂家和市场都没有相应可换的硬件配件了。 综上所述:故而个人觉得Kafka场景其实资金允许的情况下还是SSD,因为它的坏处其实传统硬盘同样有,这是我们不能回避HDD的硬件问题去说SSD的问题。即使使用HDD其实我们还是要选取读性能强于写性能且缓存偏大的硬盘,况且其实SSD的读写速度方面同样是读方面更好。严重写>读的场景下其实HDD的损坏速度同样非常快,只不过硬件代价低一些而已,但是耗时同样高许多。 期待老师的下节课:谢谢老师的教诲。
    展开

    作者回复: 小小的一个纠错,从原理的角度,HDD并不存在反复读写会导致寿命的问题。 不过在实际使用中,其实HDD的损坏率也并不低,而且损坏出现的情况随机性比较大。 实战中核心考虑的因素其实是成本,需要根据实际的应用场景,核算一下总体的成本。而且需要考虑到对应配置了CPU,比如用PCI-E接口,SSD硬盘的顺序读写能到2Gb/s,但是总的带宽有限可能又装不了10块盘。然后CPU和内存在单个机器中的价格占比也需要考虑,最后会是一个总和硬件拥有和维护成本的评估。这个问题并没有一个标准答案。

    共 3 条评论
    6
  • 活的潇洒
    2019-09-15
    工作中一直在用MongoDB但是并没有想过它不适合那些场景、今天老师从底层原理给我们刨析了个究竟 day52 笔记:https://www.cnblogs.com/luoahong/p/11510567.html
    2
  • 吴宇晨
    2019-09-02
    成本的问题ssd顺序读速度能更快,但是价格贵了很多,还有大概kafka主要读写是利用pagecache

    作者回复: 👍其实机器数量一上来,成本就成为架构设计的最重要的考虑因素之一了。

    2
  • 阿卡牛
    2019-09-02
    满满的干货,我先干为敬
    2
  • 李伟
    2021-06-04
    读到这里,为我打开了一个世界大门,我知道原来这才是设计和技术选型,而不是以前的bug少,维护快。
    2
  • Mr.埃克斯
    2020-09-21
    数据密集型应用系统设计 这本书挺不错,有空二刷一下。
    1
  • 陈德伟
    2022-02-09
    图里kv数据库的读写比例是不是写错了,应该读多写少
  • 易飞
    2021-10-09
    太牛了
  • dog_brother
    2021-05-12
    老师,为什么没有考虑用redis做kv呀?
    共 1 条评论
  • 人在江湖龙在江湖
    2020-11-11
    DMP系统讲的真的很好,受益匪浅。
  • Paul Shan
    2020-09-05
    如果Kafka 用了SSD硬盘估计响应时间会减少不少,尤其考虑PCI Express对于串行读写的优化更是如此,但是数据管道解决方案,响应时间要求不高,这个时候HDD硬盘寿命长价格低的的特点可能更重要一些。
  • Dovelol
    2020-07-11
    老师好,一般好多应用严格要求响应都是几ms,比如文章说的1ms,这种一般是怎么做到的呢,需要怎么优化,因为我感觉随便处理个什么逻辑或者查询缓存或者远程调用就不止1ms了。。
    共 1 条评论
  • Cyril
    2020-03-26
    干活慢慢,受益匪浅
  • 谢军
    2019-12-31
    那么一共我们需要 10 亿 x 500 x (4 + 4) Bytes = 400 TB 的数据了
    共 1 条评论