记异步写数据库覆盖带来的问题

需求:用户的调用时同步阻塞的,即收到了请求2的返回才会请求3

         服务器部署了两个一样的app,app需将用户多次调用产生的对话log写入到pg库,对话一次产生一轮,但同一个session只写入一行,所以采用覆盖,同时由于用户的返回与log入库无关,所以采用子线程异步入库。同时考虑到频繁插入会耗时很大,设置了1s批量插入一次。

实现:如下图,APP部署了两个。实现时,每次开始处理请求时都会去Redis中拉取之前该session存储的请求记录,保证当前内存中含有该请求以及历史请求。处理完该请求后又将请求log存入Redis

                      插入pg库时,会将当前内存里的所有请求入库。入库采用了消费者生产者模式,消费者是1s轮询一次,有值则批量插入,遇到相同key就覆盖。

产生的问题:因为左边APP入库子线程轮询可能处在还未到1s,而右边最新的请求3处理完,子线程准备执行入库时正好到了轮询的1s处,这时右边先入库,左变后入库,会导致左边的请求1,2,覆盖了右边的请求1,2,3,导致3丢失 

 

 

 

 

解决方法:1.入库时检查数据长度,只允许长数据覆盖短数据

                  2.异步因为性能问题无法去掉,可以增加标记请求时间的字段,如果当前请求时间早于已经入库的请求时间,则不覆盖

1-2解决方法都有问题,因为右边app写入时,可能左边app正好读取的是其写入前的状态,最后还是右边先入库,左边后入库

方法3:把开始处理请求3这个状态记录到Redis中,即右边app收到请求3时,里面同步写一个状态到redis,左边app子线程写库前先去看redis的状态是否已经有请求3了,有的话,不入库

方法3也有问题,假如右app主线程收到请求3时将该消息写入了Redis前左边app子线程入库时就做了状态查询,此时左app会继续入库,如果批量入库的数量较大,请求2又排在后面,可能写请求2的时间会很长,在这段长时间内,有可能右app主线程完成了接受请求3,通知Redis,再异步子线程入库,这一系列操作都赶在左app入库完成之前,那还是会有这个问题

方法4:既然问题出在请求3先与请求2入库,那入库的子线程在入库前区分一下请求2还是请求3,如果是请求3就又塞回到队列,并记录当前是第二次塞入,这样请求3入库延时肯定会比请求2长,即请求2肯定先入库

方法5:用Redis记录6种状态。

方法6:也是最终应用的方案;直接在请求2入库时sql判断,如果已经有记录则不覆盖,而请求3入库时sql为如果有记录则强行覆盖,可以避免因2覆盖3的问题。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值