(1.中国电子科技集团公司第28研究所 助理工程师 南京 210000 2.中国电子科技集团公司第28研究所 工程师 南京210000)
摘要:当前社会已然是属于大数据的社会,创新型互联网公司和迭代型各行各业应用产品层出不穷,网页访问、订单处理等操作产生的大规模日志记录,对大数据处理的实时性、准确性和高可用性发起了挑战。分布式消息系统的提出与应用成功解决了海量数据处理问题。当前各大电商企业纷纷采用该技术。文章对比了当下两种经典的开源分布式消息系统,对比分析了Kafka和 RabbitMQ的架构及性能,为科研人员和软件开发技术人员选择分布式消息系统提供了参考意见。
关键词:大数据,分布式消息系统,Kafka,RabbitMQ
首先分布式消息系统是建立在分布式系统上的,分布式系统[1]是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。分布式消息系统[2-3]是分布式系统之间进行消息传递的重要组件,它利用高效、可靠的消息传递机制进行数据交流,并基于数据通信进行分布式系统的集成。目前,分布式消息系统已经在各大互联网企业中广泛应用,甚至有些企业已自主研发更加适合自身企业应用场景的消息系统,如百度腾讯等。为了向科研人员和软件开发技术人员提供更多参考信息,本文对比分析了2种流行的开源分布式消息系统的架构及性能。
分布式系统间的协作主要分为两种模式:1、基于Http协议通过客户端发起的get、post请求,服务端接收request请求,处理请求,得到响应内容,通过网络传送到客户端,由浏览器解析出一个可视化的页面。这种交互最大的优势是实时性,通过HTTP请求连接各个子系统,从而跨服务器来完成一个完整的业务流程。2、基于消息的模式。这种模式一个很重要前提是对实时性要求不高。优点可以有效降低模块的耦合性,减轻主干业务流程,将大量的业务交由后台任务来处理,有效缩短系统响应时间,提高系统TPS。
分布式消息系统中的消息传递是基于消息模式的,消息传递主要有两种模式,分别是点对点模式和发布-订阅模式。
点对点模式(Point-to-Point)的结构如图1所示。消息被生产者放到一个队列中,消费者从消息队列中取走消息。消息一旦被一个消费者取走后,消息就从队列中移除。这意味着即使有多个消费观察一个队列,但一个消息只能被一个消费者取走。该模式会造成服务之间存在高耦合,请求阻塞以及请求无缓存等缺陷。随着服务规模不断扩张以及服务请求量急剧增加,这些缺陷也不断的放大而影响整个系统的性能。
图1 点对点模式
发布订阅模式的结构如图2所示。发布者发布一条消息可以发送给所有的订阅用户,所有的订阅用户都有处理某一条消息的机会。基于发布订阅模型的异步通信双方不再有直接的依赖关系。此外由于TOPIC在生产者和消费者之间充当了消息缓冲的作用,我们可以控制消费者的消息接受频率以避免服务由于性能性能问题在突然增加的请求压力下崩溃,这样可以更好的保证系统的稳定性[4]。
图2 发布订阅模式
1消息系统描述
1.1Kafka
1.1.1概述
Kafka是一个消息订阅和发布的系统,相对较为经典。Kafka被当作数据交换的必要的组件尤其被人们喜爱。为了解决linkedin数据的管道问题,Kafka在2010年诞生。Kafka有高吞吐量、低延迟、可扩展性、持久性、可靠性、容错性、高并发等特性。一个配置良好的Kafka集群可以做到超高并发写入,数值每秒可达上百万。
1.1.2概述 Kafka架构
如图3所示,Kafka架构中有6个基本概念[5],分别为 Broker,Topic,partition,Producer,Consumer和Consumer-Group 。
(1)Broker:Kafka 节点实例,对应为 Kafka集群的一台机器。每一个Kafka-Server是一个 Broker,一个 Kafka集群由一个或多个 Broker组成。
(2)Topic:主题,表示 Kafka 数据处理的消息源,数据的读写都要指定主题。
(3)Producer:数据生产者,向某个Topic发布消息的对象,即一种 push操作,将产生的消息推送给代理对象 Broker 进行存储。
(4)Consumer:数据消费者,订阅某个 Topic并处理消息的对象,即一种 pull 操作,主动拉去数据,Consumer自己控制消息的读取速度和数量,如果 Topic 中没有数据,那么会周期性的 pull 操作直到有数据产生[6]。
(5)Partition:分区,一个 Topic 可以有多个Partition,一个消息实际存储在 Topic 的某个 Partition中,每个Parition可以保证消息的有序性。
(6)Consumer-Group:消费者组,一组consumer的集合,group 订阅的某个 topic 下的每个分区只能被其中的一个consumer消费,不会出现一个分区的数据被同一个 group 下的多个consumer 消费的情况,可以理解为Consumer-Group是 Kafka提供的可 扩展且具有容错性的消费者机制,在开发过程中使用group.id 来标识。
图3 Kafka基本架构图
1.1.3Kafka性能分析
通过Kafka基本架构图可以看出,Kafka通过partition设计和Consumer-Group设计提高了系统的吞吐量和并发处理能力。
Kafka在创建 Topic时可以设置 partition数量,所有的 partition被均匀地分布在集群的各个节点上。Producer向Broker的Topic发布消息时,可以通将某条消息发布到随机的某个partition,消息被并行地发布到不同节点的partition中。Producer和 Consumer可以同时从多个partition上并行读写数据,这样就大大提高了系统的并行处理能力。
Kafka和其它消息系统有一个不一样的设计,在consumer之上加了一层group。同一个group的consumer可以并行消费同一个topic的消息,但是同group的consumer,不会重复消费。这就好比多个consumer组成了一个团队,一起工作,这样工作的效率就会大大提高。如果同一个topic需要被多次消费,可以通过设立多个consumer-group来实现。每个group分别消费,互不影响。因此Consumer-Group的设计有效地提高了消费消息的效率。
另外,Kafka采用发布-订阅模式传递消息,Producer只负责向 Broker发布消息,Consumer只负责从 Broker消费消息,消息的发布与消费是异步的,极大地提高了 Kafka的吞吐量。
1.2RabbitMQ
1.2.1概述
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议[7],是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
RabbitMQ[8-11]是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
1.2.2 RabbitMQ架构
RabbitMQ架构如图4所示,主要包含 Server(broker),Virtual Host,Exchange,Binding,Connection和 Channel 6个基本概念。
图4 RabbitMQ架构图
Broker:消息队列服务器,用于接收和分发消息。每一个RabbitMQ Server是一个Broker,一个RabbitMQ集群由一个或多个 Broker组成。
Queue:消息只能存储在队列(queue)中。尽管消息在RabbitMQ和应用程序间流通,但是队列却是存在于RabbitMQ内部。一个队列不受任何限制,它可以存储你想要存储的消息量,它本质上是一个无限的缓冲区。多个生产者可以向同一个队列发送消息,多个消费者可以尝试从同一个消息队列中接收数据。消息队列,提供了FIFO的处理机制,具有缓存消息的能力。RabbitMQ中,队列消息可以设置为持久化,临时或者自动删除。
Exchange:接受生产者发送的消息,并根据Binding规则将消息路由给服务器中的队列,就好比邮递员。Exchange有4种类型,direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别:
1)Direct 直接交换器,工作方式类似于单播,Exchange会将消息发送完全匹配ROUTING_KEY的Queue。
2)fanout广播是式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue。
3)topic主题交换器,工作方式类似于组播,Exchange会将消息转发和ROUTING_KEY匹配模式相同的所有队列,比如,ROUTING_KEY为user.stock的Message会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列。( * 表是匹配一个任意词组,#表示匹配0个或多个词组)。
4)headers消息体的header匹配(ignore)。
Binding:Binding联系了Exchange与Message Queue。Exchange在与多个Message Queue发生Binding后会生成一张路由表,路由表中存储着Message Queue所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key,Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在Binding Exchange与Message Queue时指定,而Routing Key由Producer发送Message时指定,两者的匹配方式由Exchange Type决定,就好比于邮件上面的地址。
Virtual Host:其实是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue等,就好比于tomcat中webapps目录下可以部署多个web项目。
Connection:连接,对于RabbitMQ而言,其实就是一个位于客户端和Broker之间的TCP连接。
Channel:信道,仅仅创建了客户端到Broker之间的连接后,客户端还是不能发送消息的。需要为每一个Connection创建Channel,AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel,是因为TCP连接的建立和释放都是十分昂贵的,如果一个客户端每一个线程都需要与Broker交互,如果每一个线程都建立一个TCP连接,暂且不考虑TCP连接是否浪费,就算操作系统也无法承受每秒建立如此多的TCP连接,可以简单的理解为线程池中的一个个线程。
Producer发 送 消 息 至 Exchange,Exchange 根 据 Exchange模 式 匹 配 到 对 应 的 Queue,将 消 息 存 入 Queue中,Consumer从 Queue中取出消息进行消费。
1.2.3 RabbitMQ 性能分析
RabbitMQ通信过程,假设P1和C1注册了相同的Broker,Exchange和Queue。P1发送的消息最终会被C1消费。基本的通信流程大概如下所示:P1生产消息,发送给服务器端的Exchange,Exchange收到消息,根据ROUTINKEY,将消息转发给匹配的Queue1,Queue1收到消息,将消息发送给订阅者C1,C1收到消息,发送ACK给队列确认收到消息Queue1收到ACK,删除队列中缓存的此条消息,Consumer收到消息时需要显式的向rabbit broker发送basic.ack消息或者consumer订阅消息时设置auto_ack参数为true。在通信过程中,队列对ACK的处理有以下几种情况:如果consumer接收了消息,发送ack,RabbitMQ会删除队列中这个消息,发送另一条消息给consumer。如果cosumer接受了消息, 但在发送ack之前断开连接,RabbitMQ会认为这条消息没有被deliver,在consumer在次连接的时候,这条消息会被redeliver。如果consumer接受了消息,但是程序中有bug,忘记了ack,RabbitMQ不会重复发送消息。
通过了解其通信过程可以发现RabbitMQ可以实现负载均衡,同时RabbitMQ提供消息跟踪机制,如果出现消息异常的情况,用户可以通过跟踪机制找出异常。另外,RabbitMQ支持集群模式,多台服务器的 Queue数据同步,若一台服务器丢失消息则可从其他服务器上获取,以保证数据不会丢失 。
2系统对比
经过对上述2种分布式消息系统的架构及性能分析,进行对比总结:
1)在架构模型方面,RabbitMQ遵循AMQP协议RabbitMQbrokerExchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。RabbitMQ以broker为中心;有消息的确认机制。Kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,消息的消费信息保存的客户端consumer上,consumer根据消费的点,从broker上批量pull数据;无消息确认机制。
2)在集群负载均衡方面,
Kafka采用zookeeper对集群中的broker、consumer进行管理,可以注册topiczookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上,RabbitMQ的负载均衡需要单独loadbalancer进行支持。
3结束语
在服务端发送消息的性能上,Kafka>RabbitMQ。Rabbit对路由、负载均衡、数据持久化都有很好的支持,但是由于其支持多种协议,使得 RabbitMQ变为一个重量级软件,更适合于企业级的开发。Kafka是高吞吐量的消息系统,支持持久化,适合于处理活跃的流式数据、产生大量数据的互联网服务的数据收集业务。除本文所述2种分布式消息系统外,ZeroMQ,Redis也可以用于分布式系统中的 消息传递。ZeroMQ号称“史上最快的消息队列”,其实质是一种基于消息队列的 多线程网络库,对套接字类型、连接处理、帧、路由等底层细节进行抽象,提供跨越多种传输协议的套接字。Redis 是一个开源的、高性能的keyvalue形式的数据库,同时也提供了发布-订阅消息的功能,可以用于消息的传输。相比上述2种成熟分布式消息系统,ZeroMQ 和 Redis较为简洁,系统开发人员可根据其提供的发布-订阅消息传递机制,进行定制开发。
参考文献:
[1]Distributed SystemsConceptsandDesign .GeorgeCoulouris[M].America:Addison-Wesley,2012.
[2]WOODI.Distributed Message TransmissionSystem and Me-thod:WO,EP1477034[P].2004.
[3]GEY,LIANG XX,PANZ,etal.MESSAGEPARSINGIN ADISTRIBUTEDSTREAM PROCESSINGSYSTEM:U.S.Pa-tentApplication15/258,629[P].2018-3-8
[4]卢帅.基于Kafka的消息发布订阅服务的设计与实现[D],南京,南京大学,2018
[5]吴 璨,王小宁,肖海力等.分布式消息系统研究综述[J].计算机科学,2019,46(06):1-4.
[6]高宗宝,刘丽美等,张家铭等.Spark 平台中 Kafka 偏移量的读取管理与设计[J] .设计研究与应用,2019,40(07):2-3
论文作者:李杨1,,陈福海2
论文发表刊物:《论证与研究》2019年10期
论文发表时间:2019/12/18
标签:消息论文; 队列论文; 分布式论文; 系统论文; 多个论文; 数据论文; 模式论文; 《论证与研究》2019年10期论文;