现网刷楼业务问题复现

起因

前段时间我们现网业务腾讯先游有个盖楼层的活动,就是一篇文章下面发表评论,运营会指定几个楼层送冒险岛2的测试资格,然后用户就开始疯狂的刷楼层,我们网站日常的请求TPS也就300+的样子,由于这个活动TPS一下子冲到5000+,然后网站就开始出现一系列的问题,不停的收到mysql的慢查询告警,更为严重的是评论计数错误,导致前端无法正确分页,新发的评论直接看不到!

原因分析

先说下我们的评论业务模型,我们现网为了提高并发量对业务表进行了分表,简化下来就是一个文章表,一个评论表,每发表一个评论就插入一天评论表,并update文章表,计数+1,出问题的sql就是计数+1的update语句的sql,出现大量慢查,并且很多失败,表现的现象就是评论表插入成功了,但是评论计数没有更新成功,前台拿到评论计数计算分页就并没有新插入的这几页,然后用户就看不到自己新发的评论了。

业务模型和现象分析清楚了,然后就是为啥出这个问题,其实也很明显,这么多条并发的update语句都是update文章表的同一行,我们现网的innodb是行锁机制,加锁操作耗费了大量时间,能支持的并发不高(我们现网就一台mysql),线下找了台4核机器搭建mysql进行了压测,update同一行的操作,innodb就2000+r/s左右,5000+的并发显然是扛不住的(PS:mysql的插入性能还是蛮好的,测出20000+r/s的样子)

问题解决

不扩充物理资源的情况下做优化,那方案显然就是队列化,合并对个update操作(反正都是update同一行)减少update的sql量,我们使用redis做了一个队列,定时(3s)批量将队列中的请求插入评论表,并统一更新文章表的评论计数,现网验证抗住了5000+r/s的并发。

但是这个方案其实也有明显问题的,为了解决一个爆发流量的问题,牺牲用户体验,用户发的评论要3s才能看到,作为一个大部分情况下流量都很低的系统,我觉得是不值得的,近期准备该进程智能识别当前流量,决定是直接落DB还是插入队列。

Loading Disqus comments...
Table of Contents