RocketMQ消息发送和消息消费

消息发送

在RocketMQ中生产者向消息队列里写入消息,不同的业务场景需要生产者采用不同的写入策略。

比如同步发送、异步发送、Oneway发送、延迟发送、发送事务消息等。

消息发送步骤

默认使用的是DefaultMQProducer类,发送消息要经过五个步骤

  • 1)设置Producer的GroupName(生产组)。

  • 2)设置InstanceName(实例名称),当一个Jvm需要启动多个Producer的时候,通过设置不同的InstanceName来区分,不设置的话系统使用默认名称“DEFAULT”。

  • 3)设置发送失败重试次数,当网络出现异常的时候,这个次数影响消息的重复投递次数。想保证不丢消息,可以设置多重试几次。

  • 4)设置NameServer地址

  • 5)组装消息并发送。

消息发生返回状态

消息发生返回状态(SendResult#SendStatus)有如下四种:

  • FLUSH_DISK_TIMEOUT

表示没有在规定时间内完成刷盘(需要Broker的刷盘策略被设置成SYNC_FLUSH才会报这个错误)。

  • FLUSH_SLAVE_TIMEOUT

表示在主备方式下,并且Broker被设置成SYNC_MASTER方式,没有在设定时间内完成主从同步。

  • SLAVE_NOT_AVAILABLE

这个状态产生的场景和FLUSH_SLAVE_TIMEOUT类似,表示在主备方式下,并且Broker被设置成SYNC_MASTER,但是没有找到被配置成Slave的Broker。

  • SEND_OK

表示发送成功,发送成功的具体含义,比如消息是否已经被存储到磁盘?消息是否被同步到了Slave上?消息在Slave上是否被写入磁盘?需要结合所配置的刷盘策略、主从策略来定。这个状态还可以简单理解为,没有发生上面列出的三个问题状态就是SEND_OK

如何提升写入的性能

发送一条消息出去要经过三步

  • 1.客户端发送请求到服务器。
  • 2.服务器处理该请求。
  • 3.服务器向客户端返回应答

一次消息的发送耗时是上述三个步骤的总和。

Oneway方式发送

Oneway方式发送在一些对速度要求高,但是可靠性要求不高的场景下,比如日志收集类应用,可以采用。

Oneway方式只发送请求不等待应答,即将数据写入客户端的Socket缓冲区就返回,不等待对方返回结果。

用这种方式发送消息的耗时可以缩短到微秒级。

增加Producer的并发量,使用多个Producer同时发送

RocketMQ引入了一个并发窗口,在窗口内消息可以并发地写入DirectMem中,然后异步地将连续一段无空洞的数据刷入文件系统当中。

顺序写CommitLog可让RocketMQ无论在HDD还是SSD磁盘情况下都能保持较高的写入性能。

目前在阿里内部经过调优的服务器上,写入性能达到90万+的TPS,我们可以参考这个数据进行系统优化。

在Linux操作系统层级进行调优,推荐使用EXT4文件系统,IO调度算法使用deadline算法。

消息消费

消息消费主要包括如下几个部分

  • 1.消息消费方式(Pull和Push)
  • 2.消息消费的模式(广播模式和集群模式)
  • 3.流量控制(可以结合sentinel来实现,后面单独讲)
  • 4.并发线程数设置
  • 5.消息的过滤(Tag、Key)TagA||TagB||TagC * null

消费模式Push or Pull

RocketMQ消息订阅有两种模式,一种是Push模式(MQPushConsumer),即MQServer主动向消费端推送;另外一种是Pull模式(MQPullConsumer),即消费端在需要时,主动到MQ Server拉取。但在具体实现时,Push和Pull模式本质都是采用消费端主动拉取的方式,即consumer轮询从broker拉取消息。

  • push

好处就是实时性高。不好处在于消费端的处理能力有限,当瞬间推送很多消息给消费端时,容易造成消费端的消息积压,严重时会压垮客户端。

  • pull

好处就是主动权掌握在消费端自己手中,根据自己的处理能力量力而行。缺点就是如何控制Pull的频率。定时间隔太久担心影响时效性,间隔太短担心做太多“无用功”浪费资源。比较折中的办法就是长轮询。

  • Push模式与Pull模式的区别

Push方式里,consumer把长轮询的动作封装了,并注册MessageListener监听器,取到消息后,唤醒MessageListener的consumeMessage()来消费,对用户而言,感觉消息是被推送过来的。

Pull方式里,取消息的过程需要用户自己主动调用,首先通过打算消费的Topic拿到MessageQueue的集合,遍历MessageQueue集合,然后针对每个MessageQueue批量取消息,一次取完后,记录该队列下一次要取的开始offset,直到取完了,再换另一个MessageQueue。

提高Consumer的处理能力

  • 1.提高消费并行度

同一个ConsumerGroup下(Clustering方式),可以通过增加Consumer实例的数量来提高并行度。

通过加机器,或者在已有机器中启动多个Consumer进程都可以增加Consumer实例数。

注意:总的Consumer数量不要超过Topic下Read Queue数量,超过的Consumer实例接收不到消息。

此外,通过提高单个Consumer实例中的并行处理的线程数,可以在同一个Consumer内增加并行度来提高吞吐量(设置方法是修改consumeThreadMin和consumeThreadMax)。

  • 2.以批量方式进行消费

某些业务场景下,多条消息同时处理的时间会大大小于逐个处理的时间总和,比如消费消息中涉及update某个数据库,一次update10条的时间会大大小于十次update1条数据的时间。

可以通过批量方式消费来提高消费的吞吐量。实现方法是设置Consumer的consumeMessageBatchMaxSize这个参数,默认是1,如果设置为N,在消息多的时候每次收到的是个长度为N的消息链表。

  • 3.检测延时情况,跳过非重要消息

Consumer在消费的过程中,如果发现由于某种原因发生严重的消息堆积,短时间无法消除堆积,这个时候可以选择丢弃不重要的消息,使Consumer尽快追上Producer的进度。