消息中间件选型,kafka和rabbitmq如何选择

消息中间件,MQ message queue
一般在比较复杂的软件设计中会引入消息中间件来进行相关功能的支撑,那么消息中间件的作用是什么?一般主流经常使用的kafka和rabbitmq二者有什么区别,在我们项目中何时该使用kafka,何时使用rabbitmq?
MQ的原始概念其实可以理解为如下流程:
生产者发送消息到MQ -> MQ保存消息 -> 消费者消费消息
后面各个厂商在这上面扩展了MQ的含义。

MQ中有如下几个模块构成:

  • Broker MQ服务器,提供核心消息服务
  • Producer 消息生产者,产生消息并发送给Broker
  • Consumer 消息消费者,从Broker中消费消息
  • Topic 消息主题,可以理解将消息分类,发布订阅模式下消息的划分,订阅了某个Topic的消费者可以消费该topic下的消息
  • Queue 消息队列,点对点模式下,生产者向特定的queue发送消息,消费者订阅特定的queue完成指定消息的消费
  • Messge 消息体

一般消息中间件的主要作用有如下:

  • 异步调用,一般消息中间件都是单独部署,传统的同步调用需要等待被调用者给出响应,调用方一直处于等待中,而使用消息中间件后,对于一些对于同步性要求不是很高的应用,可以直接通过将调用封装成消息发送给MQ,被调用者消费对应的MQ消息即可
  • 降低系统耦合度,例如现在A系统产生数据,B,C系统需要这个数据,传统可能是调用B,C接口,将数据给到B,C,但是如果来了D系统,要在A中加入D的接口逻辑,E得加入E,有了消息中间件之后,A只需要将数据发送到MQ中,下游哪个系统想用这个消息,自己去订阅消费这个消息即可
  • 流量削峰 举个例子,这个时候系统有大量的订单请求,如果基于传统的模式,可能就是每来一个订单就入库,但是在大流量情况下系统可能支撑不住,引入消息中间件之后,可以先将订单信息发送到MQ中,由于MQ也是能够持久化消息的,这样相当于中间有了一个缓存,而基于MQ的特性,下游的消费程序在流量大的时候处理可能没那么快处理完,但是等流量下来之后,这时候下游消费程序还是能够在一直消费,说白了就是在流量比较少的时候依然在处理,由于这时候没有大流量,总归是能够处理完的
  • 冗余存储、缓冲 数据处理过程中可能会出现失败的情况,消息中间件可以将数据持久化直到被完全处理,避免了数据丢失

目前市面上比较流行的MQ主要有kafka和rabbitMQ。
kafkf是Linkedin开源的消息发布/订阅系统,从大的层面上可以说是一种分布式流式数据处理框架,在大数据领域内的消息传输基本上都采用了kafka,kafka的吞吐量非常大,号称百万级TPS。一般对于吞吐量比较大的,对于日志传输,

rabbitMQ内部采用AMQP协议,broker由exchange,binding,queue组成,比较适合对可靠性要求比较高,吞吐量不是特别大的系统。

架构、处理流程

kafka中存在这么几个概念:topic、partition、producer、broker、consumer、consumergroup。producer端发送消息前会根据消息key和分区规则将消息发送到broker端topic对应的分区下(一般创建topic指定分区个数,kafka中broker端有默认分区的配置),broker端根据消息分区将消息写入到对应topic分区的文件里。consumer端会固定去broker端拉取消息,同一个消费者组的consumer会根据topic的分区数量来进行均衡的消费(比如4个分区,一个消费者组中有A,B两个消费者,那么broker端会通过均衡的算法,将4个分区分贝给A,B去进行消费),kafka中的每条消息只会投递给订阅该topic的所有消费者组中的一个消费者组,在消费者组级别消息相当于是广播的。kafka的消息默认就是写磁盘的,消息是存储在磁盘上的

rabbitmq中存在这么几个概念:exchange,queue,binding,producer,broker,consumer。producer发送消息时,声明exchange,queue,binding,通过binding将exchange和queue关联起来,消息发送到exchange时通过binding找到对应的queue继而发布到对应的queue中。rabbitmq中消息默认是存储在内存中,可以通过设置,同时将消息持久化到磁盘上

消息模式

rabbitmq可以说是一种点对点模型,kafka是典型的发布/订阅模型。rabbitmq中一般生产者都会通过发布消息到exchange和其绑定的队列上,消费者消费固定队列上的消息,同一个队列上,一条消息只能被一个消费者消费。
kafka中可以只有一个消费者组,达到点对点的发布。
rabbitmq中可以通过exchange绑定多个队列,消费者消费多个队列达到发布/订阅模式。这个时候就不是queue,相当于是订阅了exchange

消息的顺序性

在rabbitmq中,一个队列中的消息是严格有序的,在kafka中同一个topic下的同一个partition消息是有序的,就整个topic而言是无序的。

可靠性

rabbitmq中可以通过事务或confirm机制,生产者能够确认消息是否发送成功,消费者端可以关闭自动消息确认,通过手动确认消息ack。
kafka中开始是为了日志传输,可靠性是不如rabbitmq的,但是后续kafka进行了改进,通过生产者参数ack来设置消息的可靠性,ack=all或者-1的时候表示必须ISR集合内的副本都收到了消息,消息才算发送成功。消费者端设置关闭自动提交位移,通过手动提交位移来确认消息的消费进度。但是由于kafka需要引入zookeepr来进行整个集群的管理,可靠性相比rabbitmq来说要稍微差一点。

持久化

kafka中消息默认就是持久化的,一旦生产者往topic里面发送数据,默认这个topic就会被创建成功,消息写入机制就是写入磁盘的。
rabbitmq中消息默认是写在内存中的,可以通过设置,将消息进行持久化

高可用

kafka设计之初就自带高可用,通过集群,每个topic下的每个分区有多个副本,一个节点crash之后不会影响整个集群使用,但是需要注意的是,节点crash之后,需要重新选主,kafka采用的zk,这段时间暂不可用
rabbitmq中高可用性可以通过镜像队列来实现。

集群

kafka借助zookeeper来管理整个集群,kafka中的topic下的分区不是单个节点,而是在多个节点上存在多副本机制,生产者端,发送消息根据分区策略将消息发送到不同分区,消费者端,一个消费者组内的消费者根据不同的策略来消息对应的分区的数据。

rabbitmq中的集群,有两种模式,普通集群模式,队列只会存在一个节点上,集群共享的不是队列,而是队列元数据、交换器、绑定关系元数据,当向一个节点写入消息时,该节点会查找映射关系,如果队列不在当前节点,会将消息会发送到对应的节点上面,做了一个转发,不会备份消息,这时候集群中必须有一个磁盘节点,不然集群共享的数据(队列元数据、交换器、绑定关系元数据)会存在丢失风险
另外一种模式则是镜像集群模式,将需要的队列做成镜像队列,在多个节点之间同步数据

总结

如果消息数据量大,对QPS要求高,对可靠性要求不高,选kafka
如果消息数据量不大,对QPS要求不是很高,对可靠性要求高,选rabbitmq

Guess you like

Origin blog.csdn.net/LeoHan163/article/details/116406506