首先说下顺序性消费带来的问题,都不考虑链式调用业务,就单纯互斥操作的业务,单机mq,单机redis环境,在mq消息等待被消费时,

举报
赵KK日常技术记录 发表于 2023/06/29 23:18:17 2023/06/29
【摘要】 首先说下顺序性消费带来的问题,都不考虑链式调用业务,就单纯互斥操作的业务,单机mq,单机redis环境,在mq消息等待被消费时,A消息进入队列等待被消费,B消息进入队列,此时A消息未消费完毕,B要根据A消息的结果进行操作,目前发生的问题就是多线程并发调用时,mq消费并没有按着先进先出的顺序进行消费,在同一时刻库里存在相同数据,但这是不允许的,在此期间如果其他人去查看数据,如果来自数据库,那必...

首先说下顺序性消费带来的问题,都不考虑链式调用业务,就单纯互斥操作的业务,单机mq,单机redis环境,在mq消息等待被消费时,A消息进入队列等待被消费,B消息进入队列,此时A消息未消费完毕,B要根据A消息的结果进行操作,目前发生的问题就是多线程并发调用时,mq消费并没有按着先进先出的顺序进行消费,在同一时刻库里存在相同数据,但这是不允许的,在此期间如果其他人去查看数据,如果来自数据库,那必定是不准确的。所以部分业务查的redis,但更坏的情况,此时redis凉了怎么办?

业务的ABA问题

业务1将数据A从缓存中取到,业务B将数据A从缓存中取到并将A变成了B,然后又将B变成了A,业务1发现此时数据仍是A,A操作成功,尽管业务操作时成功的,但不代表整个过程就没问题。另外,虽然顺序性问题有可能带来的结果是一致的,但是不代表这个过程中影响的其他数据就没问题。

图片

如图,同一时刻库中存入相同数据6条,但严谨逻辑只能允许库中存在相同数据只有一条,如果此时其他业务查询相关数据,必定会出现多结果返回

 设想解决方案一:原子计数

 方案:在每条数据进行操作之前,先判断两次操作数据是否为同一个,即redis的kv为同一个,如果相同则此时对key进行标记incr,步进1,在mq进行消费时,从redis中取出此key的步进值与传进来的步进值比较,按理说只需要记录想用kv值得最后最大步进值得操作

Long incr = redisService.incr(key,1);
Object o = redisService.getIncrValue(“key”);
if(o.toString().equals(vo.getIncr())){
//业务逻辑
}
结果测试:同样会出现此问题。一开始想到当前页面为同一用户对同一信息的操作,不会出现或者点不出如此高的并发,那不考虑接口被恶意攻击的情况,使用jemeter进行动态传参结果如何呢?

图片

每次的参数入参读取文件值,使每次结果为不同的操作,或者两台机器为同一账户对同一信息进行操作,必定会产生网络延迟造成对结果不一致的问题。

设想解决方案二:分布式锁

方案:对当前操作进行加锁,并保证同一值得锁操作为同一把锁时进行业务处理,集群模式下对消息进行分组,具体方案不成熟,引入redisson处理,但也疑问为了保证顺序性问题引入分布式锁的成本与性能问题,最终没能达到理想结果。

public Boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime,unit);
} catch (Exception e) {
return false;
}
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。