RabbitMQ与Kafka到底选哪一个?

背景
java

本公司是.Net项目,在.Net可选的MQ比较少,主要Kafka和RabbitMQ,RabbitMQ我也是使用多年了,最近的Kafka广告与流行度打得使我也是没法无视,所以也是花了点时间收集了资料作了些对比。git

此外有个小插曲,当我造成了文档让老板兼CTO对比决策后,他打算上阿里云买MQ服务。我当时给他开了个玩笑:您这价钱把我请回来,并且公司还有运维,其实彻底能够本身维护,要不我来负责,你把这每月的MQ费用给我加工资得了。当我下楼买了支维他柠檬茶后,他决定由咱们本身搭建RabbitMQ。这个决定跟个人想法差很少,缘由主要两点:运维起来方便,吞吐没有特别高。github

若是下文有总结不到位的,或者差错的,能够在下方评论反馈给我web

RabbitMQ模型

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

  • Exchange在声明时会绑定Queue和Binding Key,当Exchange收到消息会根据消息的sql

  • Routing Key与Exchange Type、Binding Key进行匹配,最后会路由到相关的队列当中。Fanout,将消息发送到与该交换器所绑定的全部队列中,与Routing Key、Bind Key无关,这就是广播模式。Topic,经过对消息的Routing Key和Exchange、Queue进行匹配,将消息路由给一个或多个队列,以此来达到发布/订阅模式。Direct,把消息路由到哪些Bind Key和Routing Key彻底匹配的队列中。Headers,不依赖与路由键的匹配规则,基本用不上。docker

  • 消费者会直接订阅Queue里的消息进行消费,多个消费者订阅同个Queue会造成消息竞争状态,以此达到负载均衡做用。vim

Kafka模型

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

  • Kafka与RabbitMQ比没有Exchange的概念,生产者直接发消息Topic(队列)。浏览器

  • Kafka的订阅者是经过消费组(Consumer Group)来体现的,每一个消费组均可以重复消费Topic一份完整的消息,不一样消费组之间消费进度彼此不受影响。例如Message1能被Consumer Group 1和Consumer Group2里的消费者都消费一次。缓存

  • 消费组中包含多个消费者,同个Group的消费者之间是竞争消费的关系。例如Message2只可以被Consumer Group里某一个Consumer只消费一次。安全

  • Kafka具备消息存储的功能,消息被消费后不会被当即删除,由于须要被不一样的Consumer Group屡次消费同个消息,所以会在Topic维护一个Consumer Offset,每消费成功Offset自增1.

功能对比


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=


对比描述共同点

RabbitMQ与Kafka都有很好的客户端语言支持、安全机制与生态支持。

性能

Kafka的诞生的是处理高并发日志的,吞吐量比较高,每秒请求数达到数十万量级,而RabbitMQ每秒请求数则为万级别,有测试报告指出Kafka是RabbitMQ的10倍以上性能。

运维便捷

RabbitMQ相对比较方便,可使用yum或者docker安装,自带Web管理UI,没有额外的依赖,除了须要作镜像队列外须要引入HAproxy。

Kafka则须要依赖Zookeeper,也没有自带的管理工具,可使用第三方的Kafka Eagle代替,Kafka Manager过于难用,另外Kafka没有yum安装,docker镜像也是社区人员本身建的。

有序性

RabbitMQ理论上是全局有序性的,可是因为【发后既忘】+【自动确认】机制的缘由,若是在同个队列的多个消费者作相同的业务处理时,他们的各自的执行任务没法保证有序完成。若是确保100%有序可使用【非自动确认】,但会影响消费性能。

Kafka支持分区有序性,若是对有序性有严格要求能够设置单个Partition,但是单个Partition并发性比较低,所以在多个Partition状况下能够根据业务指定key把相关的消息路由到同一个Partition,例如相同UserId行为信息能够到Partition 1进行处理。

时效性

Kafka基本上不管在客户端仍是服务端都是以【异步批量】的机制进行处理,通俗的讲就是先攒起来一堆消息,到了某个阀值再发送,也会致使一些消息可靠性与消息有时效上的问题,固然能够经过各类配置策略进行解决。

消息回溯

Kafka在消费完了消息后不会当即删除,只会修改offset,若是以前部分业务消费失败了能够从新设置offset进行从新消费。

RabbitMQ则是[发后既忘]的机制,一但消费者确认消息则删除,可是能够经过死信进行补偿消费。此外RabbitMQ在队列消息堆积多的状况下性能表现不佳,因此尽量的及时消费消息。

特点功能

RabbitMQ具备死信的功能,能够经过死信造成重复消费与延时发送。

Kafka具备流处理功能,能够收集用户的行为日志进行存储与分析。

Kafka为何快?

关键核心技术点:

  • 异步批量处理

  • 磁盘顺序读写

  • 操做系统PageCache缓存数据

  • 零拷贝加速消费

Kafka的诞生就是为了高并发日志处理的,那么在他整个机制里使用了不少批量、异步、缓存。例如生产者客户端,他会积累必定量(条数、大小)的消息,再批量的发给kafka broker,若是在这段时间客户端服务挂了,就等于消息丢失了。当broker接受到了消息后,还有一堆骚操做-异步刷盘,也就是生产者发送给broker以后他是记录在缓存的,每隔一段时间才会持久化到磁盘,假如这段真空期broker挂了,消息也是丢了。

Kafka是否消息不可靠?

Kafka快是由于牺牲了消息可靠换取回来的性能,在最先期版本的确没提供消息可靠的策略,通过多个版本迭代后的功能完善,已经不存在这种旧观念。那么可靠的关键点有如下:

生产者

设置ack:

  • 0:producer不等待broker的ack,broker一接收到尚未写入磁盘就已经返回,可靠性最低;

  • 1:producer等待broker的ack,partition的leader刷盘成功后返回ack,若是在follower同步成功以前leader故障,那么将会丢失数据,可靠性中;

  • -1:producer等待broker的ack,partition的leader和follower所有落盘成功后才返回ack,数据通常不会丢失,延迟时间长可是可靠性高

消费者

设置enable.auto.commi true,无论执行结果如何,消费者会自动提交offset。

false,须要用户须要手动提交offset,能够根据执行结果具体处理offset

RabbitMQ单节点部署

安装

yum install -y rabbitmq-server

开放相关端口

firewall-cmd --permanent --add-port=15672/tcp
firewall-cmd --permanent --add-port=5672/tcp
firewall-cmd --reload

启动服务

service rabbitmq-server start

启动web管理界面

rabbitmq-plugins enable rabbitmq_management

增长访问admin用户,默认用户guest只能本地访问。

rabbitmqctl add_user admin 123456

设置admin用户为管理员角色

rabbitmqctl set_user_tags admin administrator

设置默认admin用户访问权限

rabbitmqctl set_permissions -p "/" admin "." "." ".*"

重启服务

service rabbitmq-server restart

浏览器访问:http://IP:15672

Kafka单节点部署Zookeeper部署

下载Zookeeper并启动

docker run -d --restart always --name zookeeper -p 2181:2181 -v /root/zookeeper/data:/data -v /root/zookeeper/conf:/conf -v /root/zookeeper/logs:/logs zookeeper:3.6.1

开放2181端口

firewall-cmd --permanent --add-port=2181/tcp
firewall-cmd --reload
Kafka服务部署

下载kafka 镜像并启动

docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=1 -e KAFKA_ZOOKEEPER_CONNECT=192.168.88.139:2181 -e KAFKA_ADVERTISED_HOST_NAME=192.168.88.141 -e KAFKA_ADVERTISED_PORT=9092 wurstmeister/kafka:2.12-2.5.0

建立目录并拷贝

mkdir /root/kafka
docker cp kafka:/opt/kafka/config /root/kafka/config

删除原有的容器并从新建立

docker stop kafka
docker rm kafka

docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=1 -e KAFKA_ZOOKEEPER_CONNECT=192.168.88.139:2181 -e KAFKA_ADVERTISED_HOST_NAME=192.168.88.141 -e KAFKA_ADVERTISED_PORT=9092 -v /root/kafka/config: /opt/kafka/config wurstmeister/kafka:2.12-2.5.0

开放9092端口

firewall-cmd --permanent --add-port=9092/tcp
firewall-cmd --reload
Kafka-eagle

下载jdk依赖

yum -y install java-1.8.0-openjdk*

下载kafka-eagle-bin包

wget -o kafka-eagle-bin.tar.gz https://codeload.github.com/smartloli/kafka-eagle-bin/tar.gz/v2.0.1

解压

tar -zxvf kafka-eagle-bin.tar.gz
tar -zxvf kafka-eagle-bin-2.0.1/kafka-eagle-web-2.0.1-bin.tar.gz
mv kafka-eagle-web-2.0.1 kafka-eagle

添加环境变量

vim /etc/profile

export JAVA_HOME=/usr
export KE_HOME=/etc/kafka-eagle
export PATH=$PATH:$KE_HOME/bin:$JAVA_HOME/bin

生效环境变量

source /etc/profile

修改

Kafka-eagle

配置

cd /etc/kafka-eagle/conf
vim system-config.properties

#注释
#cluster2.zk.list=xdn10:2181,xdn11:2181,xdn12:2181
#cluster2.kafka.eagle.offset.storage=zk


#cluster1.zk.acl.enable=false
#cluster1.zk.acl.schema=digest
#cluster1.zk.acl.username=test
#cluster1.zk.acl.password=test123


修改
kafka.eagle.zk.cluster.alias=cluster1
cluster1.zk.list=192.168.88.139:2181
kafka.eagle.metrics.charts=true

kafka.eagle.driver=org.sqlite.JDBC
kafka.eagle.url=jdbc:sqlite:/etc/kafka-eagle/db/ke.db
kafka.eagle.username=root
kafka.eagle.password=root

启动kafka-eagle服务

cd /etc/kafka-eagle/bin
chmod +x ke.sh
ke.sh start

开启防火墙

firewall-cmd --permanent --add-port=8048/tcp     
firewall-cmd --reload

浏览器访问:http://IP: 8048