一个自动发卡网平台在初期因高并发流量频繁崩溃,导致订单丢失、用户投诉激增,技术团队通过排查发现,核心问题在于数据库锁竞争、缓存穿透以及无限制的同步请求,经过多次优化尝试,最终采用多级缓存(Redis+本地缓存)、异步队列削峰、分布式锁防超卖,并引入熔断降级机制,通过分库分表和CDN静态资源加速,系统从每秒几十请求提升至上万并发,响应时间从5秒降至200毫秒内,这一过程从“逢大促必宕机”到“丝滑应对流量洪峰”,成为高并发架构设计的典型案例。
当流量暴增,服务器在哭泣
凌晨三点,手机疯狂震动。
"老板,服务器又挂了!"
我揉着惺忪的睡眼,看着监控面板上飙升的CPU曲线,心里只有一个念头:"又来了。"

我们的自动发卡网平台刚刚上线了一款热门游戏点卡,瞬间涌入的订单让系统直接瘫痪,用户疯狂刷新,订单重复提交,数据库锁死,支付回调堆积如山……那一刻,我深刻理解了什么叫"幸福的烦恼"——流量是好事,但没准备的流量,就是灾难。
我们开始了漫长的"高并发限流"优化之路,我就把这段血泪史分享给你,希望能帮你少踩几个坑。
为什么自动发卡网容易崩?
自动发卡网的核心业务逻辑很简单:
用户下单 → 2. 支付成功 → 3. 系统发卡(自动或人工)
但问题就出在"高并发"上:
- 瞬间订单洪峰(比如热门商品秒杀)
- 支付回调风暴(第三方支付回调堆积)
- 库存超卖(多个请求同时扣减库存)
- 数据库锁竞争(大量事务阻塞)
如果不做限流,轻则订单错乱,重则数据库崩溃,甚至引发资金损失。
限流方案:从粗暴到优雅
最原始的限流:简单粗暴,但有效
方案:Nginx 限流
limit_req_zone $binary_remote_addr zone=req_one:10m rate=10r/s; server { location /api/order { limit_req zone=req_one burst=20 nodelay; proxy_pass http://backend; } }
优点:简单,直接限制请求频率。
缺点:一刀切,正常用户也可能被误杀。
进阶版:令牌桶算法(Token Bucket)
适用场景:平滑控制请求速率,避免突发流量冲击。
实现方式(Redis + Lua):
local tokens_key = KEYS[1] -- 令牌桶Key local timestamp_key = KEYS[2] -- 最后更新时间Key local rate = tonumber(ARGV[1]) -- 每秒生成多少令牌 local capacity = tonumber(ARGV[2]) -- 桶容量 local now = tonumber(ARGV[3]) -- 当前时间戳 local requested = tonumber(ARGV[4]) -- 请求的令牌数 local last_tokens = tonumber(redis.call("get", tokens_key)) if last_tokens == nil then last_tokens = capacity end local last_refreshed = tonumber(redis.call("get", timestamp_key)) if last_refreshed == nil then last_refreshed = 0 end local delta = math.max(0, now - last_refreshed) local new_tokens = math.min(capacity, last_tokens + delta * rate) local allowed = new_tokens >= requested if allowed then new_tokens = new_tokens - requested end redis.call("set", tokens_key, new_tokens) redis.call("set", timestamp_key, now) return allowed
优点:平滑限流,适应突发流量。
缺点:需要依赖Redis,有一定性能损耗。
终极方案:分布式限流(Sentinel / Redis + Lua)
Sentinel 配置示例:
// 定义资源 @SentinelResource(value = "createOrder", blockHandler = "handleBlock") public String createOrder(OrderRequest request) { // 业务逻辑 } // 限流降级处理 public String handleBlock(OrderRequest request, BlockException ex) { return "系统繁忙,请稍后再试!"; }
优点:动态规则调整,支持熔断降级。
缺点:需要额外部署Sentinel Dashboard。
实战优化:不只是限流,而是全链路保护
前端限流:按钮防抖 + 排队动画
- 用户点击"提交订单"后,按钮禁用2秒,防止重复提交。
- 使用WebSocket或轮询显示排队状态,缓解用户焦虑。
支付回调优化:异步化 + 幂等处理
- 支付成功回调不要直接处理发卡,先写入消息队列(如RabbitMQ/Kafka)。
- 确保回调接口幂等(相同订单号只处理一次)。
库存扣减:Redis + Lua 原子操作
local stock = tonumber(redis.call('GET', KEYS[1])) if stock >= tonumber(ARGV[1]) then redis.call('DECRBY', KEYS[1], ARGV[1]) return 1 -- 成功 else return 0 -- 库存不足 end
核心思想:避免数据库行锁,用Redis原子操作保证一致性。
数据库优化:读写分离 + 连接池
- 主库写,从库读。
- 合理配置HikariCP/Druid连接池参数,避免连接耗尽。
限流不是目的,用户体验才是
经过一系列优化,我们的自动发卡网终于从"崩溃边缘"变成了"丝滑稳定"。
关键经验:
- 分层防御:前端、网关、服务、数据库都要做限流。
- 动态调整:根据业务高峰灵活调整限流阈值。
- 用户体验:限流后要给用户友好提示,避免直接报错。
- 监控告警:Prometheus + Grafana 实时监控,早发现早处理。
我想说:高并发并不可怕,可怕的是没有准备。 希望这篇分享能帮你在流量洪峰中稳如泰山!
互动时间:
你的系统遇到过限流问题吗?欢迎评论区分享你的踩坑经历! 🚀
本文链接:https://www.ncwmj.com/news/5909.html