高并发的哲学原理(十)-- 理论无限容量:站在地球表面

news2025/2/4 23:51:03

前面两篇文章每一篇都花了我五十个小时以上,写的我是欲仙欲死,本文我们来务点虚,上上价值。

我们将从微服务架构讲起,一步一步追根溯源,找寻“分布式数据库”在另一个维度的投影,探寻基建、应用、服务、组织之间的联系,通过观察自然规律和人类社会,引出本文的中心思想,并对“找出单点,进行拆分”做出最后的升华。

最后,我们将得到一个可行的 100 万 API QPS、500 万数据库 QPS 的系统设计方案,并顺便简单地讨论一下“高可用”背后的哲学悖论。

如何定义“一个系统”

前面第七篇文章我们说过:

如果两个系统的数据库不在一起,那他们就不是一个系统,就像拼多多有 7.5 亿月活用户,淘宝有 8.5 亿,你不能说“拼宝宝”电商系统有 16 亿月活用户一样。

如果两个 API 的数据落到同一张表上,那他们两个就属于同一个系统。

那,在一个电商系统内,用户 API 和商品 API 似乎没有多对多交集?是的,这就是微服务架构的拆分逻辑。

微服务架构

我们都知道,微服务的拆分方式,反映的是其背后技术团队的组织方式。(你不知道也没关系,你现在知道了( ̄▽ ̄)" )

那,技术团队的组织方式是什么决定的呢?

是由系统内各部分天然的内聚性决定的:用户相关的业务和商品相关的业务都有很强的内聚性,他们之间不会主动发生关联,但他们会分别和订单发生关联。

数据库调用推演

我们用商品下单处理流程来推演一个电商订单的生命周期内对用户、商品、订单三个部分数据库的读写情况。

  1. 搜索:商品数据库-读
  2. 点进详情:商品数据库-读,用户数据库-读(地址、会员)
  3. 立即购买:商品数据库-读,用户数据库-读,订单数据库-写
  4. 支付:订单数据库-读写,用户数据库-读
  5. 商家后台查看并处理订单:订单数据库-读写,用户数据库-读,商品数据库-读

我们可以看出,大部分情况下,每一步都只有一个主要的微服务被需要,其它微服务都处于辅助地位:只读,且大部分都是单点读取。这就为我们降低了数据库单点的负载——只要把这三个微服务部署到三个独立的数据库上,就可以通过 API 调用的形式降低单个数据库的极限 QPS。

微服务背后的哲学

既然我们不能把拼多多和淘宝的系统称作一个系统,那么,在拼多多和淘宝系统内,肯定还可以基于类似的逻辑继续拆分:

  1. 在大量调用的 API 中,一次携带了数据写入的请求一定只会对单个微服务进行写入,但会对多个微服务进行数据读取
  2. 如果某个头部 API 请求会对两个微服务系统进行写入,那说明微服务的划分出了问题,需要调整系统结构划分

把几乎不相互写入的数据拆到两个数据库上,这种组织形态在人类社会随处可见:两个国家的人分别在自己国家申请护照,他们有时也可以到对方国家内的本国领事馆申领本国护照;两个村的人各自在本村的井里打水,有时也可以不怕麻烦地去隔壁村的水井里打水;你每天早上都用滴滴打车上班,万一滴滴打不到车你还可以用高德来补救...

微服务照进现实

微服务的拆分思想相信大家都理解了,下面我们来解决现实问题。

如果你真的成为了“设计百万 QPS 系统”的架构师,相信我,你第一个想到的,一定是“削峰”。

削峰

顾名思义,将突发的流量高峰削平。大促的时候,系统顶不住,其实就是那么一会儿顶不住,只要初期的高热度下去了,系统的整体负载会迅速下降到没那么危险的水平。所以,对付突发流量,削峰是第一要务。

1. 缓存——饮鸩止渴

请原谅我用饮鸩止渴这个词形容 95% 的 web 系统的真正性能顶梁柱,实际上缓存的贡献远不止于此。

  1. 缓存以降低数据更新频率为代价,极大地提升了读取 API 的 QPS 极限
  2. 缓存可以设计成多级,形成一个逻辑上的“存储器山”
  3. 缓存可以像事务隔离级别一样划分成好几种 性能+数据一致性 级别

但是,使用缓存确实是在饮鸩止渴:缓存在带来性能的同时,大幅削弱了数据库提供的“单点性”,为系统失效埋下了一堆地雷。

缓存的毒性无法消除,一旦系统的某些部分失效,这杯毒酒就会发作,但是会不会把自己毒死还要看架构水平和基建能力:你的机房别随便断电,你的服务器别随便宕机,你在喝下缓存毒酒之后,就能活的够长。

终极缓存方案

我们上一篇文章讨论的 OceanBase 就采用了一种终极缓存方案:

  1. 内存不是快吗,那我就把所有热数据全部放到内存里
  2. 那对热数据的修改怎么办?redo log 落盘啊
  3. 你说数据库重启怎么办?上冗余,一个节点一时半会儿起不来也没问题
  4. 整个集群重启呢?都天灾了,集群重启后,停止服务一个小时还是可以接受的吧

12306 每天夜里都要维护一个小时,我有理由怀疑,它在将 redo log 落盘¹ :-D

2. 队列——欢迎来到地球

缓存可以削读的峰,队列就是拿来削写的峰的。

队列的思想其实早就贯穿在人类社会的每一个角落了:超市结账需要排队,做核酸需要排队,火车站打车需要排队,网上抢购商品也需要排队。排队的本质是将一拥而上购买变成了“异步”购买:你想买东西?先排队,过段时间轮到你了,看看商品有没有卖完,没卖完你就能买到。

排队的思维特别好理解,而现实中防止超售功能也确实是基于排队功能做的。传统数据库的事务隔离属于强迫用户等待,而现在大多使用队列系统来处理排队,排队这件事情才真正异步起来了。

3. 奇技淫巧

电商下单在普通压力下,一个队列就能解决问题,但是当你面临每秒几十万单的时候,如何让这些订单真正地下单成功,才是最需要解决的问题,这个数字就是“系统容量”。队列是无法提升系统的绝对容量的,那该怎么办呢?

继续找东西和信息之神交换:过去的时间换现在的时间。

在大促之前,先把订单生成好,然后用户下单时直接写入用户信息:不需要执行“检查库存”这个单点操作了,负载低了很多。

骚,实在是骚。

现实世界中的削峰

现实世界中,一个一百万 QPS 的电商系统,真正需要触达到数据的 QPS 其实是没有 500 万那么多的,在削峰的操作下,200 万 QPS 的 PolarDB 集群在 Redis 集群的配合下,是可以顶住 100 万 API QPS 的。史上流量最大的那一年双 11,每秒订单创建最大值仅为 58.3 万笔,这已经是这个地球上的最高记录了。

但是,现实世界中,一切都要讲 ROI(收益成本之比),搞一个顶配的 PolarDB 集群确实可以顶住巅峰时期一百万 API QPS,但是你老板看着账单肯定会肉痛,那,该如何省钱呢?

答:站在地球表面

站在地球表面

alt
一望无际的华北平原

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

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

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

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

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

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

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

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

  1. 可以预分配 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 下面所有行的数据。

Clickhouse 对多 CPU 的利用能力非常惊人

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

放弃内存缓存

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

太暴力了,我喜欢。

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

理论无限容量

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

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

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

当你的系统顶不住的时候,按照这个原理来拆就行了,绝对顶得住。别说区区一百万 QPS 了,服务全人类也做得到。

alt

价值上完了,我们最后再讨论五毛钱的高可用。

番外篇:高可用

我相信,很多人都像我一样做过思想实验,希望设计一个“完全高可用”的系统,但是最终可能都败下阵来,为什么?因为高可用和其它常见的分布式系统需求是互斥的。

数据重要如银行,也只是要求在天灾面前要尽量不丢数据、少丢数据,凭什么你就要求自己的系统永远可用呢?其实,想从架构层面实现高可用是非常困难的,终极高可用就是将数据完整地复制到世界各地的所有节点上,并用超长的时间来达到完全一致,这是什么,这是区块链呀。

高可用和性能、一致性都是冲突的,只能采用策略尽量压制问题。

熔断

这个词在技术圈的流行应该有微博一半功劳,压力一大就熔断:主动停止不重要的服务,断尾自救,争取让核心业务不挂。

限流

限制一部分地区、一部分用户的访问,以保护整个集群不崩,一般用于限制单个用户对系统造成的压力过大,对面很可能是机器人。

Facebook 2021年 10 月 4 号宕机²

Facebook 的用户不可谓不多,对高可用的投入不可谓不足,为什么还是会整个公司完全宕机 7 小时呢?

事故的起因是一个错误的命令意外断开了 Facebook 的 DNS 服务,结果问题大了:

  1. 所有客户端 API 失效,用户无法获得任何信息
  2. 数据中心 VPN 服务失效,无法远程登录到数据中心内的设备上
  3. 亲自去机房,发现门禁卡刷不开门,破拆后才接触到物理设备,插上显示器和键盘才能解决问题
  4. 邮件、Google 文档、Zoom 都登不上
  5. 办公大楼的门禁卡系统也失效了,无法刷开会议室的门,甚至无法离开办公楼

结合阿里云香港一个数据中心因为空调故障导致整个数据中心宕机超过 24 小时³,认命吧,商业机构做不了真正的高可用的:资源使用率就是钱呐。

参考资料

  1. 《12306互联网售票系统的架构优化及演进》 http://tljsjyy.xml-journal.net/article/id/3756
  2. 2021 年 Facebook 宕机事件 https://zh.wikipedia.org/wiki/2021%E5%B9%B4Facebook%E7%95%B6%E6%A9%9F%E4%BA%8B%E4%BB%B6
  3. 关于阿里云香港Region可用区C服务中断事件的说明 https://help.aliyun.com/noticelist/articleid/1061819219.html

出自:https://github.com/johnlui/PPHC

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java:运算符、位运算 的运算规则与用法详解

目录 运算符Math数学函数与常量类型转换强制类型转换自增和自减运算符关系运算符三元运算符 位运算& 与| 或^ 异或~ 按位取反<< >> 左移 右移运算符优先级 运算符 Math数学函数与常量 import java.lang.Math.*; public class Test{public static void main(S…

java项目之智能仓储系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的智能仓储系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&…

十八、网页端在移动端的像素

一、简介 -1. 在不同的屏幕&#xff0c;单位像素的大小是不同的&#xff0c;像素越小&#xff0c;屏幕越清晰。 手机端的像素就是宽度和高度&#xff0c;如iphone6 4.7寸 750 x 1334。 -2. 手机的像素点 远远小于 计算机的像素点。 问题&#xff1a;一个宽度为900px的网页在i…

探索AI图像安全,助力可信AI发展

探索AI图像安全&#xff0c;助力可信AI发展 0. 前言1. 人工智能发展与安全挑战1.1 人工智能及其发展1.2 人工智能安全挑战 2. WAIC 2023 多模态基础大模型的可信 AI2.1 WAIC 2023 专题论坛2.2 走进合合信息 3. AI 图像安全3.1 图像篡改检测3.2 生成式图像鉴别3.3 OCR 对抗攻击技…

这所211保护一志愿,但复试太难了,考八门课!

一、学校及专业介绍 华中师范大学&#xff08;Central China Normal University&#xff09;&#xff0c;简称“华中师大”&#xff0c;位于湖北省武汉市&#xff0c;是中华人民共和国教育部直属重点综合性师范大学&#xff0c;位列国家“双一流”、“211工程”、“985工程优势…

C++ 在线刷题网站

文章目录 1. 前言2. 效果展示3. 框架4. common4.1 工具类4.2 日志 5. 编译5.1 前言5.2 正文5.3 PathUtil5.4 Compile 6. 运行6.1 限制进程资源6.2 Run 7. 执行7.1 json7.2 Start 参数7.3 FileUtil7.4 Start 8. 启动服务8.1 安装 httplib8.2 compile_server.cpp 9. 测试 compile…

前端学习记录~2023.7.15~CSS杂记 Day7

前言一、介绍 CSS 布局1、正常布局流2、display 属性3、弹性盒子&#xff08;1&#xff09;设置 display&#xff1a;flex&#xff08;2&#xff09;设置 flex 属性 4、Grid 布局&#xff08;1&#xff09;设置 display&#xff1a;grid&#xff08;2&#xff09;在网格内放置元…

吴恩达教授深度学习--神经风格转换算法

什么是神经风格迁移&#xff1f; 假设你有一张内容图片C&#xff08;Content&#xff09;和一张具有独特风格S&#xff08;Style&#xff09;的图片&#xff0c;神经风格迁移可以让这两张图片结合&#xff0c;让原始图片具有图片S的风格。所以神经风格迁移可以解决的问题是&am…

Kafka 入门到起飞系列 - 磁盘存储 -零拷贝

Redis 是 在内存存储数据的&#xff0c;数据读取时不要经过磁盘的IO&#xff0c;只需要内存的操作&#xff0c;这也是redis访问速度快的原因 Kafka背道而驰&#xff0c;Kafka 是在磁盘存储数据的&#xff0c;发送过来的数据交给Kafka后会落盘&#xff0c;消费者读取数据时&…

【C++11】function包装器和bind包装器的简单使用

function function 包装器一些场景下模板的低效性包装器 function 修复问题包装成员函数的注意事项一道例题function包装器的意义 bind 包装器bind 包装器介绍bind 包装器可调整传参顺序bind 包装器可绑定固定参数bind 包装器的意义 C11提供了多个包装器&#xff08;wrapper,也…

BYOVD!干掉EDR/XDR/AVs进程工具

工具介绍 利用gmer驱动程序有效地禁止使用或杀死EDR和AV&#xff0c;它可以流畅地绕过HVCI&#xff1b;该样本来自 loldrivers&#xff1a;https://www.loldrivers.io/drivers/7ce8fb06-46eb-4f4f-90d5-5518a6561f15/ 关注【Hack分享吧】公众号&#xff0c;回复关键字【230614…

docker安装mariadb,并在宿主机连接docker中启动的mariadb

这篇文章主要介绍怎么在docker中安装一个mariadb数据库&#xff0c;然后在我们的电脑本机上连接虚拟机上docker运行的mariadb数据库。 首先&#xff0c;需要安装一个虚拟机软件&#xff0c;通过虚拟机软件安装一个linux操作系统&#xff0c;本篇文章安装的是ubuntu&#xff0c…

一、基础-3、MySQL卸载

1.、停止MySQL服务 winR 打开运行&#xff0c;输入 services.msc 点击 "确定" 调出系统服务。 2. 卸载MySQL相关组件 打开控制面板 ---> 卸载程序 ---> 卸载MySQL相关所有组件。 3. 删除MySQL安装目录 4. 删除MySQL数据目录 数据存放目录是在 C:\ProgramDat…

No.185# 技术管理框架知识点随记

引言 陆续参加了公司组织的两场关于技术管理的培训&#xff0c;时间一长也快忘的七七八八了。本文以刘建国《执行技术人管理之路》为基础框架&#xff0c;将知识点做了整理&#xff0c;在需要的时候翻翻。本文主要内容有&#xff1a; 技术管理之角色认知技术管理之管理规划技术…

【技能实训】DMS数据挖掘项目-Day11

文章目录 任务12【任务12.1】创建用户信息表【任务12.2】在com.qst.dms.entity下创建用户实体类User&#xff0c;以便封装用户数据【任务12.3】在com.qst.dms.service下创建用户业务类UserService【任务12.4】在项目根目录下创建图片文件夹images&#xff0c;存储dms.png【任务…

了解数据科学中的异常检测

大家好&#xff0c;本文将简要介绍一下异常检测&#xff0c;并指导通过不同的技术来识别异常。 如果你正在处理数据&#xff0c;那么无论是现在还是将来&#xff0c;都可能会遇到一项非常重要的任务 —— 异常检测。它在许多领域中都有很大的应用&#xff0c;如制造业、金融和…

visual studio 2017直接打开文件夹时,选择当前项目或者整个解决方案时,按快捷键查找时显示未找到以下指定文本

有的时候只想要打开一整个文件夹来看里面的代码&#xff0c;平时一般用Qt&#xff0c;但是感觉在打开整个文件夹看代码方面&#xff0c;Qt没有VS方便&#xff0c;于是选择了VS&#xff0c;安装的是VS2017&#xff0c;然后发现有个问题&#xff0c;CtrlF查找时&#xff0c;如果选…

报错:Invalid bound statement (not found): com.web.sysmgr.mapper.UserMapper.login

报错&#xff1a;Invalid bound statement (not found): com.web.sysmgr.mapper.UserMapper.login 原因&#xff1a; 确认是否在扫描Mapper接口时指定了正确的包路径。检查 MapperScan 注解中的包路径是否正确&#xff0c;确保只扫描到需要的Mapper接口。 如果在配置类中去配置…

JQuery 实现点击按钮添加 input 框

前言 用于记录开发中常用到的&#xff0c;快捷开发 需求 比如说&#xff0c;我台设备可以设置一个或多个秘钥&#xff0c;有时候我配置一个秘钥时&#xff0c;就不需要多个输入框&#xff0c;当我想配置多个秘钥时&#xff0c;就需要添加多个输入框。 实现 HTML <div…

Hadoop 之 HDFS 伪集群模式配置与使用(二)

HDFS 配置与使用 一.HDFS配置二.HDFS Shell1.默认配置说明2.shell 命令 三.Java 读写 HDFS1.Java 工程配置2.测试 一.HDFS配置 ## 基于上一篇文章进入 HADOOP_HOME 目录 cd $HADOOP_HOME/etc/hadoop ## 修改文件权限 chown -R root:root /usr/local/hadoop/hadoop-3.3.6/* ## …