让开发
成为一种享受!

2020 RocketMQ 面试题整理

为什么要使用消息队列

解耦、异步、削峰

常用MQ对比

特性ActiveMQRabbitMQRocketMQkafka
开发语言javaerlangjavascala
单机吞吐量万级万级10万级10万级
时效性ms级us级ms级ms级以内
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
功能特性成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富MQ功能比较完备,扩展性佳只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。

RocketMQ基本概念

  • Producer:消息生产者,负责产生消息,一般由业务系统负责生产消息
  • COnsumer:消息消费者,负责消费消息,一般是后台系统负责异步消费
  • Push Consumer:封装消息拉取
  • Pull Consumer:主动拉取消息,一旦拉取到消息,应用的消费进程进行初始化
  • Producer Group:一类Producer的集合名称,这类Producer通常发送一类消息,且发送逻辑一致
  • Consumer Group:一类Consumer的集合名称,这类Consumer通常消费一类消息,且消费逻辑一致
  • Broker:消息中转角色,负责存储消息,转发消息,这里就是RocketMQ Server
  • Topic:消息的主题,用于定义并在服务端配置,消费者可以按照主题进行订阅,也就是消息分类,通常一个系统一个Topic
  • Message:在生产者、消费者、服务器之间传递的消息,一个message必须属于一个Topic
  • Namesrv:一个无状态的名称服务,可以集群部署,没一个broker启动的时候都会向名称服务器注册,主要是接收broker的注册,接收客户端的路由请求并返回路由信息
  • Offset:偏移量,消费者拉取消息时需要知道上一次消费到了什么位置,这一次从哪里开始
  • Partition:分区,topic物理上的分组,一个topic可以分为多个分区,每个分区是一个有序的队列。分区中的每条消息都会给分配一个有序的ID,也就是偏移量。
  • Tag:用于对消息进行过滤,理解为message的标记,同一业务不同目的的message可以用相同的topic但是可以用不同的tag来区分
  • key:消息的KEY字段是为了唯一表示消息的,方便查问题,不是说必须设置,只是说设置为了方便开发和运维定位问题。比如:这个KEY可以使订单ID等

RocketMQ角色

  • Producer:消息生产者
  • Consumer:消费者
  • Broker:MQ服务,负责接收、分发消息
  • NameServer:负责MQ服务之间的协调

顺序消息有哪些实现方式?

  • 全局顺序一个topic内所有消息都发布到同一个queue,按照先进先出的顺序进行发布和消费。适用于性能要求不高,所有的消息严格按照FIFO原则进行消息发布和消费的场景。
  • 分区顺序对于指定的一个topic,所有消息根据sharding key进行区块(queue)分区,同一个queue内的消息严格按照FIFO原则进行消息发布和消费。sharding key是顺序消息中用来区分不同分区的关键字段,和普通消息的key是完全不同的概念。

如何保证消息顺序

  • 消息被发送时保持顺序
  • 消息被存储时保持和发送的顺序一致
  • 消息被消费时保持和存储的顺序一致

RocketMQ事务消息设计

Producer最佳实践

1. 一个应用尽可能用一个Topic,消息子类型用tags来标识,tags可以用应用自由设置 只有发送消息设置了tags,消费方在订阅消息时,才可以利用tags在broker做消息过滤

message.setTags("TagA");

2. 每个消息在业务层面的唯一标识码,要设置到keys字段,方便将来定位消息丢失问题 服务器会为每个消息创城索引(哈希索引),应用可以通过topic,key来查询这条消息内容,以及消息被谁消费。由于是哈希索引,请务必保证key尽可能唯一,这样可以避免潜在的哈希冲突。

// 订单ID
String orderId = "123443234322332";
message.setKeys(orderId);

3. 如有可靠性需要,消息发送成果或者失败,要打印消息日志(sendresult和key信息)

4. 如果相同性质的消息量大,使用批量消息,可以提升性能

5. 建议消息大小不超过512KB

6. send(msg)会阻塞,如果有性能要求,可以使用异步的方式:send(msg, callback)

7. 如果再一个JVM中,有多个生产者进行大数据处理,建议:

  • 少数生产者使用异步发送方式(3~5个就够了)
  • 通过setInstanceName方法,给每个生产者设置一个实例名

8. send消息方法,只要不抛异常,就代表消息发送成功。但是发送成功会有多个状态,在sendResult里定义

  • SEND_OK:消息发送成功
  • FLUSH_DISK_TIMEOUT:消息发送成功,但是服务器刷盘超时,消息已经进入服务器队列,只有此时服务器宕机,消息才会丢失
  • FLUSH_SLAVE_TIMEOUT:消息发送成功,但是服务器同步到Slave时超时,消息已经进入服务器队列,只有此时服务器宕机,消息才会丢失。
  • SLAVE_NOT_AUAILABLE:消息发送成功,但是此时slave不可用,消息已经进入服务器队列,只有此时服务器宕机,消息才会丢失。
  • 如果状态是FLUSH_DISK_TIMEOUT或FLUSH_SLAVE_TIMEOUT,并且Broker正好关闭,此时,可以丢弃这条消息,或者重发。但建议最好重发,由消费端去重。
  • Producer想Broker发送请求会等待响应,但如果达到最大等待时间,未得到响应,则客户端将抛出RemotingTimeoutException。默认等待时间是3秒,如果使用send(msg, timeout),则可以自己设定超时时间,但超时时间不能设置太小,因为Broker需要一些时间来刷新磁盘或与从属设备同步。如果该值超过syncFlushTimeout,则该值可能影响不大,因为Broker可能会在超时之前返回FLUSH_SLAVE_TIMEOUT或FLUSH_SLAVE_TIMEOUT的响应。

9. 对于消息不可丢失应用,务必要有消息重发机制 Producer的send方法本身支持内部重试:

  • 至多重试3次
  • 如果发送事变,则轮转到下一个Broker
  • 这个方法的总耗时时间不超过sendMsgTimeout设置的值,默认10s。所以,如果本身向broker发送消息产生超时异常,就不会再做重试。

以上策略仍然不能保证消息一定发送成功,为保证消息一定成功,建议将消息存储到DB,由后台线程定时重试,保证消息一定到大Broker

RocketMQ执行流程

  • 启动 Namesrv,Namesrv起来后监听端口,等待 Broker、Producer、Consumer 连上来,相当于一个路由控制中心。
  • Broker 启动,跟所有的 Namesrv 保持长连接,定时发送心跳包。
  • 收发消息前,先创建 Topic 。创建 Topic 时,需要指定该 Topic 要存储在 哪些 Broker上。也可以在发送消息时自动创建Topic。
  • Producer 发送消息。
  • Consumer 消费消息。

请说说你对Producer的了解?

扫码关注公众号:Java开发乐园

在聊天窗口回复:vip

输入验证码,即可永久解锁本站全部文章

扫码关注【Java开发乐园】

Java开发乐园

扫码关注【东方】

微信:东方

验证码:
赞(0) 打赏
转载请注明出处:Java开发乐园 » 2020 RocketMQ 面试题整理

来评论一下嘛~ 抢沙发

评论前必须登录!

 

我愿终生等候,换你刹那凝眸

留点🐾印

打赏即是一种肯定,谢谢您的肯定

支付宝扫一扫打赏

微信扫一扫打赏