欢迎光临
我们一直在努力

【架构-Nginx】Nginx 限流实战|定点12点500万并发抢红包,限额15000请求+每日自动重置闭环方案

文章目录

    • 一、业务需求梳理 📌
      • 核心2大诉求
      • 整体业务流程图(Mermaid彩色版)
    • 二、整体架构设计思路 💡
    • 三、Nginx 完整配置实现 🛠️
      • 3.1 nginx.conf 全局限流配置
      • 3.2 红包接口 location 拦截配置
    • 四、定时重置脚本(crontab每日12点执行) ⏰
      • 4.1 重置脚本 reset_redpacket.sh
      • 4.2 脚本授权命令
      • 4.3 crontab 定时任务配置
    • 五、Java后端红包库存控制逻辑(兜底第二层拦截) ☕
      • Redis库存工具类核心逻辑
    • 六、运维常用操作命令 📋
      • 1. 校验Nginx配置是否生效
      • 2. 手动重载Nginx刷新限流计数
      • 3. 查看Nginx限流日志
      • 4. 手动执行重置脚本测试
      • 5. 实时监控Redis红包库存
    • 七、关键问题优化点 ✨
    • 八、扩展优化方案(生产高阶) 🚀

一、业务需求梳理 📌

核心2大诉求

  • 定点定时生效:每日12:00自动开启红包限流拦截,非12点时段接口正常放行
  • 双层限流控制
    • 第一层:Nginx前置拦截,全局只放行**15000**个请求,超出直接返回红包已抢完JSON
    • 第二层:放行的15000请求内部消耗10000个红包额度,额度耗尽后,接口永久拦截直到次日12点自动重置
  • 峰值场景:午间瞬时**500万**并发,纯Nginx层拦截减少后端服务压力,避免雪崩
  • 整体业务流程图(Mermaid彩色版)

    #mermaid-svg-tii5VHCz5KLx6gWV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tii5VHCz5KLx6gWV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tii5VHCz5KLx6gWV .error-icon{fill:#552222;}#mermaid-svg-tii5VHCz5KLx6gWV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tii5VHCz5KLx6gWV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tii5VHCz5KLx6gWV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tii5VHCz5KLx6gWV .marker.cross{stroke:#333333;}#mermaid-svg-tii5VHCz5KLx6gWV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tii5VHCz5KLx6gWV p{margin:0;}#mermaid-svg-tii5VHCz5KLx6gWV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-tii5VHCz5KLx6gWV .cluster-label text{fill:#333;}#mermaid-svg-tii5VHCz5KLx6gWV .cluster-label span{color:#333;}#mermaid-svg-tii5VHCz5KLx6gWV .cluster-label span p{background-color:transparent;}#mermaid-svg-tii5VHCz5KLx6gWV .label text,#mermaid-svg-tii5VHCz5KLx6gWV span{fill:#333;color:#333;}#mermaid-svg-tii5VHCz5KLx6gWV .node rect,#mermaid-svg-tii5VHCz5KLx6gWV .node circle,#mermaid-svg-tii5VHCz5KLx6gWV .node ellipse,#mermaid-svg-tii5VHCz5KLx6gWV .node polygon,#mermaid-svg-tii5VHCz5KLx6gWV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tii5VHCz5KLx6gWV .rough-node .label text,#mermaid-svg-tii5VHCz5KLx6gWV .node .label text,#mermaid-svg-tii5VHCz5KLx6gWV .image-shape .label,#mermaid-svg-tii5VHCz5KLx6gWV .icon-shape .label{text-anchor:middle;}#mermaid-svg-tii5VHCz5KLx6gWV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tii5VHCz5KLx6gWV .rough-node .label,#mermaid-svg-tii5VHCz5KLx6gWV .node .label,#mermaid-svg-tii5VHCz5KLx6gWV .image-shape .label,#mermaid-svg-tii5VHCz5KLx6gWV .icon-shape .label{text-align:center;}#mermaid-svg-tii5VHCz5KLx6gWV .node.clickable{cursor:pointer;}#mermaid-svg-tii5VHCz5KLx6gWV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tii5VHCz5KLx6gWV .arrowheadPath{fill:#333333;}#mermaid-svg-tii5VHCz5KLx6gWV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tii5VHCz5KLx6gWV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tii5VHCz5KLx6gWV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tii5VHCz5KLx6gWV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tii5VHCz5KLx6gWV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tii5VHCz5KLx6gWV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tii5VHCz5KLx6gWV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tii5VHCz5KLx6gWV .cluster text{fill:#333;}#mermaid-svg-tii5VHCz5KLx6gWV .cluster span{color:#333;}#mermaid-svg-tii5VHCz5KLx6gWV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tii5VHCz5KLx6gWV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tii5VHCz5KLx6gWV rect.text{fill:none;stroke-width:0;}#mermaid-svg-tii5VHCz5KLx6gWV .icon-shape,#mermaid-svg-tii5VHCz5KLx6gWV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tii5VHCz5KLx6gWV .icon-shape p,#mermaid-svg-tii5VHCz5KLx6gWV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tii5VHCz5KLx6gWV .icon-shape .label rect,#mermaid-svg-tii5VHCz5KLx6gWV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tii5VHCz5KLx6gWV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tii5VHCz5KLx6gWV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tii5VHCz5KLx6gWV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    定时重置计数/库存

    客户端并发请求500W QPS

    Nginx网关层限流拦截模块

    定时任务每日12点重置计数

    当前放行计数≥15000?

    红包库存≤0?

    Java红包服务扣减红包库存

    返回JSON:红包已抢完

    正常抢红包返回结果

    二、整体架构设计思路 💡

  • Nginx 限流选型:使用 ngx_http_limit_req_module + 共享内存计数器,持久化计数文件
  • 定时定点控制:Linux crontab 每日12点执行脚本重置Nginx计数器,恢复放行权限
  • 双重熔断机制
    • Nginx层:硬限制最大放行15000次,超量直接拒绝,不打穿Java服务
    • Java服务层:红包库存10000,库存清零后接口直接返回已抢完,不再执行业务逻辑
  • 数据存储:Nginx共享内存存储放行请求数;Redis存储红包剩余库存(Java层)
  • 三、Nginx 完整配置实现 🛠️

    3.1 nginx.conf 全局限流配置

    # 共享内存区域:红包接口计数器,存储15000请求计数,共享内存10M
    limit_req_zone $uri zone=red_packet:10m rate=10000r/s;
    # 持久化计数文件,重启Nginx不丢失当前放行计数
    limit_req_file /var/nginx/red_packet_count.txt zone=red_packet;

    # 自定义限流返回JSON,红包已抢完
    limit_req_status 429;
    error_page 429 = @packet_full;

    location @packet_full {
    default_type application/json;
    return 200 '{"code":999,"msg":"红包已抢完","data":null}';
    }

    # 定时开关控制变量,默认关闭红包限流
    set $packet_switch 0;
    # 利用Nginx时间判断,每日12点~14点开启红包限流窗口
    if ($time_iso8601 ~ "T12|T13") {
    set $packet_switch 1;
    }

    3.2 红包接口 location 拦截配置

    location /api/redPacket/grab {
    # 非12-14点直接放行,不限流
    if ($packet_switch = 0) {
    proxy_pass http://java_backend;
    break;
    }
    # 限流规则:最大放行15000个请求,突发不排队,超量直接429
    limit_req zone=red_packet burst=15000 nodelay;
    proxy_pass http://java_backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    }

    四、定时重置脚本(crontab每日12点执行) ⏰

    4.1 重置脚本 reset_redpacket.sh

    #!/bin/bash
    # 1.清空Nginx红包计数器持久化文件
    echo 0 > /var/nginx/red_packet_count.txt
    # 2.重载Nginx配置,刷新共享内存计数
    nginx -s reload
    # 3.调用Java后台接口重置Redis红包库存为10000
    curl -X POST http://127.0.0.1:8080/api/redPacket/resetStock
    echo "每日12点红包限流计数、库存重置完成"

    4.2 脚本授权命令

    chmod +x /usr/local/script/reset_redpacket.sh

    4.3 crontab 定时任务配置

    # 每日中午12:00整执行重置脚本
    0 12 * * * /usr/local/script/reset_redpacket.sh >> /var/log/redpacket_cron.log 2>&1
    # 查看定时任务
    crontab -l
    # 编辑定时任务
    crontab -e

    五、Java后端红包库存控制逻辑(兜底第二层拦截) ☕

    Redis库存工具类核心逻辑

    /**
    * 红包抢单兜底拦截,Nginx放行15000次,实际仅10000个红包
    */

    @Service
    public class RedPacketService {
    private static final String RED_PACKET_STOCK_KEY = "red:packet:stock";
    private static final Integer MAX_STOCK = 10000;

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 每日定时重置库存接口(crontab调用)
    @PostMapping("/api/redPacket/resetStock")
    public Result<Void> resetStock() {
    redisTemplate.opsForValue().set(RED_PACKET_STOCK_KEY, MAX_STOCK.toString());
    return Result.success();
    }

    // 抢红包核心接口
    @GetMapping("/grab")
    public Result<?> grabPacket() {
    // 原子扣减库存
    Long remainStock = redisTemplate.opsForValue().decrement(RED_PACKET_STOCK_KEY);
    if (remainStock < 0) {
    // 库存耗尽,直接返回已抢完
    return Result.error(999, "红包已抢完");
    }
    // 正常发放红包逻辑
    return Result.success("领取成功");
    }
    }

    六、运维常用操作命令 📋

    1. 校验Nginx配置是否生效

    nginx -t

    2. 手动重载Nginx刷新限流计数

    nginx -s reload

    3. 查看Nginx限流日志

    tail -f /var/log/nginx/error.log | grep red_packet

    4. 手动执行重置脚本测试

    sh /usr/local/script/reset_redpacket.sh

    5. 实时监控Redis红包库存

    redis-cli get red:packet:stock

    七、关键问题优化点 ✨

  • 500万并发防雪崩:全部无效请求在Nginx直接拦截,不建立Java服务连接,大幅降低后端CPU/连接池压力
  • 计数持久化:使用 limit_req_file 存储放行计数,Nginx重启不会丢失已放行请求数量
  • 时间窗口可控:可修改Nginx $time_iso8601 正则,自定义红包活动时段(示例12~14点)
  • 双层兜底:Nginx控制总放行量,Redis库存控制实际红包数量,双重保障超发
  • 自动循环:crontab每日12点自动清零计数+重置库存,无需人工干预
  • 八、扩展优化方案(生产高阶) 🚀

  • 分布式Nginx集群:单机共享内存失效,替换为 lua-resty-redis 实现分布式统一计数器
  • 动态调整额度:通过Lua脚本读取Redis配置,动态修改放行15000阈值,无需改配置重载Nginx
  • 监控告警:监控429状态码占比,并发突增推送钉钉/短信告警
  • 流量削峰:配合Nginx队列缓冲,瞬时超大并发平滑丢弃无效请求
  • 赞(0)
    未经允许不得转载:171主机测评 » 【架构-Nginx】Nginx 限流实战|定点12点500万并发抢红包,限额15000请求+每日自动重置闭环方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址