为什么要支持HTTP协议
- 复杂的逻辑:
RocketMQ的客户端逻辑相对较为复杂,使用私有协议进行通信。对于非Java语言的开发者来说,理解和实现RocketMQ的客户端可能会比较困难。通过支持HTTP协议,可以使用标准的HTTP协议进行通信,简化了客户端的逻辑复杂性。
- 非Java语言客户端的更新和兼容性
除了Java以为,其它语言的客户端是由社区提供并维护的,其更新不如Java客户端及时,可能存在一些已知的问题和Bug,并且兼容性可能较差。这就意味着,如果使用非Java语言的客户端出现生产和消费问题,需要有对该语言和RocketMQ原理都较为精通的人才能够进行故障排查和修复,从而增加了成本和难度。
- 缺乏特定语言的客户端
某些编程语言可能没有官方或者完善的RocketMQ客户端实现。这就限制了使用这些语言的开发者使用RocketMQ的能力。通过支持HTTP协议,可以将RocketMQ的消息发送和消费功能扩展到任何支持HTTP协议的编程语言,消除了特定语言客户端的依赖性。
实现HTTP协议的原理
HTTP接入相对于TCP SDK客户端的使用,需要解决客户端无状态消费的问题。对于使用SDK客户端来说,消费状态是由客户端维护的,包括队列重平衡、消费位点的起始位置,以及消费进度的更新等。而对于HTTP接入,客户端只管拉取消息,而不用管消息拉取位置、拉取队列,以及消费进度的更新。
对于以HTTP接入RocketMQ,主要有消息生产、消息消费接口,为了保证消费成功,提供消费确认接口,允许消费方主动ACK。
对于RocketMQ4.x和5x实现HTTP接入会有不同的实现,下面分别进行说明:
对于RocketMQ4.x版本:
客户端不维护状态信息,需要将状态上移到Proxy层,Proxy层依赖第三方基础服务(例如Redis、RocksDB等)做状态数据管理,包括消费者上下线、消费者的消费位点以及消费进度的管理等。一个消费者上线消费消息的流程为:
获取对应消费组的消费代理
选择合适的队列pull消息,在对队列拉取消息前,会对队列上锁,当前请求结束后,释放队列锁
客户端消费消息,消费完成后ACK消息,对应更新消费进度
总结为,Proxy层和Broker只是使用对应的API进行Pull拉取消息,并不会将消费组的消费进度等信息保存到Broker中,所有的关于消费组消费信息例如消费组队列已消费的Offset和已提交的Offset均存储在第三方基础服务中。
对于RocketMQ5.x版本:
5.0版本开始,RocketMQ开始引入新的消费模式[RIP 19] Server side rebalance, lightweight consumer client support,用于解决Pull消费模式下的如队列和消费者实例绑定、客户端重平衡、以及消费队列积压问题。
总结为5.x版本新增的POP消费模式,让原本的客户端变得非常轻量、无状态,并且不会独占队列,那么就可以在Proxy层基于POP消费模式,将原本需要自己实现的状态管理,交给Broker本身来做。另外其本身可以解决例如ACK消费空洞和消费超时等问题,如果是在4.x的RocketMQ版本上实现HTTP接入,需要自己实现解决这些问题。