RabbitMQ與Kafka選型對比

背景

  本公司是.Net項目,在.Net可選的MQ比較少,主要Kafka和RabbitMQ,RabbitMQ我也是使用多年了,最近的Kafka廣告與流行度打得使我也是無法無視,因此也是花了點時間收集了資料做了些對比。

  此外有個小插曲,當我形成了文檔讓老闆兼CTO對比決策後,他打算上阿里雲買MQ服務。我當時給他開了個玩笑:您這價錢把我請回來,而且公司還有運維,其實完全可以自己維護,要不我來負責,你把這每個月的MQ費用給我加工資得了。當我下樓買了支維他檸檬茶後,他決定由我們自己搭建RabbitMQ。這個決定跟我的想法差不多,原因主要兩點:運維起來方便,吞吐沒有特別高。

  如果下文有總結不到位的,或者差錯的,可以在下方評論回饋給我

RabbitMQ模型

名詞 描述
Queue 用於存儲消息,消費者直接綁定Queue進行消費消息
Exchange 生產者將消息發送到Exchange,由交換器將消息通過匹配Exchange Type、Binding Key、Routing Key後路由到一個或者多個隊列中。
Exchange Type Direct、Fanout、Topic、Headers
Routing Key 生產者發送消息給Exchange會指定一個Routing Key。
Binding Key 在綁定Exchange與Queue時會指定一個Binding Key
  • Exchange在聲明時會綁定Queue和Binding Key,當Exchange收到消息會根據消息的
  • Routing Key與Exchange Type、Binding Key進行匹配,最後會路由到相關的隊列當中。
    • Fanout,將消息發送到與該交換器所綁定的所有隊列中,與Routing Key、Bind Key無關,這就是廣播模式。
    • Topic,通過對消息的Routing Key和Exchange、Queue進行匹配,將消息路由給一個或多個隊列,以此來達到發布/訂閱模式。
    • Direct,把消息路由到哪些Bind Key和Routing Key完全匹配的隊列中。
    • Headers,不依賴與路由鍵的匹配規則,基本用不上。
  • 消費者會直接訂閱Queue里的消息進行消費,多個消費者訂閱同個Queue會形成消息競爭狀態,以此達到負載均衡作用。

Kafka模型

 

名詞 描述
Topic 隊列是通過Topic進行隔離的,生產者發送消息必須指定Topic
Broker 一個Kafka Server的被稱為一個Broker。
Partition 每個Topic可以包含多個Partition,多個Partition會平均分配給同一個Consumer Group里的不同Consumer進行消費
Consumer Group 不在同一個Group 的Consumer能重複消費同一條消息(訂閱),相同Group的Consumer存在消費競爭(負載均衡)
  • 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.

功能對比

 

對比項 RabbitMQ Kafka
吞吐量
有序性 全局有序性 分區有序性
消息可靠性 多策略組合 消息持久化
流處理 不支援 支援
時效性
運維便捷度
系統依賴 zookeeper
Web監控 自帶 第三方
優先順序隊列 支援 不支援
死信 支援 不支援
客戶端支援 支援多種語言
社區生態
安全機制 (TLS/SSL、SASL)身份認證和(讀寫)許可權控制
消息回溯 支援 不支援

 

對比描述

共同點

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.commitrue,不管執行結果如何,消費者會自動提交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

瀏覽器訪問://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

瀏覽器訪問://IP:8048

阿里雲費用

以下截圖基本以最低配置。

Kafka按量付費

Kafka包月

RabbitMQ包月

Tags: