logo

站在地球表面

图 12-1 一望无际的华北平原

如图 12-1 所示就是地球表面的代表——一望无际的华北平原。

北京位于美丽的华北平原北端,生活着两千多万人,在巅峰的 2020 年双 11,天猫平台北京地区销售额为 216 亿,全国总额为 4982 亿,占比为 4.33%,略高于北京占全国 3.44% 的 GDP 比例,数据比较可信。使用这些数字我们可以计算得出,北京的两千多万人,给天猫贡献了583000 * 0.0433 = 25243.9笔/秒的并发。

虽然全国订单数看起来十分惊人,但是北京这一个地方的压力却只有 2.5 万单每秒,这个哪怕不用奇技淫巧,纯靠数据库硬抗,十万数据库 QPS 只用主从架构可能都能抗住。但是,系统能基于地理位置划分吗?系统不是必须全国一盘棋吗?不是的,可以划分。

下面我们讨论一下怎么划分。

基于地理位置对应用和数据库分区

为什么非要全国的用户访问同一个数据库呢?我们可以利用微服务思想对业务系统和数据进行拆分:北京的用户和上海的用户,理论上讲都可以只访问“本地天猫”。

接下来我们分析一下,在一个标准的电商业务中,哪些地方会让一个北京的用户和一个上海的用户发生联系。

  1. 用户表自增 ID
  2. 商品库存检查
  3. 商家订单聚合
  4. 离线数据分析

实际上,地理上被隔开的两个人,在系统内还真没什么机会需要相互查询对方的数据,这就是我们能基于地理位置对应用和数据库进行分区的现实原因。下面我们一一拆除这几个单点:

  1. 用户表自增 ID:可以预分配 ID 段,也可以用算法保证,例如一奇一偶。
  2. 商品库存检查:预分配库存,再异步刷新缓存。这个部分能玩出花,甚至有在客户端上提前下发抢购结果的骚操作,大家可以自己探索。
  3. 商家订单聚合:简单地从两个地方各拉一次即可。
  4. 离线数据分析:更不用说了,都离线了,本身也是要做很多数据同步和聚合的,不差这一点。

基于地理位置对应用和数据库进行划分,产生出两个“本地天猫”后,就需要我们老朋友 DNS 出来表演了。

进击的 DNS

域名当初可能是为了方便记忆而发明的,但是域名背后的 DNS 服务却几乎是最重要的互联网高并发基础设施:不同地区的人,对同一个域名进行访问,可以获得两个公网 ip,这样“本地天猫”就实现了。

类 DNS 哲学思想:Consul 和 Kong

DNS 几乎完全放弃了一致性,但却实现了极高的可用性和分区容错性。其实,gossip 协议也是这个思想:让消息像病毒一样传播,能够实现最终一致性就行了,要啥自行车。

异曲同工的 Kong 集群的设计思想也十分令人震惊:所有节点每 5 秒从数据库读取最新的配置文件,然后,这些节点就成了一个行为完全一致的集群啦。“想那么多干什么,短时间内多个节点的行为不一致,就让它们不一致好了,5 秒之后不就一致了。”

高性能计算第一原则

高性能计算第一原则:数据离 CPU 越近,性能越高,容量越小

在我们熟悉的存储器山中,这是一个大家都理解的基本特性,而这个特性引申到分布式系统中,就是:一定不能让应用和数据库分离。

和 InnoDB 一样,很多时候其实是“局部性”这个我们宇宙的基本属性在帮助我们提升系统的性能,让应用和数据库分布在同一个地域,也是在利用局部性获得性能增益。

所以,让应用去隔壁区域的数据库读数据是要极力避免的——我们应该用 API 网关直接把请求发给隔壁区域的应用服务器,这显然是在今天这个异地网络传输速度接近光速的时代最佳的选择。

向 Clickhouse 学习高并发

Clickhouse 在亿级数据量面前丝毫不怵:MySQL、MongoDB、Hadoop,谁也没有老子快。为什么 Clickhouse 这么快呢?

列式存储

首先,它将数据以列为单位组织起来,压缩后存入磁盘上一个又一个的 block,这些 block 就像 InnoDB 的 16KB 页一样,只是它更大(64KB~1MB)。这样,当我们 select 某个 column 的时候,Clickhouse 就能顺序读出磁盘上这个 column 下面所有行的数据。

高效压缩

由于同一列通常具有高度的数据相似性,所以列式压缩的效果在大部分情况下都非常好,这也能算作“局部性”在数据库层面的一种应用。

充分利用多 CPU 并行计算

除了列存储之外,每个 block 内,Clickhouse 还用“稀疏索引”的方式,将每一列的数据划分为了多个 granularity(颗粒度),然后给每个 granularity 分配一个 CPU 核心进行并行计算,并且它还利用 SSE4.2 指令集,利用 CPU 的 SIMD(Single Instruction Multiple Data)指令,在 CPU 寄存器层面进行并行操作。

放弃内存缓存

这是 Clickhouse 整个架构中笔者最喜欢的部分。我们通过前面的章节可以看出,所有的分布式数据库,其本质都是在搞“内存缓存的数据同步”,Clickhouse 直接掀桌子——老子不要内存缓存了。由于所有数据都在磁盘上,而节点的 CPU 又直接和磁盘数据打交道,所以 Clickhouse 实现了真正的并行:增加 CPU 核心数就能提升系统容量,无论在不在同一台机器上都行,反正 CPU 相互之间完全不需要通信。这样,Clickhouse 通过堆核心数就能够实现系统容量的“近线性扩展”。

太暴力了,我喜欢

我们可以学习这种思想,打造一个可以线性扩展的系统架构:只要不同地区的本地系统之间完全没有“数据实时同步”需求,那其实它们就是两个系统,就可以实现线性的性能提升。

理论无限容量

我们说过,关系型数据库的关系,指的就是两行数据之间的关系。现实世界中,位于异地甚至是异国的两个人之间,几乎是不会发生实时相互数据读取的。

站在地球表面来思考,你会发现人类社会和自然规律都是契合高并发“找出单点,进行拆分”哲学原理的:每一个人类居所,本质上都是散落在整个地球上的一个又一个点。因为这些点的存在,我们发明了国省市县乡村逐级政府,同级政府之间几乎没有相互通信。

将一个大系统拆成不需要实时相互通信的多个小系统,可以获得线性的性能提升。

当你的系统顶不住的时候,按照这个原理来拆就行了,绝对顶得住。别说区区一百万 QPS 了,服务全人类也做得到,毕竟全球 80 亿人都生活在如图 12-2 所示的球体上嘛,这个球体的半径也只有六千多公里,不算是很大的一个球。

图 12-2 我们的地球

价值上完了,我们最后再讨论一下高可用。

阅读数:4215      字数:2321 最后更新:2023-11-08 10:52:17