分布式消息中间件 ActiveMQ-秒杀阿里面试

本章重点:

1.消息发送源码分析

2.消费端源码分析

3.持久化存储支持的五种类型

4.prefetchSize原理

5.ActiveMQ优缺点及使用场景

消息中间件产生背景:

  1. 使用多线程可以实现异步化,并行处理数据;
  2. 使用MQ不仅满足多线程这些特点,因为它具有:异步,解耦,流量削峰,数据持久化存储,高性能,高可用,可伸缩特性,并且在弱一致性事务中,可以通过最大努力通知实现分布式事务的最终一致性。

从JMS规范来了解ActiveMQ

两种消息传递形式:

  1. 点对点:消息与消费者一一对应,异步消费。
  2. 发布订阅:每个消息可以有多个消费者,消费消息有时间上的相关性,只能消费 订阅之后发布的消息,可以利用持久订阅机制,降低时间上的相关性,持久订阅允许消费者消费没有订阅之前的数据。

什么是持久订阅和非持久订阅?

  1. 针对发布订阅模型,如果broker发送消息给未激活状态的订阅者,持久订阅可以接受到消息,但非持久订阅接收不到消息。
  2. 缺点是,在持久订阅模式下,broker需要为未激活状态的订阅者保存消息,可能会造成消息堆积过多溢出
  3. 持久订阅时,生产者向jms服务器注册自己的唯一id,当生产者处于离线状态时,jms Provider会为这个id保存所有发送到主题的消息,当生产者再次连接到jms provider的时候,生产者可以根据自己的id得到自己离线时发送到主题的消息。

JMS的可靠性机制

相当于寄快递,只有快递被签收,才认为快递送达成功,消息的消费包括三阶段:消息接收,消息处理,消息确认

消息结构组成

消息头:

  1.        消息发送的目的地,即队列或者主题
  2.        传送模式:即持久模式和非持久模式
  3.        消息优先级:0-9,默认优先级4
  4.        消息id:唯一识别的消息id

消息体格式:

       Text(文本),Map(键值对),Byte(字节),Stream(流),Object(对象).

JMS的事务性会话和非事务性会话

  1. 在创建session时候,可以通过true or false来指定事务还是非事务会话。
  2. 只有当commit的时候才将消息投递出去。

在非事务性会话中:

       消息的确认取决于应答模式:自动确认,手动确认,惰性确认。

消息的持久化存储和非持久化存储

  1. 持久化保证当broker宕机之后,消息不会丢失。
  2. 非持久化可能会导致mq故障,消息丢失情况。

Broker是什么?

消息队列的核心,控制中心,可以将消息路由,保存订阅者和连接信息。

怎么解决幂等性?

在消费端,通过判断消息的全局是否重复来解决幂等。

扫描二维码关注公众号,回复: 5946305 查看本文章

持久化消息与非持久化消息的发送策略

  1. 默认情况下,非持久化消息是异步的。持久化消息在非事务模式下是同步的。但在开启事务模式下都是异步的。
  2. 建议持久化消息开启事务进行异步发送,效率高。

消息发送机制原理

在异步发送时才有意义,生产者发送message会统计message字节数,当字节数大于窗口大小时,需要等待broker确认消息才能继续发送。

这是为了约束produce端允许积压的还未ACK的消息。

消息发送源码分析

1.以produce.send为入口:

         1.1.检查session状态

         1.2.检查destination类型

         1.3判断窗口大小是否为空

                  3.1不为空,则判断窗口大小决定是否阻塞

                  3.2为空,则直接send消息到broker的topic上

                          2.1使用互斥锁,保证一个session的多个produce发送消息的有序性

                          2.2告诉broker开启一个新的事务,只有事务型会话才开启

                          2.3从事务上下文中获取事务id

                          2.4在jms协议头中设置是否持久化

                          2.5计算消息过期时间

                          2.6设置消息过期时间、优先级、消息为非重发

                          2.7将不同格式统一转发为ActiveMQMessage

                           2.8设置目的地,并设置消息id

                          2.9如果消息经过转发,则跟新原来的消息id和目的地

                          3.0把消息属性和消息体都设置为只读,防止篡改

                           3.1判断消息走异步还是同步

                                   1.1异步的话,需要设置窗口大小

                                   1.2同步的话

                                            1.2.1调用带超时时间的同步发送

                                            1.2.2调用带回调的同步发送

其中transport在同步回调中被使用到了,这个对象通过transportFactory工厂去创建对象,在configura中进行了四层包装:

包装后可以实现:

  1. 异步请求
  2. 实现写锁,表示同一时间只能发送一个请求
  3. 实现客户端连接broker上进行解析版本号,是否使用缓存机制
  4. 实现心跳检查

持久化消息和非持久化消息的原理

  1. 非持久化消息堆积一定程度(内存超过指定的阈值)会写入dump文件中,以便腾出内存,重启mq消息会丢失。
  2. 持久化机制会持久化到硬盘,消息不会丢失。

持久化存储支持的五种类型

  1. KahaDB存储(默认存储方式):使用事务日志+索引文件(B-树记录地址)
  2. JDBC存储(创建三张表,消息表,锁表,ACK表(记录id和存储信息))
  3. Memory存储(非持久存储内存中)
  4. LevelDB存储(Zookeeper数据复制方式)
  5. JDBC With ActiveMQ Journal存储(使用缓存机制,减少数据写入DB过程)

消费端消费消息原理

1.消费端同步接收消息源码入口

         1.1检查reserve和MessageListener是否同时配置在当前会话中

         1.2如果prefetchSize大小为0并且unconsumerMessage为空,者发起pull命令

                  2.1在pull之前先清理已经分发的消息链表

         2.从unconsumerMessage队列中获取消息

                  2.1消费之前的准备工作

                           1.如果是事务类型的会话

                                   1.1单条消息直接返回ACK

                                   1.2否则惰性应答,消息缓存起来到一定阈值再统一ACK

                  2.2在获取消息之后

                           1.如果消息过期,则返回过期ACK

                          2.如果是事务类型会话,不做任何处理

                          3.如果是AUTO_ACK或者DUPS_OK_ACK且是队列,走优化ack(批量确认)

                          4.其它走惰性ACK

         3.发送ACK到broker

         4.获取消息并返回

数据的获取过程源码分析

1.	动态创建一个传输协议
2.	创建一个连接
3.	通过transport.start()
     a)	创建一个线程调用run()方法
     b)	从socket中循环读取数据包
     c)	对数据进行格式化,转为对象,传给ActiveMQConnection
     d)	通过transportListener来绑定ActiveMQConnection
     e)	消息从传送层到达我们的连接层
     f)	对线程池executer进行初始化
     g)	适配器模式对消息进行分发
       i.	如果会话不是异步分发且没有使用sessionPool分支
         1.	调用dispatcher来处理消息
         2.	异步直接将消息放入队列中
          a)	通过线程池去执行异步调用
           i.	把消费者所有监听的消息转存到消费队列
           ii.	如果消息队列还存有消息,同样把消息分发出去
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

消费端的prefetchSize与optimizeAcknowledge 原理

只有在开启优化下prefetchSize才有意义,使得客户端不必频繁地确认消息,减少通讯开销,批量获取消息,延迟确认。

消息的确认过程

自动确认,手动确认,自动批量确认,事务提交并确认

消息重发原理

  1. 事务会话中,事务未提交
  2. 非事务中,网络延迟重试,重试超过默认6次进入死信队列

ActiveMQ的优缺点

  1. ActiveMQ 采用消息推送方式,所以最适合的场景是默认消息都可在短时间内被消费。
  2. 数据量越大,查找和消费消息就越慢,消息积压程度与消息速度成反比。
  3. 吞吐量低。由于 ActiveMQ 需要建立索引,导致吞吐量下降
  4. 无分片功能。

适用场景 

对 TPS 要求比较低的系统,

猜你喜欢

转载自blog.csdn.net/qq_38357267/article/details/89397569
今日推荐