learn.lianglianglee.com/专栏/深入浅出计算机组成原理/52 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药.md.html
2022-08-14 03:40:33 +08:00

370 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>52 设计大型DMP系统MongoDB并不是什么灵丹妙药.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/深入浅出计算机组成原理/00 开篇词 为什么你需要学习计算机组成原理?.md.html">00 开篇词 为什么你需要学习计算机组成原理?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/01 冯·诺依曼体系结构:计算机组成的金字塔.md.html">01 冯·诺依曼体系结构:计算机组成的金字塔</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/02 给你一张知识地图,计算机组成原理应该这么学.md.html">02 给你一张知识地图,计算机组成原理应该这么学</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/03 通过你的CPU主频我们来谈谈“性能”究竟是什么.md.html">03 通过你的CPU主频我们来谈谈“性能”究竟是什么</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/04 穿越功耗墙,我们该从哪些方面提升“性能”?.md.html">04 穿越功耗墙,我们该从哪些方面提升“性能”?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/05 计算机指令:让我们试试用纸带编程.md.html">05 计算机指令:让我们试试用纸带编程</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/06 指令跳转原来if...else就是goto.md.html">06 指令跳转原来if...else就是goto</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/07 函数调用为什么会发生stack overflow.md.html">07 函数调用为什么会发生stack overflow</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/08 ELF和静态链接为什么程序无法同时在Linux和Windows下运行.md.html">08 ELF和静态链接为什么程序无法同时在Linux和Windows下运行</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/09 程序装载“640K内存”真的不够用么.md.html">09 程序装载“640K内存”真的不够用么</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/10 动态链接:程序内部的“共享单车”.md.html">10 动态链接:程序内部的“共享单车”</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?.md.html">11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/12 理解电路:从电报机到门电路,我们如何做到“千里传信”?.md.html">12 理解电路:从电报机到门电路,我们如何做到“千里传信”?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/13 加法器:如何像搭乐高一样搭电路(上)?.md.html">13 加法器:如何像搭乐高一样搭电路(上)?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/14 乘法器:如何像搭乐高一样搭电路(下)?.md.html">14 乘法器:如何像搭乐高一样搭电路(下)?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/15 浮点数和定点数怎么用有限的Bit表示尽可能多的信息.md.html">15 浮点数和定点数怎么用有限的Bit表示尽可能多的信息</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/16 浮点数和定点数(下):深入理解浮点数到底有什么用?.md.html">16 浮点数和定点数(下):深入理解浮点数到底有什么用?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/17 建立数据通路(上):指令加运算=CPU.md.html">17 建立数据通路(上):指令加运算=CPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/18 建立数据通路(中):指令加运算=CPU.md.html">18 建立数据通路(中):指令加运算=CPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/19 建立数据通路(下):指令加运算=CPU.md.html">19 建立数据通路(下):指令加运算=CPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/20 面向流水线的指令设计一心多用的现代CPU.md.html">20 面向流水线的指令设计一心多用的现代CPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/21 面向流水线的指令设计奔腾4是怎么失败的.md.html">21 面向流水线的指令设计奔腾4是怎么失败的</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/22 冒险和预测hazard是“危”也是“机”.md.html">22 冒险和预测hazard是“危”也是“机”</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/23 冒险和预测(二):流水线里的接力赛.md.html">23 冒险和预测(二):流水线里的接力赛</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/24 冒险和预测CPU里的“线程池”.md.html">24 冒险和预测CPU里的“线程池”</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/25 冒险和预测(四):今天下雨了,明天还会下雨么?.md.html">25 冒险和预测(四):今天下雨了,明天还会下雨么?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/26 Superscalar和VLIW如何让CPU的吞吐率超过1.md.html">26 Superscalar和VLIW如何让CPU的吞吐率超过1</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/27 SIMD如何加速矩阵乘法.md.html">27 SIMD如何加速矩阵乘法</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/28 异常和中断:程序出错了怎么办?.md.html">28 异常和中断:程序出错了怎么办?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/29 CISC和RISC为什么手机芯片都是ARM.md.html">29 CISC和RISC为什么手机芯片都是ARM</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/30 GPU为什么玩游戏需要使用GPU.md.html">30 GPU为什么玩游戏需要使用GPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/31 GPU为什么深度学习需要使用GPU.md.html">31 GPU为什么深度学习需要使用GPU</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/32 FPGA、ASIC和TPU计算机体系结构的黄金时代.md.html">32 FPGA、ASIC和TPU计算机体系结构的黄金时代</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/33 解读TPU设计和拆解一块ASIC芯片.md.html">33 解读TPU设计和拆解一块ASIC芯片</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/34 理解虚拟机:你在云上拿到的计算机是什么样的?.md.html">34 理解虚拟机:你在云上拿到的计算机是什么样的?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/35 存储器层次结构全景:数据存储的大金字塔长什么样?.md.html">35 存储器层次结构全景:数据存储的大金字塔长什么样?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/36 局部性原理:数据库性能跟不上,加个缓存就好了?.md.html">36 局部性原理:数据库性能跟不上,加个缓存就好了?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/37 理解CPU Cache“4毫秒”究竟值多少钱.md.html">37 理解CPU Cache“4毫秒”究竟值多少钱</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/38 高速缓存(下):你确定你的数据更新了么?.md.html">38 高速缓存(下):你确定你的数据更新了么?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/39 MESI协议如何让多核CPU的高速缓存保持一致.md.html">39 MESI协议如何让多核CPU的高速缓存保持一致</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/40 理解内存(上):虚拟内存和内存保护是什么?.md.html">40 理解内存(上):虚拟内存和内存保护是什么?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/41 理解内存解析TLB和内存保护.md.html">41 理解内存解析TLB和内存保护</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/42 总线:计算机内部的高速公路.md.html">42 总线:计算机内部的高速公路</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/43 输入输出设备我们并不是只能用灯泡显示“0”和“1”.md.html">43 输入输出设备我们并不是只能用灯泡显示“0”和“1”</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/44 理解IO_WAITIO性能到底是怎么回事儿.md.html">44 理解IO_WAITIO性能到底是怎么回事儿</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/45 机械硬盘Google早期用过的“黑科技”.md.html">45 机械硬盘Google早期用过的“黑科技”</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/46 SSD硬盘如何完成性能优化的KPI.md.html">46 SSD硬盘如何完成性能优化的KPI</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/47 SSD硬盘如何完成性能优化的KPI.md.html">47 SSD硬盘如何完成性能优化的KPI</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/48 DMA为什么Kafka这么快.md.html">48 DMA为什么Kafka这么快</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/49 数据完整性(上):硬件坏了怎么办?.md.html">49 数据完整性(上):硬件坏了怎么办?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/50 数据完整性(下):如何还原犯罪现场?.md.html">50 数据完整性(下):如何还原犯罪现场?</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/51 分布式计算:如果所有人的大脑都联网会怎样?.md.html">51 分布式计算:如果所有人的大脑都联网会怎样?</a>
</li>
<li>
<a class="current-tab" href="/专栏/深入浅出计算机组成原理/52 设计大型DMP系统MongoDB并不是什么灵丹妙药.md.html">52 设计大型DMP系统MongoDB并不是什么灵丹妙药</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/53 设计大型DMP系统SSD拯救了所有的DBA.md.html">53 设计大型DMP系统SSD拯救了所有的DBA</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/54 理解Disruptor带你体会CPU高速缓存的风驰电掣.md.html">54 理解Disruptor带你体会CPU高速缓存的风驰电掣</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/55 理解Disruptor不需要换挡和踩刹车的CPU有多快.md.html">55 理解Disruptor不需要换挡和踩刹车的CPU有多快</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/结束语 知也无涯,愿你也享受发现的乐趣.md.html">结束语 知也无涯,愿你也享受发现的乐趣</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>52 设计大型DMP系统MongoDB并不是什么灵丹妙药</h1>
<p>如果你一讲一讲跟到现在,那首先要恭喜你,马上就看到胜利的曙光了。过去的 50 多讲里,我把计算机组成原理中的各个知识点,一点一点和你拆解了。对于其中的很多知识点,我也给了相应的代码示例和实际的应用案例。</p>
<p>不过呢,相信你和我一样,觉得只了解这样一个个零散的知识点和案例还不过瘾。那么从今天开始,我们就进入应用篇。我会通过两个应用系统的案例,串联起计算机组成原理的两大块知识点,一个是我们的整个存储器系统,另一个自然是我们的 CPU 和指令系统了。</p>
<p>我们今天就先从搭建一个大型的 DMP 系统开始,利用组成原理里面学到的存储器知识,来做选型判断,从而更深入地理解计算机组成原理。</p>
<h2>DMP数据管理平台</h2>
<p>我们先来看一下什么是 DMP 系统。DMP 系统的全称叫作数据管理平台Data Management Platform目前广泛应用在互联网的广告定向Ad Targeting、个性化推荐Recommendation这些领域。</p>
<p>通常来说DMP 系统会通过处理海量的互联网访问数据以及机器学习算法,给一个用户标注上各种各样的标签。然后,在我们做个性化推荐和广告投放的时候,再利用这些这些标签,去做实际的广告排序、推荐等工作。无论是 Google 的搜索广告、淘宝里千人千面的商品信息,还是抖音里面的信息流推荐,背后都会有一个 DMP 系统。</p>
<p><img src="assets/170004db8634a3a7f9dc47c4a4d5bfef.jpg" alt="img" /></p>
<p>那么,一个 DMP 系统应该怎么搭建呢?对于外部使用 DMP 的系统或者用户来说,可以简单地把 DMP 看成是一个键 - 值对Key-Value数据库。我们的广告系统或者推荐系统可以通过一个客户端输入用户的唯一标识ID然后拿到这个用户的各种信息。</p>
<p>这些信息中有些是用户的人口属性信息Demographic比如性别、年龄有些是非常具体的行为Behavior比如用户最近看过的商品是什么用户的手机型号是什么有一些是我们通过算法系统计算出来的兴趣Interests比如用户喜欢健身、听音乐还有一些则是完全通过机器学习算法得出的用户向量给后面的推荐算法或者广告算法作为数据输入。</p>
<p>基于此,对于这个 KV 数据库,我们的期望也很清楚,那就是:<strong>低响应时间</strong>Low Response Time<strong>高可用性</strong>High Availability<strong>高并发</strong>High Concurrency<strong>海量数据</strong>Big Data同时我们需要<strong>付得起对应的成本</strong>Affordable Cost。如果用数字来衡量这些指标那么我们的期望就会具体化成下面这样。</p>
<ol>
<li>低响应时间:一般的广告系统留给整个广告投放决策的时间也就是 10ms 左右,所以对于访问 DMP 获取用户数据,预期的响应时间都在 1ms 之内。</li>
<li>高可用性DMP 常常用在广告系统里面。DMP 系统出问题往往就意味着我们整个的广告收入在不可用的时间就没了所以我们对于可用性的追求可谓是没有上限的。Google 2018 年的广告收入是 1160 亿美元,折合到每一分钟的收入是 22 万美元。即使我们做到 99.99% 的可用性,也意味着每个月我们都会损失 100 万美元。</li>
<li>高并发:还是以广告系统为例,如果每天我们需要响应 100 亿次的广告请求,那么我们每秒的并发请求数就在 100 亿 / (86400) ~= 12K 次左右,所以我们的 DMP 需要支持高并发。</li>
<li>数据量:如果我们的产品针对中国市场,那么我们需要有 10 亿个 Key对应的假设每个用户有 500 个标签,标签有对应的分数。标签和分数都用一个 4 字节Bytes的整数来表示那么一共我们需要 10 亿 x 500 x (4 + 4) Bytes = 400 TB 的数据了。</li>
<li>低成本:我们还是从广告系统的角度来考虑。广告系统的收入通常用 CPMCost Per Mille也就是千次曝光来统计。如果千次曝光的利润是 $0.10,那么每天 100 亿次的曝光就是 100 万美元的利润。这个利润听起来非常高了。但是反过来算一下你会发现DMP 每 1000 次的请求的成本不能超过 $0.10。最好只有 $0.01,甚至更低,我们才能尽可能多赚到一点广告利润。</li>
</ol>
<p>这五个因素一结合,听起来是不是就不那么简单了?不过,更复杂的还在后面呢。</p>
<p>虽然从外部看起来DMP 特别简单,就是一个 KV 数据库,但是生成这个数据库需要做的事情更多。我们下面一起来看一看。</p>
<p><img src="assets/b5d8c56d840b9e824cfbc186c19d0733.jpg" alt="img" /></p>
<p>在这个系统中,我们关心的是蓝色的数据管道、绿色的数据仓库和 KV 数据库</p>
<p>为了能够生成这个 KV 数据库,我们需要有一个在客户端或者 Web 端的数据采集模块,不断采集用户的行为,向后端的服务器发送数据。服务器端接收到数据,就要把这份数据放到一个<strong>数据管道</strong>Data Pipeline里面。数据管道的下游需要实际将数据落地到<strong>数据仓库</strong>Data Warehouse把所有的这些数据结构化地存储起来。后续我们就可以通过程序去分析这部分日志生成报表或者或者利用数据运行各种机器学习算法。</p>
<p>除了这个数据仓库之外我们还会有一个实时数据处理模块Realtime Data Processing也放在数据管道的下游。它同样会读取数据管道里面的数据去进行各种实时计算然后把需要的结果写入到 DMP 的 KV 数据库里面去。</p>
<h2>MongoDB 真的万能吗?</h2>
<p>面对这里的 KV 数据库、数据管道以及数据仓库,这三个不同的数据存储的需求,最合理的技术方案是什么呢?你可以先自己思考一下,我这里先卖个关子。</p>
<p>我共事过的不少不错的 Web 程序员,面对这个问题的时候,常常会说:“这有什么难的,用 MongoDB 就好了呀!”如果你也选择了 MongoDB那最终的结果一定是一场灾难。我为什么这么说呢</p>
<p>MongoDB 的设计听起来特别厉害,不需要预先数据 Schema访问速度很快还能够无限水平扩展。作为 KV 数据库,我们可以把 MongoDB 当作 DMP 里面的 KV 数据库除此之外MongoDB 还能水平扩展、跑 MQL我们可以把它当作数据仓库来用。至于数据管道只要我们能够不断往 MongoDB 里面插入新的数据就好了。从运维的角度来说我们只需要维护一种数据库技术栈也变得简单了。看起来MongoDB 这个选择真是相当完美!</p>
<p>但是,作为一个老程序员,第一次听到 MongoDB 这样“万能”的解决方案,我的第一反应是,“天底下哪有这样的好事”。所有的软件系统,都有它的适用场景,想通过一种解决方案适用三个差异非常大的应用场景,显然既不合理,又不现实。接下来,我们就来仔细看一下,这个“不合理”“不现实”在什么地方。</p>
<p>上面我们已经讲过 DMP 的 KV 数据库期望的应用场景和性能要求了,这里我们就来看一下<strong>数据管道</strong><strong>数据仓库</strong>的性能取舍。</p>
<p>对于数据管道来说,我们需要的是高吞吐量,它的并发量虽然和 KV 数据库差不多但是在响应时间上要求就没有那么严格了1-2 秒甚至再多几秒的延时都是可以接受的。而且,和 KV 数据库不太一样,数据管道的数据读写都是顺序读写,没有大量的随机读写的需求。</p>
<p><strong>数据仓库</strong>就更不一样了,数据仓库的数据读取的量要比管道大得多。管道的数据读取就是我们当时写入的数据,一天有 10TB 日志数据,管道只会写入 10TB。下游的数据仓库存放数据和实时数据模块读取的数据再加上个 2 倍的 10TB也就是 20TB 也就够了。</p>
<p>但是,数据仓库的数据分析任务要读取的数据量就大多了。一方面,我们可能要分析一周、一个月乃至一个季度的数据。这一次分析要读取的数据可不是 10TB而是 100TB 乃至 1PB。我们一天在数据仓库上跑的分析任务也不是 1 个,而是成千上万个,所以数据的读取量是巨大的。另一方面,我们存储在数据仓库里面的数据,也不像数据管道一样,存放几个小时、最多一天的数据,而是往往要存上 3 个月甚至是 1 年的数据。所以,我们需要的是 1PB 乃至 5PB 这样的存储空间。</p>
<p>我把 KV 数据库、数据管道和数据仓库的应用场景,总结成了一个表格,放在这里。你可以对照着看一下,想想为什么 MongoDB 在这三个应用场景都不合适。</p>
<p><img src="assets/fe9fc1ade3611ed2acf3ba3a23267f41.jpg" alt="img" /></p>
<p>在 KV 数据库的场景下,需要支持高并发。那么 MongoDB 需要把更多的数据放在内存里面,但是这样我们的存储成本就会特别高了。</p>
<p>在数据管道的场景下,我们需要的是大量的顺序读写,而 MongoDB 则是一个文档数据库系统,并没有为顺序写入和吞吐量做过优化,看起来也不太适用。</p>
<p>而在数据仓库的场景下主要的数据读取时顺序读取并且需要海量的存储。MongoDB 这样的文档式数据库也没有为海量的顺序读做过优化,仍然不是一个最佳的解决方案。而且文档数据库里总是会有很多冗余的字段的元数据,还会浪费更多的存储空间。</p>
<p>那我们该选择什么样的解决方案呢?</p>
<p>拿着我们的应用场景去找方案,其实并不难找。对于 KV 数据库,最佳的选择方案自然是使用 SSD 硬盘,选择 AeroSpike 这样的 KV 数据库。高并发的随机访问并不适合 HDD 的机械硬盘,而 400TB 的数据,如果用内存的话,成本又会显得太高。</p>
<p>对于数据管道,最佳选择自然是 Kafka。因为我们追求的是吞吐率采用了 Zero-Copy 和 DMA 机制的 Kafka 最大化了作为数据管道的吞吐率。而且,数据管道的读写都是顺序读写,所以我们也不需要对随机读写提供支持,用上 HDD 硬盘就好了。</p>
<p>到了数据仓库,存放的数据量更大了。在硬件层面使用 HDD 硬盘成了一个必选项。否则,我们的存储成本就会差上 10 倍。这么大量的数据,在存储上我们需要定义清楚 Schema使得每个字段都不需要额外存储元数据能够通过 Avro/Thrift/ProtoBuffer 这样的二进制序列化的方存储下来,或者干脆直接使用 Hive 这样明确了字段定义的数据仓库产品。很明显MongoDB 那样不限制 Schema 的数据结构,在这个情况下并不好用。</p>
<p>2012 年前后做广告系统的时候,我们也曾经尝试使用 MongoDB尽管只是用作 DMP 中的数据报表部分。事实证明即使是已经做了数据层面的汇总的报表MongoDB 都无法很好地支撑我们需要的复杂需求。最终,我们也不得不选择在整个 DMP 技术栈里面彻底废弃 MongoDB而只在 Web 应用里面用用 MongoDB。事实证明我最初的直觉是正确的并没有什么万能的解决方案。</p>
<h2>总结延伸</h2>
<p>好了,相信到这里,你应该对怎么从最基本的原理出发,来选择技术栈有些感觉了。你应该更多地从底层的存储系统的特性和原理去考虑问题。一旦能够从这个角度去考虑问题,那么你对各类新的技术项目和产品的公关稿,自然会有一定的免疫力了,而不会轻易根据商业公司的宣传来做技术选型了。</p>
<p>因为低延时、高并发、写少读多的 DMP 的 KV 数据库,最适合用 SSD 硬盘,并且采用专门的 KV 数据库是最合适的。我们可以选择之前文章里提过的 AeroSpike也可以用开源的 Cassandra 来提供服务。</p>
<p>对于数据管道,因为主要是顺序读和顺序写,所以我们不一定要选用 SSD 硬盘,而可以用 HDD 硬盘。不过,对于最大化吞吐量的需求,使用 zero-copy 和 DMA 是必不可少的,所以现在的数据管道的标准解决方案就是 Kafka 了。</p>
<p>对于数据仓库,我们通常是一次写入、多次读取。并且,由于存储的数据量很大,我们还要考虑成本问题。于是,一方面,我们会用 HDD 硬盘而不是 SSD 硬盘;另一方面,我们往往会预先给数据规定好 Schema使得单条数据的序列化不需要像存 JSON 或者 MongoDB 的 BSON 那样,存储冗余的字段名称这样的元数据。所以,最常用的解决方案是,用 Hadoop 这样的集群,采用 Hive 这样的数据仓库系统,或者采用 Avro/Thrift/ProtoBuffer 这样的二进制序列化方案。</p>
<p>在大型的 DMP 系统设计当中,我们需要根据各个应用场景面临的实际情况,选择不同的硬件和软件的组合,来作为整个系统中的不同组件。</p>
<h2>推荐阅读</h2>
<p>如果通过这一讲的内容,能让你对大型数据系统的设计有了兴趣,那就再好不过了。我推荐你去读一读<a href="https://book.douban.com/subject/30329536/">《数据密集型应用系统设计》</a>这本书,深入了解一下,设计数据系统需要关注的各个核心要点。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/深入浅出计算机组成原理/51 分布式计算:如果所有人的大脑都联网会怎样?.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/深入浅出计算机组成原理/53 设计大型DMP系统SSD拯救了所有的DBA.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997afb0fce3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>