最近想从浅入深系统地整理一些关于消息队列的知识,这里从为什么用或为什么不用消息队列开始。
为什么要用消息队列
1. 异步
想象一种场景,一个有订阅功能的博客平台,一个作者有100w个订阅者(好羡慕这样的大V),这位大V一但发布了新博客,需要给这100w位订阅者发提醒邮件。大V的在编辑完博客,点击提交的时候需要做两件事,一个是最基础的保存博客内容,第二个是要给订阅者发邮件。如果两个操作都要在提交请求中同步处理,大V点完提交可能要等到花谢才能收到响应。这种场景就特别适合放到队列中处理,保存完提交的博客内容,不在请求里做真实的发邮件操作,而是把发邮件任务那到队列异步处理,直接响应请求,这样就可以大大减少请求耗时。
2. 压力缓冲
还是上面的例子,如果现在平台举办活动,发文章赢大奖,导致瞬间大量的文章发布,每一篇文章的发布都意味着至少一次的数据库操作,而且是写操作,都要在主库执行,极端情况下可能会把数据库压垮。这时候假如对发文章没有严格的实时性要求,我们也可以把文章内容入库这个操作也放入队列,从并发入库变成顺序入库,这样就把数据瞬时的高并发写变成了一段时间内的均匀写库。
除上述两点外,当然还可以业务解耦等很多优点,这里不再细说。
为什么不用消息队列
消息队列的也存在着明显的缺点:
1. 不能保证实时性
用消息队列来处理文章入库,需要首先和MQ通信,把内容写到MQ中,可能需要MQ内部的各种路由,最后再交给下游的消费者来做真实的入库操作,同时如果有很多消息待处理,还要再加上排队等待处理的时间,算下来肯定要比实时处理延时很大。
2. 执行顺序问题
异步是把双刃剑,带来快速响应的同时,也会导致编码上的复杂性,也有一些并发问题不注意的话会导致奇怪的问题。假如有这样一个场景,发文章时需要做:1. 入库 2. 通知,现在这两个操作都分别是放入了各自的队列里异步处理,有可能会出现这样的现象:通知已经发完了,文章内容还没有入库。
3. 处理结果问题
还是上面发文章的例子,文章内容入库异步处理,返回给用户的只是入队列是否成功,并不代表真实入库的成功。所以放入队列的任务要确保执行成功或将处理结果回调,如果是需要将结果回调的场景,恰好处理失败,但是之前入队列时已经返回用户了处理成功,这种情况需要确定如果处理。需要确保成功的场景可能就要为此引入重试等更复杂的逻辑,重试又会带来处理逻辑幂等的要求(多次处理不会产生问题,如果包含redis的incrodwv的操作,就会产生问题),这些都会增加代码的复杂度。
总之,消息队列在一些场景下必需要用,也有场景是不需要使用,用的话需要关注带来的各种问题要如果避免或者如何处理。
领取专属 10元无门槛券
私享最新 技术干货