消息中间件在高并发业务场景中占有非常重要的地位。其中,国内Java实现的典型代表RocketMQ是需要掌握的。本文主要关注以下五点:1.RocketMQ简介2.RocketMQ技术演进3.RocketMQ架构设计4.RocketMQ核心特性5.RocketMQ应用场景RocketMQ简介RocketMQ是一个纯java,分布式,队列model开源消息中间件,原名MetaQ,是阿里开发的队列模型消息中间件。后来开源给Apache基金会,成为Apache的顶级开源项目。它具有高性能、高可靠性、高实时性和分布式的特点。RocketMQ的演进RocketMQ经历了三代的演进:1.第一代,推送方式的数据存储使用关系型数据库,典型代表有Notify和Napoli。2、第二代,自研专有消息存储pull方式,日志处理方面参考Kafka,典型代表是MetaQ。3、第三代,主要基于pull模式,也有push模式的低延迟消息引擎RocketMQ。基于二代的功能特点,在电商金融领域增加了基于文件存储的可靠重试和分布式交易。特征。已经在阿里的大量应用中使用,比如双十一场景,新闻流量上万亿。RocketMQ的架构设计1.RocketMQ的核心组件RocketMQ主要由四部分组成:NameServer、Broker、Producer和Consumer。1)NameServer:主要负责源数据的管理,包括Topic和路由信息的管理。NameServer是一个功能完备的服务器,其作用类似于Dubbo中的Zookeeper,但NameServer比Zookeeper轻量级。主要原因是各个NameServer节点相互独立,没有任何信息交互。备注:以下消息类型由Topic引入。2)生产者消息生产者负责生成消息,一般业务系统负责生成消息。Producer由用户分布式部署,消息由Producer通过多种负载均衡方式发送给Broker集群,延迟低,故障快。3)Broker消息中转角色,负责存储消息和转发消息。Broker是专门提供服务的服务器。单个Broker节点与所有NameServer节点保持长连接和心跳,定期向NameServer注册Topic信息。对了,底层的通信和连接都是基于Netty的。Broker负责消息的存储,支持以Topic为纬度的轻量级队列。单机可支持上万个队列,支持消息推拉模型。官网数据显示,其具备亿级消息积累能力,同时能够严格保证消息的顺序。4)Consumer消息消费者,负责消费消息,一般后台系统负责异步消费。Consumer同样由用户部署,支持PUSH和PULL消费模式,支持集群消费和广播消息,提供实时消息订阅机制。5)一般流程Broker在启动时会向NameServer注册并定时发送心跳。当Producer启动后,会去NameServer拉取Topic所属Broker的具体地址,然后向具体的Broker发送消息。具体如下:2、RocketMQ的消息域模型主要分为Message、Topic、Queue、Offset和Group。1)TopicTopic代表第一级新闻类型。例如电子商务系统的消息可以分为:交易消息、物流消息等,一条消息必须有一个Topic。最细粒度的订阅单元,一个Group可以订阅多个Topic的消息。2)TagTag表示消息的二级类型,例如事务消息可以分为:事务创建消息、事务完成消息等。RocketMQ提供二级消息分类,方便灵活控制。3)Group组,一个组可以订阅多个Topic。4)MessageQueue消息的物理管理单元。一个Topic下可以有多个Queue。Queues的引入实现了消息存储的分布式集群化,实现了水平扩展。在RocketMQ中,所有的消息队列都是持久化的数据结构,长度不限。所谓无限长就是队列中的每个存储单元都是固定长度的,其中的存储单元是使用Offset访问的,Offset是javalong类型,64位,理论上100年内不会溢出,所以认为是无限长。也可以认为MessageQueue是一个无限长的数组,Offset是下标。RocketMQ的主要特点1.消息的顺序消息的顺序是指在消费消息时,可以按照消息发送的顺序消费。例如:一个订单生成3条消息,分别是订单创建、订单支付、订单完成。消费的时候,只有按照这个顺序消费才有意义。但同时订单可以并行消费。RocketMQ通过发送“相同ID的消息到同一个队列,一个队列的消息只被一个消费者处理”来实现顺序消息。如下图所示:这样就保证了同一个订单的创建、支付、完成消息都在这个订单中发送和消费。2.消息重复1)消息重复的原因消息字段有消息传递的QoS定义,分为:至多一次(Atmostonce)、至少一次(Atatleastonce)仅一次(Exactlyonce)QoS:QualityofService,服务质量几乎所有的MQ产品都声称是Atleastonce。由于是至少一次,消息重复是不可避免的,尤其是在分布式网络环境中。例如:网络暂时断开,ACK返回失败等,没有向消息队列发送确认信息,导致消息队列不知道自己已经消费了该消息,将消息分发给其他又是消费者。不同的消息队列以不同的形式发送确认信息。比如RabbitMQ发送一个ACK确认报文,RocketMQ返回一个CONSUME_SUCCESS成功标志,而Kafka其实有offset的概念。RocketMQ没有内置消息去重方案,需要确认最新版本是否支持。2)消息去重a.去重原则:利用业务端逻辑保持幂等性幂等性:即用户对同一个操作发起一次请求或多次请求的结果是一致的,不会因为多次点击而产生无副作用的数据库结果是唯一且不可变的。只要保持幂等性,无论有多少重复的消息过来,最终的处理结果都是一样的,这需要业务方去实现。b.去重策略:保证每条消息都有唯一的编号(比如唯一的序号),保证成功的消息处理和去重表的日志同时出现。创建消息表,获取消息做数据库的插入操作。为这条消息做一个唯一的主键(primarykey)或者唯一约束,那么即使有重复消费,也会造成主键冲突,那么这条消息将不会被处理。RocketMQ的应用场景1.削峰填谷例如秒杀等大规模活动会带来高流量脉冲。如果不做相应的保护,系统就会过载甚至死机。如果由于限制过多导致大量请求失败影响用户体验,可以使用MQ超高性能的消息处理能力来解决问题。2.异步解耦通过上下游业务系统的松耦合设计,例如交易系统下游子系统(如积分等)不可用甚至宕机,也不会影响交易系统的正常运行核心交易系统。3.顺序消息类似于FIFO原则。MQ提供的时序消息保证了消息的先进先出,可应用于交易系统中的订单创建、支付、退款等流程。4、分布式事务消息如阿里的交易系统、支付红包等场景需要保证数据的最终一致性,需要引入MQ的分布式事务,既实现了系统间的解耦,又保证了最终的数据一致性。将大事务拆分成小事务,减少系统间的交互,高效可靠。然后利用MQ的可靠传输和多副本技术保证消息不丢失,At-Least-Once特性最终保证了数据的最终一致性。
