问一个并发上座的问题?

发布于 2022-09-11 17:02:33 字数 387 浏览 13 评论 0

问题描述

我是用 hash 表来表示座位上的人的( key 表示座位位置,value 就是具体的 uid ),然后用 hsetnx 处理并发上座,
但是有个问题是,在上座成功后,我要把这条信息投递到消息队列里去(为了通知客户端),但是这里可能有网络原因(或者其他原因),
导致投递失败,但是 redis 又没有事务,没办法回滚,这样就会出问题,不知道大家有什么好思路,冒昧请教下。
伪代码类似于:

res =  cache.setnx(pos, uid)
if (!res) {
    throw new Exception('上座失败!')
}
mq.send({
    pos: pos,
    uid: uid,
    time: new Date()
})

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

两人的回忆 2022-09-18 17:02:34

既然是担心网络问题,我们在投递消息的时候如果投递失败(可以利用rabbitmqconfirm模式),就将消息存到本地,然后起一个定时任务,定期将未投递成功的消息再次投递,直到投递成功为止(保证最终一致性)。

res =  cache.setnx(pos, uid)
if (!res) {
    throw new Exception('上座失败!')
}
mq.confirmSelect();
mq.send({
    pos: pos,
    uid: uid,
    time: new Date(),
    confirmCallback:function() {
        //将没有投递成功的消息存到本地
    }
})
︶ ̄淡然 2022-09-18 17:02:34

还是需要结合具体场景来看这个问题。

  1. 操作之前,对数据做好检验工作。尽可能保证后面的失败都是由网络引起的。
  2. 考虑对消息投递做重试处理。如果第一次投递失败,那么延迟2S,继续投递。如果还失败,延迟4S进行投递......设置一个重试上限,另外对重试过程追加日志输出,最好能加上报警。如果最后依旧失败的话,手工介入处理。这样的补偿,可以考虑新起goroutine异步处理就可以了。
  3. 如果必须对redis回滚的话。你可以考虑,自己对整个处理过程加锁,保证map中key的值不被别的请求修改掉。当投递失败之后,删除redis中的数据。而且删除前一定要对删除的数据进行判断,保证删除的一定是自己写入的。
  4. 延续3的话题,你可以看一下redis的set命令是否合适:SET key value [expiration EX seconds|PX milliseconds] [NX|XX]。不仅实现了setnx的功能,同时还加上了过期时间。跟map唯一的区别就是没有统一管理key值。
  5. 考虑使用MySQL事物替换。数据表创建4个字段,主键ID,key,value,status。设置key为唯一索引。第一次INSERT插入数据也能模拟SETNX的操作。

仅供参考,需要结合实际需要来处理

魄砕の薆 2022-09-18 17:02:34

消息队列本身就是解耦的,如果投递失败就回滚那就相当于强依赖了?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文