开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情
消息队列使用场景:
解耦合
假设在如图的场景里面,bcd系统的完成需要依赖A系统,如果E也需要A系统,或者bcd不需要A系统了,那么A系统就会多写很多代码来保证这个结构。
在这个场景中,A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?看上去就很难了!
如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。
这个MQ有点类似我们之前学过的java的JDBC
在这里JDBCAPI就很像mq
其实就是把本来该A完成的代码放出去了,通过MQ存储,然后让其他系统自己去申请mq,从而减少A系统工作量。
并且我们知道,可以通过发布订阅消息来进行解耦,新加系统,通过继承或者实现我们基本类的订阅功能,然后就相当于自己申请了。
异步
当A系统接收到用户的一个请求时候,需要一条一条循环BCD进行备份,花费时间很长,但是加入mq后,我们A可以连续发送三条数据到mq,由mq分发给其他系统。
削峰
在进行秒杀操作的时候,很容易服务器挂掉,因为一瞬间大量请求会出现,超过服务器的最大接收范围。这时候加入mq,其实就是规定通过发送给服务器的数据范围,在服务器可接收的范围内。
缺点:
看到上面的优点,你可能会有这样的想法:
如果mq挂掉了,其他也不能运行,这不是把原来A的工作给了mq,没能解决问题啊?
这其实属于mq的高可用性解决里面的。
为了防止mq挂掉导致的系统崩溃,那么我们可以做备份,在每一次读写的时候,保证我们操作对象至少和一个备份对象相连。我们操作这个对象就叫他leader
写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)
消费的时候,只会从 leader 去读,但是只有当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。
可能你还想问:那我直接备份A不行吗?干嘛要另外来个mq
这看上去好像有道理,但是其实不行,因为A除了我们可以写入mq的还有其他内容,多次复制内存可能....(个人想法,可能是错误的)
系统复杂度提高了。
本来直接A-》B,现在在里面加入了mq,万一传递过程数据丢失怎么办?
以kafka为例子:就是 Kafka 某个 broker 宕机,然后重新选举 partition 的 leader。大家想想,要是此时其他的 follower 刚好还有些数据没有同步,结果此时 leader 挂了,然后选举某个 follower 成 leader 之后,不就少了一些数据?这就丢了一些数据啊。
所以我们需要设置mq:
- 每个topic必须至少两个副本
- 至少要有一个备份和自己联系才能往下走
- 必须写入所有当前数据才算成功,失败进行重传
重复数据
我们知道 MQ需要满足不多不少,怎么保证不少,我们可以备份重传,但是怎么处理重复数据?
比如我们要写入数据库:你先根据主键查一下,如果这数据都有了,你就别插入了,update 就行。
如果其他:需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,然后你这里消费到了之后,先根据这个 id 去比如 查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 入。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。