# 高并发的哲学原理（一）-- 找出单点，进行拆分

### 人列计算机

《三体》中，刘慈欣设计了一个用人进行二进制运算的计算机，使用了三千万名士兵(晶体管)：

![](https://qn.lvwenhan.com/2023-01-27-16747559623736.jpg)

* 计算机名：秦一号
* CPU：秦始皇最精锐的五个军团
    1. 挥舞旗帜进行二进制运算
    2. 用三个士兵来组成与门、或门、与非门、或非门、异或门、同或门和三态门，又用两个士兵组成了非门
    3. 将这些基本部件组合起来，构成了计算阵
* 内存：由文化程度较高的人组成，每个人挥舞多个颜色的旗帜，可以替代 20 个挥舞单色旗帜的人
* 硬盘：三百万文化程度较高的人（据说是上次坑儒留下来的）
* 显示阵列：至少配有红色和绿色像素单元（双色显示阵列）
* 维护部件：一组骑兵
    1. 传输信号
    2. 处理“故障”士兵
    3. 由秦始皇最精锐的骑兵团构成
* 维护方式：更换出错部件

#### 一提到高并发，很多人的第一反应都可以归纳为以下两种情况：

#### 1. 进程间通信(IPC)、共享内存、管道、队列、事件：这是学院派
#### 2. 内存缓存、消息队列、分库分表、NoSQL、ES 搜索：这是实战派

其实，高并发之路，无论是学院派还是实战派，甚至是刘慈欣设计的人列计算机，其背后的哲学原理都是一样的。如果你问人列计算机和高并发有什么关系？按照上面的设计，最多一万名士兵就够了，为什么需要三千万呢？还不是为了提高性能。

其实，高并发的哲学原理早就隐藏在了现代计算机的基础结构之中，感兴趣的欢迎去看我的《性能之殇（二）-- 分支预测、流水线与多核 CPU》¹。

## 本文目标

上面只是我的喃喃私语，下面我们进入正题。

本文的目标是在我有限的认知范围内，讨论一下高并发问题背后隐藏的一个哲学原理。我们将从动静分离讲起，一步步深入 Apache、Nginx、epoll、虚拟机、k8s、异步非阻塞、协程、应用网关、L4/L7 负载均衡器、路由器(网关)、交换机、LVS、软件定义网络(SDN)、Keepalived、DPDK、ECMP、全冗余架构、用户态网卡、集中式存储、分布式存储、PCI-E 5.0、全村的希望 CXL、InnoDB 三级索引、内存缓存、KV 数据库、列存储、内存数据库、Shared-Nothing、计算存储分离、Paxos、微服务架构、削峰、基于地理位置拆分、高可用等等等等。并最终基于地球和人类社会的基本属性，设计出可以服务地球全体人类的高并发架构。

先说结论，这个哲学原理就是：`找出单点，进行拆分`。

## 准备工作

### 性能问题要靠架构解决

在展开这个哲学原理前，我们需要先明确一下高并发问题的解决思路：性能问题要靠架构解决。

首先，在架构上动刀是最简单的，也是最容易获得收益的。其次，即便是真的去做单个资源的性能优化，例如 MySQL 单机性能优化(软件优化)、x86 CPU 多核性能提升(硬件优化)，拆到微观来看，也是在做架构优化：

`没有银弹`就是计算机世界的第一准则，你想获得收益，总得拿出一些东西，和`信息之神`交换。

### 我们讨论“哪个”高并发？

本文讨论的是“web 服务高并发”问题，典型场景为电商秒杀：同一个时刻，数万人抢同一个低价商品，会给系统的每一个层面都造成显著的性能瓶颈，这种场景的集大成者，就是每年的双 11。

## 一个小目标

`找出单点，进行拆分`，就是将每一个大单点都拆成一个小单点+多资源并行的形式。

在解决高并发问题的过程中，我们会不断地遇到新的单点：web server、单个操作系统、虚拟化/容器技术、编程语言运行架构、网络、UNIX 进程模型、数据库等。每遇到一个单点，我们都要见招拆招，使用`架构`工具拆掉它。计算机的虚拟化程度非常高，几乎每个单点都可以继续往下拆。

接下来大家就跟着我一起，一步一步将系统性能的上限从单机 100 QPS 提升到 1,000,000（一百万）QPS。

### 文章列表

1. 找出单点，进行拆分（本文）
2. Apache 的性能瓶颈与 Nginx 的性能优势
3. 基础设施并发：虚拟机与 Kubernetes（k8s）
4. 隐藏在语言背后的魔鬼：运行架构为何会成为性能瓶颈
5. 拆分网络单点(上)：应用网关、负载均衡和路由器(网关)
6. 拆分网络单点(下)：SDN 如何替代百万人民币的负载均衡硬件(网关、LVS、交换机)
7. 最难以解决的单点：数据库以及它背后的存储
8. 将 InnoDB 剥的一丝不挂：B+ 树与 Buffer Pool
9. 细数四代分布式数据库并拆解 TiDB 和 OceanBase（主从、中间件、KV、计算与存储分离、列存储、CAP定理）
10. 理论无限容量：站在地球表面

## 找出第一个单点

大部分系统都是从单个虚拟机开始的，原始的资源可能只有 1 核 2G，你安装了一个 Apache，一个 MySQL，把代码部署上去，这个系统就开始对外服务了。如果系统用户数量增加了，你会发现，CPU 满了，这个时候，我们第一个应该拆的就是静态流量。

### 动静分离

大概是在 2013 年，我用从同学那里买的二手 MacBook Pro 跑过 Apache 和 Nginx 的性能测试，在本机访问同一张 jpg 图片的情况下，Apache 的 QPS 为 2 万出头，而 Nginx 则超过 8 万，四倍性能。

所以，如果你还在用 Apache 承载所有流量，在前面加一个 Nginx 就能显著降低 CPU 占用率，大幅提升系统性能。如果你再利用云服务商把这些静态资源用 CDN 来承载，你的静态资源压力还能再降低 90%。

动静分离以后，CPU 又满了，该怎么办呢？这个时候就需要把数据库拆出去了。

### 最适合独立部署的软件：数据库

如果应用代码和数据库跑在一个系统上，压力稍微大一点，很容易出现“债股双杀”的局面：MySQL 的响应变慢，应用代码就需要更长时间的等待，又要消耗更多的 CPU 资源，从而形成“内卷”和“踩踏”。只要你的系统不是用户极其少，或者你们公司极其抠，把数据库独立部署的收益都是要高于投入的：1 核 2G 的虚拟机就够 MySQL 跑到 200 QPS了，配合缓存支撑一个日 PV 100 万的小系统应该够了。

### 我的实际经验

#### 进击的爬虫

2017 年，我维护的一个 SEO 网站突然遭遇大量爬虫的袭击：由于这个网站拥有数百万个内容页面，页面内也有着大量的“类似文章推荐”，在只依靠 MySQL `like`语句的情况下，单个页面的返回时间长达 300-500ms。一天两万的真实用户 UV 对系统的压力并不大，但这些爬虫不讲武德，上来就是 100 QPS，当时 1 核 2G 的虚拟机和 1 核 1G 的 MySQL 可遭了殃了，完全顶不住。

这些爬虫并不是正规大厂的爬虫，而是采集机器人，由于拥有海量代理 ip，对网站形成了 DDOS 态势，没法使用常规手段封禁，只能想办法抗住。

我首先做的，就是将静态资源全部 CDN 化，直接让 CPU 占用率降低了一半。然后就开始着手提升系统性能：

1. 使用 ElasticSearch 提供“类似文章推荐”，将每个页面的响应时间压缩到了 200ms
2. 提升数据库性能：增加索引，增加 Redis 缓存，使用定时任务刷新文章总数而不是实时计算，将响应时间压缩到了 120ms
3. 访问 ES 的 HTTP 请求进行并行化：虽然 PHP 是一种阻塞语言，但是一次性发送多个 HTTP 请求的能力还是有的，平均每个页面有五次请求，每次 15ms，并行化以后从 15ms*5 减少到了 25ms，最终将平均响应时间压缩到了 70ms

同时，服务器和数据库也进行了计算资源的扩容，增加到了 2 核 4G 的虚拟机和 2 核 4G 的 MySQL，最终顶住了每天 200 万次页面访问的冲击，对比之下，真实用户 PV 每天只有十万左右。

这个时候可能有人会问了，既然是内容网站，为什么不静态化呢？因为数据量太大了，500 万个页面，一个页面 100KB，就是 476GB 的磁盘容量，这个量级太夸张了，不如做性能优化硬抗了，这么多静态资源的管理和刷新反而是个更大的问题。在百万量级下，数据库绝对是更好的数据存储解决方案，远比自己管理文件要更简单更稳定。

即便我做了那么多，还是不乏有一些爬虫愣头青在学习了 swoole 和 go 协程之后，对我的网站发动数千 QPS 的死亡冲锋，这个时候再怎么性能优化都是没用的，这时就需要使用倒数第二个工具：限流。

我做了三道限流关卡才最终顶住采集机器人 DDOS：

1.  针对单个 ip 做请求频率限制
2.  针对整个 /24 ip 段做请求频率限制（很多爬虫采用同一段内的多个 ip 绕过限流）
3.  针对每个 UA 做请求频率限制

在这三板斧使出来以后，天下太平了，网站再也没有被突然发起的死亡冲锋搞挂过。

对了，既然限流是倒数第二个工具，肯定有人好奇最后一个工具是什么？那就是熔断，熔断属于系统鲁棒性工具，是善后用的，我们最后一篇文章还会再提一嘴。

### 接下来

下一篇文章，我们将看到真实的 Apache 性能瓶颈与 Nginx 的性能优势，同时我会继续现身说法，讲述团购秒杀业务的故事。

> [高并发的哲学原理（二）-- Apache 的性能瓶颈与 Nginx 的性能优势](https://github.com/johnlui/PPHC/tree/main/02.%20Apache%20%E7%9A%84%E6%80%A7%E8%83%BD%E7%93%B6%E9%A2%88%E4%B8%8E%20Nginx%20%E7%9A%84%E6%80%A7%E8%83%BD%E4%BC%98%E5%8A%BF)

### 参考资料

1. 性能之殇（二）-- 分支预测、流水线与多核 CPU  https://lvwenhan.com/tech-epic/493.html


