背景
在电商场景中,会经常有秒杀活动,用户在秒杀一个商品时,商家如果设置了自动加群,会导致在秒杀时刻大批量用户加入群聊,如果任其流量冲击,会导致后端服务出现一系列问题。在这种特殊的秒杀场景下,我对加群接口做了一次彻底的优化改造。
分析
首先来分析一下加群具体的流程。
加群会给业务方返回3种结果。
1、群满了
一个群有群人数限制,当群满了后业务方会重新创建一个群,然后用新的群来加群。
2、加群成功
加群成功后表示该用户已经进群,不重试。
3、加群失败
当系统问题或者接口超时,返回失败。业务方会进行接口延时重试。
如何解决
当了解分析了该场景下的加群后,有以下几个方案可以解决。
1、向业务方规定请求速度,让业务方进行限速请求。(历史原因,一开始我们就是这么干的)
2、重构加群接口,业务方不再进行限速,无脑请求加群接口即可。(这次我要做的事)
方案流程
整体的流程大致就是利用Redis的高性能以及MQ异步+限流缓冲去解决秒杀的大批量入群操作。
在这个方案中也有几个需要注意的点。
一、在流程1中同人-同群,重复发加群消息,怎么处理Redis人数?
利用redis实现分布式锁,在1s内只能有1个请求通过,第2个请求返回成功。
二、流程2 redis缓存剩余人数的难点
1、在高并发下,理论上有多个请求进来查询群人数,这时候利用Redis分布式锁只有第一个请求去查询群人数并设置剩余人数至Redis缓存。剩余的请求自旋(重复尝试获取锁,第一次获取失败后在一个baseTime+随机时间内唤醒(需要根据查询群人数+入缓存的时间来设置baseTime))
2、双重检查(假设第一个请求已经给redis设置了缓存人数,第二个自旋拿到锁的请求就可以直接获取redis的值做判断了)
三、有没有有效解决获取分布式锁自旋造成的性能问题?
在创建群的接口设置Redis剩余群人数,并设置缓存时间为一星期。(一般商家搞活动都是提前2,3天创建群),足够了。
四、其他需要注意的地方
1、在删除群成员和群成员退出群聊时需要对Redis群人数自增。
2、加群触发的加群系统通知看情况是否需要进行限流降级发送。
3、Redis分布式锁注意不要使用SetNx + exipre命令,可能造成锁无法过期。
五、在加群请求投入到MQ后就代表加群成功了,如果确保最终请求一定成功?
在方案流程中的第5步,从mq限流获取加群请求后依次做入群操作,如果此时MySql压力过大或者有问题加失败了,重新投递MQ到延时队列,直到加群成功为止。
六、还做了哪些策略?
1、分布式配置动态调整限流大小
2、动态线程池
3、数据库迁移(将群聊从单聊的库中迁移(降低群聊秒杀对单聊的影响))
效果
线上凌晨压测直接QPS干到10000多,机器数不变的情况下cpu 在35%以内。
最后,没有最好的方案,只有最适合自己的方案。如有疑问和发现不足的地方,请联系,谢谢~