1秒下单10万次,服务器是怎么扛住的?

2019年双十一,天猫订单创建峰值达到 54.4万笔/秒 。 2020年双十一,订单峰值 58.3万笔/秒 。 2021年,每秒 4982亿次实时计算...

这些数字什么概念?

想象一下:全国人民同时点外卖,美团服务器大概会这样:

yaml 复制代码
你 ──→ 外卖服务器
         ↓
     服务器:💥 这谁顶得住啊!
         ↓
     宕机...全员崩溃...

但双十一从来没有宕机过。为什么?

今天聊聊,负载均衡是怎么让"一个人扛"变成"一堆人扛"的。


原文地址

墨渊书肆/1秒下单10万次,服务器是怎么扛住的?


一个厨师干不了的事

单机天花板

假设你开了一家小餐厅,只有一个厨师:

yaml 复制代码
顾客1 → 厨师(做菜)→ 上菜
顾客2 → 厨师(做菜)→ 上菜  (等...)
顾客3 → 厨师(做菜)→ 上菜  (等...)
...
顾客100 → 厨师(做菜)→ 上菜  (等到天荒地老...)

一个厨师同时只能做一道菜。顾客多了就要排队,排队久了就走人。

服务器也是一样的道理。

一台服务器的 CPU、内存、带宽都是有限的。当请求量超过服务器的"精力",就会出现:

问题 表现
响应变慢 用户等半天没反应
超时 请求等太久,直接失败
宕机 服务器扛不住,直接崩了

加厨师!谁来分配?

加10个厨师就行了:

yaml 复制代码
顾客1 → 厨师A → 上菜
顾客2 → 厨师B → 上菜
顾客3 → 厨师C → 上菜
...

但新问题来了:顾客怎么知道该找哪个厨师?

这时候就需要一个迎宾员


负载均衡:谁来当迎宾员?

什么是负载均衡?

负载均衡 (Load Balancer)= 把请求均匀分配到多台服务器。

就像餐厅迎宾员:顾客进门,迎宾员安排到哪个厨师。

yaml 复制代码
请求 ──→  迎宾员 ──→ 服务器A
                 ──→ 服务器B
                 ──→ 服务器C

三种分配策略

策略 原理 优点 缺点 适合场景
轮询 挨个分配 简单、公平 不管服务器性能差异 服务器配置相同的场景
最少连接 谁闲谁上 动态平衡 连接数≠实际负载 各请求耗时差异大的场景
IP哈希 固定IP打固定服务器 会话保持 服务器缩容会丢会话 需要保持用户状态的场景

怎么选?

  • 服务器配置一样 → 轮询
  • 请求耗时差异大 → 最少连接
  • 需要会话保持 → IP哈希

举例:

yaml 复制代码
# 轮询:简单粗暴,挨个来
请求1 → 服务器A
请求2 → 服务器B
请求3 → 服务器C

# 最少连接:谁闲谁上
服务器A(5个连接)
服务器B(2个连接)← 选这个
服务器C(8个连接)

# IP哈希:同一IP永远打同一台
某个IP的请求 ──→ 哈希计算 ──→ 固定某台服务器

分配策略定了,但负载均衡在哪一层做?

请求进来之后,在不同网络层级做分配,能力是不同的:

L4 和 L7 的区别

层级 工作在 特点 例子
L4 IP + 端口 快,不解析内容 LVS、F5
L7 HTTP/HTTPS 懂业务,按URL/Cookie分配 Nginx、Envoy
yaml 复制代码
L7 负载均衡:看得懂 URL
  /api/users → 用户服务
  /api/products → 商品服务

L4 负载均衡:只看 IP + 端口
  192.168.1.1:80 → 服务器A
  192.168.1.2:80 → 服务器B

实际用法:L4 做入口分发,L7 做业务路由。


负载均衡搞定了,但如果厨房要"换厨师"怎么办?

流量分配、高可用都搞定了。但如果厨房要换新厨师(更新代码),不能直接换------万一新厨师出问题,整个餐厅就乱了。

金丝雀发布:怎么安全地更新版本?

想象餐厅换新菜单

你要换一批新菜品,直接让所有客人都吃,万一出问题就全砸了招牌。

更好的做法:先印10份新菜单,给几桌客人试试,好用再全面推广。

这就是金丝雀发布。"金丝雀"是最先尝鲜的少数用户。

怎么发布?

yaml 复制代码
旧版本A(老菜单)← 90%客人
新版本B(新菜单)← 10%客人

观察:
- 新菜单没问题 → 逐步加大比例
- 新菜单有问题 → 立刻换回老菜单

核心:先让少量用户试水,没问题再全量上线。

yaml 复制代码
第一阶段:10% 流量到新版本
         ↓ 观察错误率
第二阶段:50% 流量到新版本
         ↓ 观察错误率
第三阶段:100% 流量到新版本

金丝雀 vs 蓝绿部署

方式 原理 资源 切换速度
金丝雀 新旧版本共存,逐步切换
蓝绿 两套完整环境,一键切换

蓝绿部署就是:准备好一套全新的,等它测试通过后,DNS 一刀切换过去。回滚也是一刀切回来。


换菜单的问题解决了,但迎宾员自己也有问题------万一迎宾员累趴了呢?

高可用:迎宾员挂了怎么办?

只有一个迎宾员的问题

yaml 复制代码
迎宾员A ← 单点故障!
    ↓
所有顾客不知道往哪走

解决方案:再加一个迎宾员。

yaml 复制代码
主迎宾员A  ←→  心跳检测  ←→  备迎宾员B

A活着:B 闲着
A挂了:B 马上顶上

这就是**高可用(HA)**的核心:冗余备份

熔断:服务器"跳闸"保护

想象一下:厨房着火冒烟了,迎宾员还一个劲往里塞客人,结果整个餐厅都完了。

熔断就是当某个服务出问题时报错"别塞了,等一下":

yaml 复制代码
服务A(正常)→ 继续接收请求
服务A(报错增多)→ 触发熔断
服务A(熔断中)→ 直接返回"服务繁忙",不往里塞

等服务A恢复后 → 逐步放行请求

熔断 vs 限流:

  • 限流:人多时"排队取号"
  • 熔断:厨房着火时"暂停营业"

健康检查:怎么知道厨师还活着?

迎宾员要时不时看看后厨:

yaml 复制代码
迎宾员:嘿,师傅,还在吗?
厨师A:活着!(2ms)
厨师B:...(没响应)
厨师C:活着!(3ms)

→ 把厨师B踢出队列
→ 等恢复了再加回来

核心就三点:

  1. 定时探测
  2. 失败就标记"不健康"
  3. 不再往这台机器分配请求

高可用搞定了,但还有一个问题:用户登录后,下次请求换到另一台服务器,还认识他吗?

登录状态:换台服务器怎么还认识我?

你登录了淘宝,刷新页面还是登录状态。但如果负载均衡把你从服务器A换到了服务器B...

yaml 复制代码
服务器A(存着登录状态)
服务器B(没有登录状态)

你的请求被换到服务器B → 要重新登录!

三种解决方案:

方案 原理 缺点
Session同步 所有服务器都存一份 同步慢,占内存
Session绑定 同一IP永远打同一台 服务器挂了状态丢
Session外置 存Redis,所有服务器共享 依赖Redis,Redis挂了也完蛋
yaml 复制代码
用户请求 ──→ 服务器A ──→ Redis(Session)
                              ↓
                         所有服务器都能访问

Session问题解决了,接下来看看更前一层------DNS怎么帮忙分流。

DNS轮询:最简单的负载均衡

DNS = 域名解析。把 www.taobao.com 变成 IP 地址。

普通DNS:一个域名 → 一个IP

DNS轮询:一个域名 → 多个IP,轮流返回。

yaml 复制代码
用户1 → DNS → IP1(服务器A)
用户2 → DNS → IP2(服务器B)
用户3 → DNS → IP3(服务器C)
...

优点:简单

缺点:

  • DNS 不知道服务器挂了(没有健康检查)
  • DNS 不知道哪台忙(没有智能分配)

DNS轮询适合做"第一层分流",配合 L4/L7 负载均衡使用。

分层搞清楚了,下面用一张图串起来。

一张图:流量是怎么走的

yaml 复制代码
用户请求
    ↓
DNS轮询(宏观分流)
    ↓
L4/L7 负载均衡(智能分配)
    ↓
应用集群(真正干活)
    ↓
Redis(Session共享)
    ↓
数据库(持久化)
层级 负责什么
DNS轮询 高速路口分流
L4/L7负载均衡 商场迎宾员
应用服务器 厨师做菜
Redis 记忆
数据库 保险箱

理论讲完了,来个实战。

实战:秒杀系统怎么设计?

需求: 100万人同时下单,每秒处理10万订单,不能宕机。

三招:

1. 分 --- 多层分流

yaml 复制代码
用户端限流(token验证码)
    ↓
Nginx 负载均衡
    ↓
网关集群(限流熔断)
    ↓
应用集群(库存/订单/支付服务拆分)
    ↓
消息队列(Kafka)削峰

2. 保 --- 每一层都备份

没有单点,任何一台挂了都能切换。

3. 限 --- 超过能力直接拒绝

超过阈值的请求直接返回"抢光了",保护系统不被压垮。

以上就是双十一不宕机的秘密。

写在最后

双十一从不宕机,不是因为服务器特别牛,而是架构设计得好

本质就三招:

yaml 复制代码
分 ------ 流量分散到多台机器
保 ------ 备份、心跳、故障转移
限 ------ 超过能力的直接拒绝

下次双十一剁手的时候,可以想想:这么顺畅的体验,背后是无数台服务器在负载均衡互相备份限流熔断...

他们比你还累。

相关推荐
小强19881 小时前
为什么小程序中不能使用 window、document 或 jQuery?
后端
楼田莉子1 小时前
仿Muduo的高并发服务器:LoopThread模块及其ThreadPool模块
linux·服务器·c++·后端·学习
二月龙1 小时前
微信小程序页面栈限制解析与突破方案
后端
Rust研习社2 小时前
你为什么总是入门 Rust 失败
开发语言·后端·rust
SamDeepThinking2 小时前
批评下属不如当场展示解决方案
后端·程序员·团队管理
逸Y 仙X2 小时前
文章二十四:Elasticsearch查询排序应用实战e
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
techdashen2 小时前
等了两年,Cloudflare 终于给规则引擎加上了通配符
服务器·rust
无忧智库2 小时前
具身智能的数据底座之战:一个大规模三维空间语义语料库的完整工程实践(WORD)
大数据·人工智能
zhangfeng11332 小时前
宝塔服务器完全可以安装 Git,进行版本管理,而且非常简单
运维·服务器·人工智能·git·编程