
当后台系统面临 “秒杀活动每秒 10 万 + 请求”“电商大促 QPS 突破百万” 等场景时,传统架构极易因 “流量过载、资源耗尽、延迟飙升” 陷入瘫痪。高并发系统的核心不是 “用更贵的服务器”,而是通过系统化设计,让有限资源高效承载海量请求,同时保证 “低延迟(如 P99<100ms)、高可用(无宕机)、数据准”。本文将从高并发的核心挑战出发,拆解六大关键设计要点,结合秒杀、直播带货等实战场景,提供可落地的方案,帮你避开 “高并发踩坑”。
在设计前,需明确高并发系统的三大核心目标,所有方案都需围绕这些目标展开:
而实现这些目标的核心挑战集中在三点:
高并发的第一道防线是 “在流量进入系统前就进行管控”,避免无效流量占用核心资源。核心思路是 “削峰填谷 + 精准过滤”,关键设计要点如下:
脉冲式流量(如秒杀开始的 10 秒内)是系统崩溃的主要原因,需通过 “缓冲层” 将 “尖峰流量” 拉平为 “平缓流量”:
将同步请求转为异步处理,用消息队列(Kafka/RocketMQ)暂存请求,后端服务按能力消费。例如:
前端用 “排队页面” 控制请求发送节奏,后端用 “令牌桶” 控制接收速度。例如:
高并发场景中,30%-50% 的请求是无效的(如重复请求、无资格请求),需在接入层提前过滤,减少核心服务压力:
无效请求类型 | 过滤方案 | 实现位置 |
|---|---|---|
重复请求(如用户多次点击) | 前端:按钮置灰(点击后禁用);后端:用 Redis 记录 “用户 - 商品” 请求记录(过期时间 5 秒),重复请求直接返回 “已提交” | 前端 + API 网关 |
无资格请求(如未登录、未预约) | API 网关验证用户令牌(JWT)、查询 Redis 中的 “预约资格表”,无资格请求直接返回 “无权限” | API 网关 |
非法请求(如参数篡改、爬虫) | 网关层校验参数签名(时间戳 + 随机数 + secret)、IP 黑名单(拦截高频爬虫 IP)、User-Agent 过滤(排除非浏览器请求) | API 网关 |
将过滤后的有效流量均匀分配到多个服务节点,避免单节点过载:
应用层是请求处理的核心,高并发下需做到 “快速处理、不阻塞、可扩展”,核心设计要点是 “无状态设计” 和 “异步化改造”。
“无状态” 指服务节点不存储本地数据(如用户会话、业务缓存),所有数据从公共存储(Redis、数据库)获取,这样才能通过 “增加节点” 线性提升处理能力:
同步调用(如 “创建订单→同步调用支付→同步调用库存”)会导致线程阻塞(等待下游响应),高并发下线程池很快会被耗尽。异步化通过 “非阻塞” 方式让线程处理更多请求:
业务场景 | 同步问题 | 异步方案 |
|---|---|---|
订单创建后发送通知(短信 / 推送) | 同步调用通知服务(耗时 500ms),线程阻塞 | 订单创建后,向 RocketMQ 发送 “订单创建事件”,通知服务消费事件异步发送通知,订单服务无需等待 |
下单时校验多个下游服务(库存、价格、资格) | 同步调用 3 个服务(共耗时 800ms),线程阻塞 | 用 CompletableFuture 实现 “并行调用”(3 个服务同时调用,总耗时 200ms),且线程非阻塞 |
大文件上传(如视频、日志) | 同步等待文件上传完成(耗时 10 秒),线程长期占用 | 前端分片上传 + 后端异步合并(上传分片时返回 “分片 ID”,全部分片上传后,后端异步合并文件) |
// 异步并行调用库存、价格、资格校验服务,总耗时=最长的单个服务耗时(约200ms)CompletableFuture<Boolean> stockFuture = CompletableFuture.supplyAsync(() -> stockService.checkStock(productId, quantity) // 库存校验(200ms));CompletableFuture<Boolean> priceFuture = CompletableFuture.supplyAsync(() -> priceService.checkPrice(productId, price) // 价格校验(150ms));CompletableFuture<Boolean>资格Future = CompletableFuture.supplyAsync(() -> userService.checkEligibility(userId, productId) // 资格校验(180ms));// 等待所有调用完成,且都返回true才继续boolean allPass = CompletableFuture.allOf(stockFuture, priceFuture, 资格Future) .thenApply(v -> { try { return stockFuture.get() && priceFuture.get() && 资格Future.get(); } catch (Exception e) { return false; } }).get();if (!allPass) { throw new BusinessException("下单条件不满足");}应用层的线程池是 “请求处理的入口”,高并发下线程池配置不当(如核心线程数太少、队列太小)会导致 “线程耗尽、请求拒绝”:
线程池参数 | 配置原则(高并发场景) | 示例(订单服务) |
|---|---|---|
核心线程数(corePoolSize) | CPU 密集型(如计算):CPU 核心数 + 1;IO 密集型(如调用 DB、缓存):CPU 核心数 * 2(因线程大部分时间在等待 IO) | 8 核 CPU→16 个核心线程 |
最大线程数(maximumPoolSize) | 核心线程数的 2-3 倍(避免线程过多导致上下文切换开销) | 16→48 |
队列容量(queueCapacity) | 有界队列(避免无界队列导致内存溢出),容量 = 核心线程数10(如 1610=160) | 160 |
拒绝策略(rejectedExecutionHandler) | 核心业务用 “CallerRunsPolicy”(调用方线程兜底执行,避免请求丢失);非核心业务用 “DiscardOldestPolicy” | CallerRunsPolicy |
高并发下,数据库是最大的瓶颈(单 MySQL 实例的 QPS 上限约 1 万),数据层设计的核心是 “减少数据库访问” 和 “拆分数据存储”,关键要点如下:
通过 “多级缓存” 将 80% 的请求拦截在缓存层,仅 20% 的请求到数据库,这是高并发的 “核心优化手段”:
缓存层级 | 核心作用 | 技术选型与配置 | 适用场景 |
|---|---|---|---|
1. CDN 缓存 | 拦截静态资源请求(图片、JS、CSS) | 阿里云 CDN、Cloudflare;配置 “静态资源缓存时间”(如图片缓存 7 天,JS 缓存 1 天) | 电商商品图片、活动页面静态资源 |
2. 网关缓存 | 拦截高频动态请求(如商品基本信息、库存) | API 网关(如 Spring Cloud Gateway)集成 Redis;缓存时间短(如 10 秒),避免数据不一致 | 商品详情页的 “价格、库存” 展示 |
3. 服务本地缓存 | 拦截服务内高频请求(如配置、枚举) | Caffeine(Java 本地缓存,性能优于 HashMap);配置 “最大容量 1 万条,过期时间 5 分钟” | 服务内的 “活动规则、字典枚举” 查询 |
4. Redis 缓存 | 拦截分布式高频请求(如用户购物车、会话) | Redis 集群(3 主 3 从);开启 “数据持久化(AOF+RDB)”;缓存时间根据业务定(如购物车缓存 2 小时) | 用户购物车、秒杀商品库存计数 |
高并发下,缓存异常会直接冲击数据库,需针对性解决三大问题:
public Integer getSeckillStock(Long productId) { String key = "seckill:stock:" + productId; // 1. 先查Redis缓存 Integer stock = redisTemplate.opsForValue().get(key); if (stock != null) { return stock; } // 2. 缓存未命中,获取互斥锁 String lockKey = "lock:stock:" + productId; boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS); if (locked) { try { // 3. 拿到锁,查数据库 Integer dbStock = stockMapper.selectStockByProductId(productId); // 4. 缓存到Redis(设置过期时间5分钟) redisTemplate.opsForValue().set(key, dbStock, 300, TimeUnit.SECONDS); return dbStock; } finally { // 5. 释放锁 redisTemplate.delete(lockKey); } } else { // 6. 没拿到锁,重试(100ms后) Thread.sleep(100); return getSeckillStock(productId); }}当单表数据量超过 1000 万、单库 QPS 超过 1 万时,需通过分库分表拆分数据,提升存储和查询能力:
拆分方式 | 核心逻辑 | 适用场景 | 示例(电商订单表) |
|---|---|---|---|
水平分表(按行拆) | 将同一表的数据按 “分片键” 拆到多个表(如 order_1、order_2) | 单表数据量大(如订单表 1 亿行) | 按 “用户 ID 哈希” 分表:用户 ID%16=0→order_0,%16=1→order_1,共 16 个表,每个表约 625 万行 |
水平分库(按库拆) | 将多个表按 “分片键” 拆到多个库(如 db_0、db_1) | 单库 QPS 高(如 10 万 / 秒) | 按 “用户 ID 哈希” 分库:用户 ID%8=0→db_0,%8=1→db_1,共 8 个库,每个库 2 个订单表 |
垂直分表(按列拆) | 将表的 “热点列” 和 “冷列” 拆分到不同表(如 order_main、order_ext) | 表列数多(如 50 + 列),且热点列少 | 订单表拆为:order_main(订单 ID、用户 ID、金额等热点列)、order_ext(收货地址、备注等冷列) |
高并发场景中,读请求占比 80%-90%,通过 “主从复制 + 读写分离” 将读请求分流到从库,主库仅处理写请求:
spring: shardingsphere: rules: readwrite-splitting: data-sources: order-db: type: Static props: write-data-source-name: order-db-master # 写库(主库) read-data-source-names: order-db-slave1,order-db-slave2 # 读库(从库) load-balancer-name: round_robin # 读库负载均衡(轮询)高并发下,一个服务的资源耗尽(如线程池满、内存溢出)可能导致全链路崩溃,需通过 “资源隔离、限流、降级” 实现 “故障隔离”。
将不同业务的资源(线程池、数据库连接池、缓存)隔离,避免 “一个业务占用所有资源”:
隔离维度 | 实现方案 | 示例 |
|---|---|---|
线程池隔离 | 每个业务模块用独立线程池(如秒杀业务线程池、普通订单线程池) | 秒杀线程池满了仅影响秒杀业务,普通订单线程池仍正常处理请求 |
数据库连接池隔离 | 核心业务与非核心业务用独立连接池(如订单库连接池、日志库连接池) | 日志业务连接池满了,不影响订单库的连接获取 |
缓存隔离 | 不同业务的缓存 Key 加前缀(如 “seckill:stock:”“order:info:”),且用不同 Redis 集群 | 秒杀缓存集群故障,不影响订单缓存集群 |
限流是 “最后一道防线”,即使前面的优化都失效,也要通过限流保证系统不崩溃:
限流粒度 | 实现方案 | 示例(电商秒杀) |
|---|---|---|
接口级限流 | API 网关用 “令牌桶算法” 限制接口 QPS(如秒杀接口 10 万 / 秒) | Spring Cloud Gateway 集成 Resilience4j,配置 “seckill/create” 接口 QPS 上限 10 万 |
用户级限流 | 用 Redis 记录 “用户 - 接口” 请求次数(如每个用户每秒最多 2 次秒杀请求) | Redis INCR 命令:Key=“limit:user:123:seckill”,过期时间 1 秒,超过 2 次返回限流 |
IP 级限流 | 用 Redis 记录 “IP - 接口” 请求次数(如每个 IP 每秒最多 10 次请求) | Redis INCR 命令:Key=“limit:ip:192.168.1.1:seckill”,超过 10 次返回限流 |
当系统压力达到阈值(如 CPU 使用率 80%、内存使用率 90%),需 “舍弃非核心业务”,确保核心业务可用:
降级触发条件 | 降级方案 | 示例 |
|---|---|---|
服务响应时间超阈值(如 P99>500ms) | 关闭非核心接口(如商品详情页的 “历史评价”“猜你喜欢”) | 电商大促时,商品详情页仅保留 “商品信息、价格、库存”,关闭其他非核心模块 |
依赖服务故障(如支付服务超时) | 降级为 “本地缓存 + 异步重试”(如支付失败时,先保存订单,后台异步重试支付) | 支付服务故障时,订单服务先创建 “待支付” 订单,返回 “支付处理中”,后台用定时任务重试支付 |
数据库压力超阈值(如 CPU>90%) | 关闭非核心查询(如订单列表不显示 “订单备注”) | 订单查询接口仅返回 “订单 ID、金额、状态”,不返回 “备注、物流详情”,减少数据库查询字段 |
高并发下,“数据一致性” 容易被忽略(如秒杀超卖、订单少付),需针对核心场景设计一致性方案:
秒杀场景中,“超卖” 是致命问题(如库存 100,卖出 101 件),需通过 “原子操作” 保证库存扣减准确:
用 Redis 的 DECR 命令(原子操作)扣减库存,库存为 0 时直接返回 “已抢完”,后续请求不到数据库:
// 秒杀扣减库存(Redis原子操作)public boolean seckillDeductStock(Long productId) { String key = "seckill:stock:" + productId; // DECR原子扣减,返回扣减后的值 Long remainStock = redisTemplate.opsForValue().decrement(key); if (remainStock < 0) { // 库存不足,回补1(避免库存为负) redisTemplate.opsForValue().increment(key); return false; } // 库存足够,后续异步同步到数据库 sendStockSyncEvent(productId, remainStock); return true;}用 “版本号” 或 “库存字段” 实现乐观锁,避免并发扣减超卖:
-- 乐观锁扣减库存(仅当库存>=扣减数量时才执行)UPDATE stock SET count = count - #{deductCount}, version = version + 1 WHERE product_id = #{productId} AND count >= #{deductCount} AND version = #{version};高并发下大量使用异步消息,但消息丢失(如队列崩溃、网络抖动)会导致业务中断(如订单创建后,消息丢失导致库存未扣减),需保证消息 “不丢、不重、不乱序”:
高并发系统不能 “裸奔”,需完善监控体系和应急方案,确保 “问题早发现、故障能快速恢复”:
监控需覆盖 “流量、延迟、错误、资源” 四个维度,核心指标与工具如下:
监控维度 | 核心指标 | 工具选型与配置 |
|---|---|---|
流量监控 | 接口 QPS、请求量、并发用户数 | Prometheus+Grafana;配置 “QPS 告警阈值”(如秒杀接口 QPS 超过 10 万告警) |
延迟监控 | 接口 P50/P90/P99 响应时间、各环节耗时(如缓存耗时、DB 耗时) | SkyWalking(全链路追踪);配置 “P99 延迟告警”(如下单接口 P99>200ms 告警) |
错误监控 | 接口错误率、异常类型(如超时、数据库异常) | Sentry(异常追踪)、Prometheus;配置 “错误率告警”(如错误率超过 1% 告警) |
资源监控 | 服务器 CPU / 内存 / 磁盘 IO、Redis 内存 / 连接数、数据库连接数 | Prometheus+Node Exporter(服务器监控)、Redis Exporter(Redis 监控);配置 “CPU>80% 告警” |
高并发场景下,需提前准备应急方案,避免 “故障发生后手忙脚乱”:
故障场景 | 应急方案 |
|---|---|
秒杀流量超预期(QPS>20 万) | 1. 临时提高网关限流阈值(从 10 万到 15 万);2. 关闭非核心业务(如商品评价、推荐);3. 扩容 API 网关和订单服务节点 |
Redis 集群故障 | 1. 切换到备用 Redis 集群;2. 核心业务降级为 “直接查数据库”(如库存查询);3. 非核心业务返回 “服务繁忙” |
数据库主库故障 | 1. 用 MHA 自动切换从库为主库;2. 关闭非核心写业务(如日志写入);3. 读请求全部走从库 |
全链路雪崩 | 1. 网关层开启 “熔断”(仅允许核心接口请求);2. 核心接口降级为 “静态响应”(如返回 “系统维护中,5 分钟后重试”);3. 紧急扩容核心服务 |
有些系统 QPS 很高,但 P99 延迟超过 1 秒(如大量请求排队),用户体验差。需平衡 QPS 和延迟,核心接口需同时满足 “高 QPS” 和 “低延迟”。
有些系统为了性能,缓存不更新、不校验,导致 “用户看到的库存和实际库存不一致”。需定期校验缓存与数据库一致性,核心业务(如库存)需保证 “缓存更新实时性”。
高并发系统上线前必须做压测(用 JMeter、Locust 模拟峰值流量),验证系统能否扛住预期 QPS,避免 “上线即崩溃”。
以 “电商秒杀系统” 为例,整合上述设计要点,看高并发系统如何落地:
该系统最终扛住了 12 万 / 秒的秒杀峰值,下单接口 P99 延迟 80ms,无超卖、无数据丢失,且单个节点故障不影响整体服务。
高并发后台系统设计不是 “堆砌技术”,而是 “基于业务场景的系统化优化”—— 从流量接入层的 “削峰过滤”,到应用层的 “异步无状态”,再到数据层的 “缓存分拆”,每个环节都需围绕 “扛住高 QPS、控制低延迟、保障数据准” 的目标。关键是 “不追求一步到位”,可先实现核心优化(如缓存、限流),再根据业务增长逐步完善(如分库分表、异地多活)。希望本文的设计要点与实战方案,能帮你构建出 “稳、快、准” 的高并发后台系统。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。