记一次线上严重并发bug

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 记一次线上严重并发bug

记一次线上并发bug




前言


最近在写一个视频会议系统,我这边主要的一部分代码是RTC回调,还有一部分是客户端回调。在处理回调的时候都是按照同步的方式去进行的,本质上对于我来说不能有并发问题的,但是它确实发生了,那么我们一起来看下。


展示问题代码


下面这段代码主要含义就是当客户端开启共享屏幕或者视频的时候需要客户端回调给服务端RTC状态,服务端需要根据RTC状态计算最新视频画面排序规则。


// 1+6 1:主窗口一个 6 右侧小窗口数量
    public List<Integer> getTop7(String roomId, Integer mainN, Integer rightN) {
        // 【redis:zset】获取top7排序
        List<Integer> topList = getTopN(roomId, mainN, rightN);
        log.info("Top7返回的排序列表:"+topList);
        // 【redis:list】主要针对右侧小窗口缓存 减少相对调换次数
        List<Integer> lastList = getLastScreenSortList(roomId, "7");
        log.info("Top7最后一次排序:"+lastList);
        List<Integer> tmpLastList = new ArrayList<>(lastList);
        List<Integer> tmpTopList = new ArrayList<>(topList);
        // 纯算法计算稳定性排序 不涉及中间件存储和读取
        List<Integer> newList = updateLastScreenSortList(tmpLastList, tmpTopList);
        log.info("Top7当前最新排序:"+newList);
        // 【redis:list】删除最后一次排序key
        deleteLastScreenSortList(roomId);
        if (newList.size() > 0) {
            // 【redis:list】存储最新排序为最后一次排序key
            saveLastScreenSortList(roomId, newList, "7");
        }
        log.info("Top7当前最新排序:"+newList);
        return newList;
    }


大家可以看下,并发问题主要会出现在代码块哪里???



问题就是出现在如下代码块中:


// ---并发代码开始---
    deleteLastScreenSortList(roomId);
    if (newList.size() > 0) {
        // 【redis】存储最新排序为最后一次排序key
        saveLastScreenSortList(roomId, newList, "7");
    }
    // ---并发代码结束---
    // 保存最后一次排序列表
    public void saveLastScreenSortList(String roomId, List<Integer> userIds, String topN) {
        redisTemplate.opsForList().rightPushAll(LAST_SCREEN_SORT_KEY.setParamValue(topN, roomId), userIds);
    }


为什么会出现并发问题呢?就是当出现多个RTC回调同时走到并发代码段开始的时候,就会出现一个现象,这个现象就是:删删增增也就说多个请求会同时执行删除操作,然后同时走到存储部分。而存储部分是调用redis的list结构的rightPushAll方法,因此会push多份数据,那如果有大量上万级别回调同时进行呢?那就会导致数据在短时间内急剧膨胀,导致redis内存告警,当前服务和其他服务不可用。

这是非常严重的一个并发操作不当导致的线上问题,因此需要大家特别留心观察自己的代码,尤其是共享资源部分。


解决方案


  1. 可以用并发锁解决
  2. 可以用lua 脚本
  3. 可以用redis事务


这几种方案都可以,就看自己的场景适合哪一种,我们选择第二种方式,保证删除和新增都是原子操作。当然第三种也可以,只要保证删和增命令没问题就可以。至于第一种锁的粒度需要掌控好,同时也要保证锁的正确释放。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
测试技术
线上问题,如何处理?
线上问题,如何处理?
114 37
|
5天前
|
SQL 监控 数据库
线上服务假死排查
线上服务假死排查
7 0
|
8月前
|
Java Linux
并发编程系列:线上问题定位
面试时经常会被问到“CPU飙高怎么排查”,“内存泄露怎么定位解决”这类问题。本篇介绍一些常见的分析方法和工具
78 0
|
9月前
|
存储 缓存 监控
线上服务发布抖动,该怎么解决呢
之前的文章分别讲了[优雅上线]和 [优雅下线],实际工作中做了优雅上下线后,服务发布后还是会有短暂的“抖动”,接口的响应时间急剧升高后又恢复正常,就和下面的监控图一样
107 0
线上服务发布抖动,该怎么解决呢
|
10月前
|
运维 监控 前端开发
记一次线上 bug 的排查分析过程及总结
记一次线上 bug 的排查分析过程及总结
记一次线上 bug 的排查分析过程及总结
|
12月前
|
SQL 监控 NoSQL
高并发-【抢红包案例】之三:使用乐观锁方式修复红包超发的bug
高并发-【抢红包案例】之三:使用乐观锁方式修复红包超发的bug
91 0
|
12月前
|
SQL Web App开发 BI
高并发-【抢红包案例】之二:使用悲观锁方式修复红包超发的bug
高并发-【抢红包案例】之二:使用悲观锁方式修复红包超发的bug
62 0
|
12月前
|
测试技术 数据库
项目上线出bug怎么处理
项目上线出bug怎么处理
|
IDE Linux 调度
看完这篇文章,我再也不用担心线上出现 CPU 性能问题了(下)
在上一篇文章中咸鱼给大家介绍了 CPU 常见的性能指标,当生产环境出现 CPU 性能瓶颈的时候,优先观察这些指标有没有什么异常的地方,能解决大部分情况
|
存储 消息中间件 Linux
看完这篇文章,我再也不用担心线上出现 CPU 性能问题了(上)
生产环境上出现 CPU 性能问题是非常典型的一类问题,往往这个时候就比较考验相关人员排查问题的能力