《消息队列高手课》笔记(1)

第一课:01 | 为什么需要消息队列?

总结

一、哪些问题适合使用消息队列来解决?

1. 异步处理

  可以更快地返回结果;

  减少等待,自然实现了步骤之间的并发,提升系统总体的性能。

2. 流量控制

  1)使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。

  2)用消息队列实现一个令牌桶,更简单地进行流量控制。

3. 服务解耦

思考题

1、在你工作或学习涉及到的系统中,哪些问题可以通过引入消息队列来解决?

1.数据同步:包括业务服务之间的业务数据同步(主要是状态)、DB间的数据同步等等

2.异步通知:包括发送IM消息、异步日志、异步短信/邮件(尤其是批量数据)或注册/开启任务等等

3.信息收集:主要用于数据统计、监控、搜索引擎等等

4.服务解耦:主要用于重构和新设计时,对频繁变动的接口服务进行解耦(通常是被需求给逼的)

5.分布式事务消息:尤其是对数据一致性有要求的异步处理场景

6.主动性防御:秒杀、限流

 

 

第二课:02 | 该如何选择消息队列?

总结

选择中间件的考量维度:可靠性,性能,功能,可运维行,可拓展性,是否开源及社区活跃度

rabbitmq:

优点:轻量,迅捷,容易部署和使用,拥有灵活的路由配置

缺点:性能和吞吐量较差,不易进行二次开发

rocketmq:

优点:性能好,稳定可靠,有活跃的中文社区,特点响应快

缺点:兼容性较差,但随意影响力的扩大,该问题会有改善

kafka:

优点:拥有强大的性能及吞吐量,兼容性很好

缺点:由于“攒一波再处理”导致延迟比较高

pulsar:

采用存储和计算分离的设计,是消息队里产品中黑马,值得持续关注

 

第三课:03 | 消息模型:主题和队列有什么区别?

总结

见答疑解惑

 

第四课:04 | 如何利用事务消息实现分布式事务?

总结

一、消息队列中的“事务”,主要解决的是消息生产者和消息消费者的数据一致性问题。

二、分布式事务

1)2PC(Two-phase Commit,也叫二阶段提交)

2)TCC(Try-Confirm-Cancel) 和事务消息

三、RocketMQ 中的分布式事务实现

通用事务消息的实现和 RocketMQ 的事务反查机制

 

 

第五课:05 | 如何确保消息不会丢失?

总结

一、检测消息丢失的方法

  1)我们可以利用消息队列的有序性来验证是否有消息丢失。

    原理非常简单,在 Producer 端,我们给每个发出的消息附加一个连续递增的序号,然后在 Consumer 端来检查这个序号的连续性。

二、确保消息可靠传递

1. 生产阶段

  在编写发送消息代码时,需要注意,正确处理返回值或者捕获异常,就可以保证这个阶段的消息不会丢失

2. 存储阶段

  如果对消息的可靠性要求非常高,可以通过配置 Broker 参数来避免因为宕机丢消息。

3. 消费阶段

  不要在收到消息后就立即发送消费确认,而是应该在执行完所有消费业务逻辑之后,再发送消费确认。

思考

1、如何确保消息不丢失?在消费消息的代码中,该如何处理这种重复消息,才不会影响业务逻辑的正确性

答:

1)如何确保消息不会丢失

1:WAL

2:分布式WAL

除非地球爆炸,否则问题不大。

猜测各种消息队列或者数据库,确保消息不丢只能这么玩,就连人也一样,脑袋记不住那就写下来,怕本子弄潮啦!那就光盘、U盘、磁盘、布头、木头、石头北京、上海、深圳都各写一份。

2)consumer接到重复消息,那就业务去重,怎么去?

1:业务处理逻辑本身就是幂等的,那天然就去掉了

2:业务处理逻辑非幂等,那就消息先去重,根据业务ID(标识消息唯一性的就行),去查询是否消费过此消息了,消费了,则抛弃,否则就消费

 

第六课:06 | 如何处理消费过程中的重复消息?

总结

一、消息重复的情况必然存在

在 MQTT 协议中,给出了三种传递消息时能够提供的服务质量标准,这三种服务质量从低到高依次是:

  • At most once: 至多一次。消息在传递时,最多会被送达一次。换一个说法就是,没什么消息可靠性保证,允许丢消息。一般都是一些对消息可靠性要求不太高的监控场景使用,比如每分钟上报一次机房温度数据,可以接受数据少量丢失。
  • At least once: 至少一次。消息在传递时,至少会被送达一次。也就是说,不允许丢消息,但是允许有少量重复消息出现。
  • Exactly once:恰好一次。消息在传递时,只会被送达一次,不允许丢失也不允许重复,这个是最高的等级。

二、用幂等性解决重复消息问题

从对系统的影响结果来说:At least once + 幂等消费 = Exactly once。

三、常用的设计幂等操作的方法

1. 利用数据库的唯一约束实现幂等

2. 为更新的数据设置前置条件

3. 记录并检查操作

  记录并检查操作,也称为“Token 机制或者 GUID(全局唯一 ID)机制”。

  实现的思路特别简单:在执行数据更新操作之前,先检查一下是否执行过这个更新操作。具体的实现方法是,在发送消息时,给每条消息指定一个全局唯一的 ID,消费时,先根据这个 ID 检查这条消息是否有被消费过,如果没有消费过,才更新数据,然后将消费状态置为已消费。

思考题

1、为什么大部分消息队列都选择只提供 At least once 的服务质量,而不是级别更高的 Exactly once 呢?

答:

1)解决一个问题,往往会引发别的问题。若消息队列实现了exactly once,会引发的问题有:①消费端在pull消息时,需要检测此消息是否被消费,这个检测机制无疑会拉低消息消费的速度。可以预想到,随着消息的剧增,消费性能势必会急剧下降,导致消息积压;②检查机制还需要业务端去配合实现,若一条消息长时间未返回ack,消息队列需要去回调看下消费结果(这个类似于事物消息的回查机制)。这样就会增加业务端的压力,与很多的未知因素。 所以,消息队列不实现exactly once,而是at least once + 幂等性,这个幂等性让给我们去处理

2)最重要的原因是消息队列即使做到了Exactly once级别,consumer也还是要做幂等。因为在consumer从消息队列取消息这里,如果consumer消费成功,但是ack失败,consumer还是会取到重复的消息,所以消息队列花大力气做成Exactly once并不能解决业务侧消息重复的问题。

 

第六课:07 | 消息积压了该如何处理?

总结

一、如何预防消息积压?

 

如果说,你的代码发送消息的性能上不去,你需要优先检查一下,是不是发消息之前的业务逻辑耗时太多导致的。

1、发送端提高并发及批量大小;
2、消费端增加实例且同步宽容分区;

二、如何处理消息积压?

一定要保证消费端的消费性能要高于生产端的发送性能,这样的系统才能健康的持续运行。

1、消费端扩容;

2、服务降级;

3、异常监控。

思考题

1、在消费端是否可以通过批量消费的方式来提升消费性能?在什么样场景下,适合使用这种方法?或者说,这种方法有什么局限性?

答:

1、要求消费端能够批量处理或者开启多线程进行单条处理

2、批量消费一旦某一条数据消费失败会导致整批数据重复消费

3、对实时性要求不能太高,批量消费需要Broker积累到一定消费数据才会发送到Consumer

posted @ 2023-02-28 22:57  r1-12king  阅读(33)  评论(0编辑  收藏  举报