Java后端
,选择“设为星标”
原文来自 GitHub 开源社区 Doocs,欢迎 Star 此项目,如果你有独到的见解,同样可以参与贡献此项目。
面试题
使用消息队列如何保证幂等性,这个是你架构里要考虑的一个问题。
因为这问题通常不是 MQ 自己保证的,是由我们开发来保证的。
挑一个 Kafka 来举个例子,说说怎么重复消费吧。
这会导致 consumer 有些消息处理了,但是没来得及提交 offset,尴尬了。
重启之后,少数消息会再次消费一次。
数据 1/2/3 依次进入 kafka,kafka 会给这三条数据每条分配一个 offset,代表这条数据的序号,我们就假设分配的 offset 依次是 152/153/154。
消费者从 kafka 去消费的时候,也是按照这个顺序去消费。
假如当消费者消费了
offset=153
的这条数据,刚准备去提交 offset 到 zookeeper,此时消费者进程被重启了。
那么此时消费过的数据 1/2 的 offset 并没有提交,kafka 也就不知道你已经消费了
offset=153
这条数据。
那么重启之后,消费者会找 kafka 说,嘿,哥儿们,你给我接着把上次我消费到的那个地方后面的数据继续给我传递过来。
由于之前的 offset 没有提交成功,那么数据 1/2 会再次传过来,如果此时消费者没有去重的话,那么就会导致重复消费。
假设你有个系统,消费一条消息就往数据库里插入一条数据,要是你一个消息重复两次,你不就插入了两条,这数据不就错了?
但是你要是消费到第二次的时候,自己判断一下是否已经消费过了,若是就直接扔了,这样不就保留了一条数据,从而保证了数据的正确性。
-
比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
-
比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
-
比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?
如果没有消费过,你就处理,然后这个 id 写 Redis。
如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
-
比如基于数据库的唯一键来保证重复数据不会重复插入多条。
因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。
一下吧,感谢。微信搜索「web_resource」,关注后即可获取每日一题的推送。
荐
阅
读
每日一题:为什么要进行系统拆分?
每日一题:你有没有做过 MySQL 读写分离?
欢
文
章
,
点
个
在看
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
相关文章
暂无评论...