并发情况下的重复记录分析

并发情况下的重复记录分析

直播数据中心观众统计不准确,直播数据存在同一直播间同一用户两条记录
录的情况

  • 抓取异常请求日志观察
    1. 第一次 2022-07-06 10:40:48,586|INFO
    2. 第二次 2022-07-06 10:40:48,606|INFO
    3. 两次请求上报的时间戳来看,间隔不到30毫秒
  • 抓取接口平均响应时效
    1. 接口平均耗时在30毫秒-50毫秒作用
    2. 在第一次和第二次通过直播间ID 和用户ID 查询时 很大可能获取不到数据,同时进行了两次insert操作,也就造成了重复数据

解决方案

  • 前端修改上报频率
  1. 前端上报的时间间隔, 最起码应该是秒以上的单位,不能在毫秒内上报两次,用户的观看时长应该是秒级别的
  • 服务端对改接口进行并发加锁
基于redis的分布式锁

一个相对安全的分布式锁,一般需要具备以下特征:

  • 互斥性。互斥是锁的基本特征,同一时刻锁只能被一个线程持有,执行临界区操作。
  • 超时释放。通过超时释放,可以避免死锁,防止不必要的线程等待和资源浪费,类似于 MySQL 的 InnoDB 引擎中的 innodblockwait_timeout 参数配置。
  • 可重入性。一个线程在持有锁的情况可以对其再次请求加锁,防止锁在线程执行完临界区操作之前释放。
  • 高性能和高可用。加锁和释放锁的过程性能开销要尽可能的低,同时也要保证高可用,防止分布式锁意外失效。
    实现思路:
  1. redis保存lockKey,在获取不到锁的情况下进行一次重试
  2. 利用RocketMQ延时队列,进行异常和获取不到的锁的情况下,进行重试
  3. 数据库新增唯一索引,在丢失一条数据情况下,不影响后续数据的累加(可能会丢失并发时长数据)
 public Boolean lock(String key, long time) {
        try {
            String id = String.valueOf(Thread.currentThread().getId());
            String redisKey = LOCK + key;
            BoundValueOperations<String, String> ops = stringRedisTemplate.boundValueOps(redisKey);
            Boolean ans = ops.setIfAbsent(id, time, TimeUnit.MILLISECONDS);
            //可能有活锁问题
            if (Objects.equals(ans, Boolean.FALSE)) {
                Thread.sleep(time);
                return ops.setIfAbsent(id, time, TimeUnit.MILLISECONDS);
            }
            return true;
        } catch (Exception e) {
            log.error("redislock error#", e);
        }
        return false;
    }

当前锁缺陷:

  1. 没有进行锁的重入性判断,当加锁代码超过本身锁失效时间,可能会造成锁的失效,进而影响数据的正确性
  2. 可能会产生活锁问题,在重试过程中,如果一直获取不到锁,那么就有可能反复重试,没有任何一个线程能持有锁,造成活锁问题
  3. 当前代码不是有效的分布式锁,当redis本身出现异常,例如:主从同步延时较高,主库挂掉,从库升级master节点过程中,没有同步数据,可能会造成多个线程获取到锁,也无法保证数据的正确性

思考

  • 在分布式系统中,不能过多的依赖数据接口的执行时间,在临界操作的代码,一定要考虑一些数据正确性的保证,除了加锁操作,也可以通过消息队列做一些重试操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值