笔者在工作中曾经成功地用 Nginx 改造了一个高并发的电商秒杀系统,保证了业务的正常开展,下面是笔者的真实故事。
在新冠疫情初期,住范儿的私域电商业务迅速发展。尽管 3 月中旬才复工,3 月份半个月的 GMV 就超过了前一年的总和,并在 4 月就完成了全年目标。然而,这也导致电商系统的性能压力急剧增加。
当时,我们的电商系统和第一版淘宝一样是购买的一个 PHP 单体系统,天生不具备扩展性。再加上我们采用团购秒杀的业务模式,这给系统带来了巨大的挑战。客户端主要使用微信小程序,而服务端则提供两种主要服务:开团瞬间的海量 HTTP API 请求以及每个页面都非常消耗资源的订单管理后台。
笔者面临的第一个问题是数据库无法承受如此巨大的压力。经过分析,笔者发现请求数最高的接口是商品详情,于是为该接口增加了一层保持时长为一分钟的 Redis 缓存,这个动作显著降低了开团瞬间的数据库压力。
而且幸运的是,当时阿里云刚刚商用 PolarDB 几个月。笔者利用 PolarDB 成功应对了开团三分钟内涌入的大约 4000 名用户带来的巨大的数据库压力。然而,当笔者将后端云主机升级到 16 核 32G 内存时,出现了一个非常奇怪的现象:
为什么会出现这种现象呢?原因是新用户无法与服务器建立 TCP 连接!
默认情况下,CentOS 7.9 单个进程的最大文件打开数(ulimit)为 1024。由于一切皆文件,每个 TCP 连接也是一个文件,因此也被锁定在了 1024 个。通常情况下,我们会将这个数字设置为 65535。然而,笔者观察到这台虚拟机最大 TCP 连接数只能达到 5-6K 之间,远远无法满足用户需求。无论是采用 prefork、worker 还是 event 模式都是如此。而原因正是我们之前实测过的:此时 Apache 已经忙不过来,花费了一颗 CPU 核心的全部时间片来进行数据包和线程的匹配。
为了解决这个问题,笔者在同一台机器上安装了 Nginx 作为反向代理服务器,将所有用户请求转发给 Apache 处理。这个操作立即缓解了请求压力,而且 Nginx 使用的最大活跃 TCP 连接数量也只有 1K,完全满足了三分钟 4000 用户的需求。此时,系统架构和第一章的图 1-1 一样。
📙 高并发的哲学原理 《Philosophical Principles of High Concurrency》
Copyright © 2023 吕文翰