消息中间件需要解决哪些问题

(1)Publis/Subscribe

发布订阅是消息中间件的最基本功能,是相对于传统的RPC通信而言。

(2)Message Priority

规范中描述的优先级是指在一个消息队列中,每条消息都有不同的优先级,一般用整数来描述,优先级高的信息先投递,如果消息完全在一个内存队列中,那么在投递前可以按照优先级排序,令优先级高的先投递。

由于RocketMQ所有的消息都是持久化的,所以如果按照优先级排序,开销会非常大,因此RockeMQ没有特意支持消息优先级,但是可以通过变通的方式实现类似的功能,即单独配置一个优先级高的队列和一个普通优先级的队列。将不同优先级发送到不同队列即可、

对于优先级问题,归纳为2类:

a、只要达到优先级目的即可,不是严格意义上的优先级,通常优先级划分为高中低或者更多,每个优先级可以用不同的topic表示,发消息时,指定不同的topic表示优先级,这种方式可以解决绝大部分的优先级问题,但是对业务的优先级精确性做了妥协。
b、严格优先级,优先级用整数表示,如0-65535,这种优先级问题如果用topic解决就不行,如果要MQ解决,会对MQ的性能造成非常大的影响。

(3)Message Order

消息有序指的是一类消息消费时,按照发送的顺序来消费,例如一个订单产生了3条消息,分别是订单创建,订单付款,订单完成,消费时,必须按照这个顺序才有意义,但同时订单之间是可以并行消费的。

RocketMQ是可以严格保证消息有序。


(4)Message Filter

   Broker端过滤消息,在Broker中,按照Consumer的要求做过滤,优点是减少了对于Consumer无用消息进行网络传输,缺点是增加了Broker的负担,实现相对复杂。

    (a)淘宝Notify支持多种过滤方式,包括直接按照消息类型过滤,灵活的语法表达式过滤,几乎可以满足最苛刻过滤要求、

   (b)淘宝RocketMQ支持按照简单的Message Tag过滤,也支持按照Message Header、body进行过滤、

consumer端消息过滤

   这种过滤方式可由应用完全自定义实现,缺点是很多无用消息要传输到Consumer端。

(5)Message Persistence

消息中间件通常采用几种持久化方式:

(1)持久化到数据库,例如MySql

(2)持久化到KV存储

(3)文件记录形式持久化

(4)对内存数据做一个持久化镜像

(1)(2)(3)三中持久化方式都具有将内存队列Buffer进行扩展的能力,(4)只是一个内存的镜像,作用是当Broker挂掉重启后仍然能将之前内存的数据恢复出来。

RocketMQ 参考了Kafka的持久化方式,充分利用Linux文件系统内存Cache来提高性能。


(6)Message Reliablity

影响消息可靠性的几种情况:

(1)Broker正常关闭

(2)Broker异常Crash

(3)OS Crash

(4)机器掉电,但是能立即恢复供电情况、

(5)机器无法开机

(6)磁盘设备损坏

1、2、3、4都属于硬件资源可立即恢复情况,RocketMQ在这四种情况下能保证消息不丢,或者丢失少量数据(依赖刷盘方式是异步还是同步)

5、6属于单点故障,且无法恢复,一旦发生,在此单点上的消息全部丢失,RocketMQ在这两种情况下,通过异步复制,可保证99%的消息不丢,但是仍然会有极少量的消息可能丢失,通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与钱相关的应用。

RocketMQ从3.0开始支持同步双写。


(7)Low Latency Messaging

在消息不堆积的情况下,消息到达Broker后,能立刻到达Consumer。

RocketMQ使用长轮询Pull方式,可保证消息非常实时,消息实时性不低于Push.

(8)At least Once

指每个消息必须投递一次

RocektMQ consumer 先pull消息到本地,消费完成后,才想服务器返回ack,如果没有消费一定不会ack,所以RocketMQ可以很好支持此特性。

(9)Exactly Only Once

(a)发送消息阶段,不允许发送重复的消息

(b)消费消息阶段,不允许消费重复的消息。

只有以上两个条件都满足的情况下,才认为消息是“Exactly only once”,而要实现以上两点,在分布式环境下,不可避免要产生巨大的开销,所以RocketMQ为了追求高性能,并不保证此特性,要求在业务上进行去重,也就是消费消息要做到幂等性,RocketMQ虽然不能严格保证不重复,但是正常情况下,很少会出现重复发送,消费的情况,只有网络异常,Consumer启停等异常情况下会出现消息重复。

此问题本质原因是网络调用存在不确定性,导致出现既不成功也不失败的第三种状态,所以才产生了消息重复性问题。


(10)Broker的Buffer满了怎么办

Broker的Buffer指的是Broker中一个队列的内存Buffer大小,这类Buffer通常大小有限,若Buffer满了怎么办?

CORBA Notification规范中处理方式:

(1)RejectNewEvents 拒绝新来的消息,向Producer返回RejectNewEvents错误码。

(2)按照特定策略丢弃已有的消息


RocketMQ没有内存Buffer概念,RocketMQ的队列都是持久化磁盘,数据定期清除。

对于此问题的解决思路,RocketMQ同其他MQ有非常显著的区别,RocketMQ内存Buffer抽象成一个无限长度的队列,不管有多少数据进来都能装的进来,这个无限是有前提的,Broker会定期删除过期的数据,例如Broker只会保存3天的消息,那么这个Buffer虽然长度无限,但是3天前的数据会被从队尾删除。

(11)回溯消息

回溯消息是指Consumer已经消费成功的消息,由于业务上需求需要重新消费,要支持此功能,Broker在向Consumer投递成功消息后,消息仍然需要保留,并且重新消费一般是按照时间维度,例如由于Consumer系统故障,恢复后需要重新消费1小时前的数据,那么Broker要提供一种机制,可以按照时间维度来回退消费进度。

RocketMQ支持按照时间回溯消费,时间维度精确到毫秒,可以向前回溯,也可以向后回溯。


(12)消息堆积

消息中间件的主要功能是异步解耦,还有个重要功能是挡住前端的数据洪峰,保证后端系统的稳定性,这就要求消息中间件有一定的消息堆积能力,消息堆积分以下两种情况:
(a)消息堆积在内存Buffer,一旦超过内存Buffer,可以根据一定的丢弃策略来丢弃消息。

(b)消息堆积到持久化存储系统中,例如DB,KV,文件记录形式。

当消息不能在内存cache命中时,要不可避免的访问磁盘,会产生大量读IO,读IO的吞吐量直接决定了消息堆积后的访问能力

(13)分布式事务

分布式事务涉及到两阶段提交问题,在数据存储方面必然需要支持KV存储的支持,因为第二阶段的提交回滚需要修改消息状态,一定涉及到根据key去查找Message动作,RocketMQ在第二阶段绕过了根据key去查找Message的问题,采用第一阶段发送Prepared消息时,拿到了消息的offset,第二阶段通过offset去访问消息,并修改状态,offset就是数据的地址。

RocketMQ这种实现事务方式,没有通过KV存储做,而是通过offset方式,存在一个显著的缺陷,即通过offset更改数据,会令系统的脏页过多,需要特别关注。

(14)定时消息

定时消息指消息发送到Broker后,不能立刻被Consumer消费,要到特定的时间点或者特定的时间后才能被消费。

如果要支持任意的时间精度,在Broker层面,必须要做消息排序,如果在涉及到持久化,那么消息排序要不可避免产生巨大性能开销。

RocketMQ支持定时消息,但是不支持任意时间精度,支持特定的level1

(15)消息重试

Consumer消费消息失败后,要提供一种重试机制,令消息在消费一次,consumer消费消息失败通常可以认为以下几种情况:

1、由于消息本身的原因,例如反序列化失败,消息数据本身无法处理(如充话费,当前消息的手机号被注销,无法充值),这种错误通常需要跳过这条消息,再消费其他消息,而这条失败的消息即使立刻重试消费,99%也不成功,所以最好提供一种定时重试机制,即过10s在重试。

2、由于依赖的下游应用服务不可用,例如db连接不可用,外系统网络不可到达

遇到这种错误,即使跳过当前失败消息,消费其他消息同样也会报错,这种情况建议应用sleep 30s,再消费下一条消息,这样可以减轻Broker重试消息的压力。




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值