场景——高并发

一、如何保证接口幂等性?

接口幂等性:同一个接口,多次发出同一个请求,必须保证操作只执行一次。

前端控制:

  • 页面控制:点击之后按钮置灰或者是加载中,避免让用户重复点击多次;
  • 使用 Post/Redirect/Get 模式:数据提交后,跳转页面;
  • token机制:前端重复提交,但服务器收到了一个已经使用过的Token,就会认为这是一个重复请求并拒绝处理,从而确保接口的幂等性;(需要前端先调用后端接口,获取幂等 Token

后端控制:

  • 唯一标识符:客户端生成唯一 ID(如 UUID)随请求发送,服务器通过存储该 ID 判断是否重复(存在则视为重复请求);
  • 请求参数:利用参数特性(如时间戳、签名)判断合理性,例如时间戳超出有效范围则拒绝,适用于对时效性敏感的场景;
  • 状态检查:通过校验系统当前状态(如订单是否已创建)决定是否处理请求,直接基于业务逻辑判断,无需额外存储标识;

 

二、如何设计一个10w QPS高并发抢票系统?

1、限流设计:从入口到核心链路的流量管控

(1)多级限流策略:分层过滤无效流量

  • 网关层限流:全局流量拦截
    • 技术方案:使用 Nginx+Lua 实现基于 IP 的访问频率限制,通过 limit_req_zone 模块实现固定窗口限流(如每分钟单 IP 访问不超过 200 次);
    • 选型依据:Nginx 作为流量入口,具备高性能网络 IO 处理能力,Lua 脚本可直接操作共享内存(shm_zone),实现毫秒级响应的限流逻辑,适合拦截恶意高频请求;
  • 应用层限流:核心接口精准控制
    • 算法对比与选型:

      • 令牌桶算法(推荐):使用 Guava RateLimiter 或 Redis 分布式令牌桶,允许突发流量(如用户集中点击时的瞬时峰值);例如,设置每秒生成 10万个令牌,每个请求消耗1个令牌,突发时可消耗桶内累积令牌(适合抢券场景的流量突刺特性);

      • 漏桶算法:通过队列平滑请求速率,适合对流量稳定性要求高的场景(如支付接口),但不适合抢券这种短时间高并发场景。

  • 资源层限流:保护下游服务

    • 对库存查询、扣减等核心接口,使用 Sentinel 或 Hystrix 实现熔断降级,设置线程池隔离(如每个接口独立分配 200 个线程),防止某接口过载拖垮整个系统;

 

(2)库存扣减的分布式锁优化

  • Redis 分布式锁 vs 数据库行锁:
    • 对于秒杀场景,优先使用 Redis Redisson 实现可重入锁,锁超时时间需大于库存扣减逻辑执行时间(如 100ms),避免出现“超卖"漏洞;
    • 数据库行锁(如 MySQL的SELECT...FOR UPDATE)适用于库存精度要求极高的场景,但性能较低(单节点 QPS 约 5000),需配合分片库存(如按券ID哈希分库)提升并发能力;

2、防刷策略:从规则引擎到智能识别的立体防护

(1)基础防刷:规则化流量清洗

  • IP 限流:通过 Redis 记录每个 IP 的请求次数,设置滑动窗口(如5分钟内同- IP 请求超过 50 次则触发熔断),使用 ZSET 数据结构存储时间戳,定期清理过期数据;
  • 设备指纹:客户端生成唯一设备ID(结合 UUID、MAC地址、IMEI等),调用 Redis 判断该设备是否在短时间内多次请求(如1分钟内超过 10次),防止同一设备多账号刷券;
  • 验证码机制:对触发阈值的请求(如 IP 请求次数超过 30 次/分钟),返回图形验证码或行为验证码(如滑动拼图),通过阿里云验证码、极验等第三方服务提升破解难度;

(2)进阶防刷:行为分析与机器学习

  • 实时行为建模:使用 Flink 或 Spark Streaming 实时分析用户行为特征,如请求间隔分布、地理位置突变(同一账号1分钟内出现在北京和上海)、高频点击(每秒点击超过5次)等异常行为,动态调整限流值。

  • 黑名单系统:将被识别为机器刷票的 IP、设备 ID、用户 ID 存入 Redis 黑名单,后续请求直接返回失败,黑名单数据定期同步到 MySQL 长期存储;

(3)数据层防刷:库存预热与熔断保护

  • 预扣库存:将优惠券库存按比例拆分(如10万张券拆分为1000个库存单元,每个单元100张),用户抢到券时先预扣单元库存,减少锁竞争;
  • 熔断降级:当库存低于 10% 时,自动切换为“排队模式",通过 Kafka 消息队列缓冲请求,前端显示“排队中",避免瞬时流量击垮系统;

3、幂等性设计:确保操作唯一性与一致性

(1)唯一标识生成:请求去重的核心

  • 业务唯一键:生成全局唯一的请求ID,用户每次请求携带该 ID,服务端通过判断是否重复提交,确保同一请求仅处理一次;
  • 数据库唯一索引:在表中设置唯一索引;

(2)接口设计:幂等性实现的关键

  • HTTP 方法选择:使用POST方法时,通过请求体中的唯一 ID 实现幂等;对于查询类接口,使用GET方法天然支持幂等;
  • 状态机设计:定义清晰的业务状态流转(如“未领取一已领取一已使用一已过期”),每次操作前校验状态(如"已领取"状态不可重复领取),通过数据库事务保证状态一致性;

(3)重试机制:容错与幂等的配合

  • 客户端重试时携带相同请求 ID,服务端通过 Redis 或数据库唯一键判断是否已处理,避免重试导致重复操作;
  • 对于异步任务(如发券通知),使用消息队列的 ack 机制和消费者幂等处理(如根据消息 ID 去重),确保消息不重复消费;

posted @ 2025-08-08 18:21  幻月hah  阅读(38)  评论(0)    收藏  举报