1. 介紹
采用ZooKeeper+Kafka的方式建立集群,主要支持了消息傳遞和負載均衡,常見的一些文檔,有的是概念較多,沒有實際操作;有的只有命令,不知其原理。這里就結合集群礦池來說說它的具體應用場景,原理,以及具體實現。
2. 舉例
先舉個例子,比如一個理發店:
一開始只有一個理發師,洗剪吹都由他一個人負責,那么只能一個客人做完全套(同一臺機器上操作各個步驟),再給下一個客人服務。
之后, 又來了幾個理發師,每個人負責接待一個客人(多臺服務器,每臺負責單個流程)。
再后來理發店又擴大,人多了(多臺不同用途的機器),老板發現如果把工作細分為:洗(A)剪(B)吹(C)三部分,這三部分的工作量和難度都不同,可以安排專人專職,以節約人力成本。三個模塊工作量不同,需要的人數也不同,如上圖所示,洗2人(2臺機器),剪3人(3臺機器),吹2人(2臺機器)。Data為庫房(數據服務器),每個人都可能去庫房存取工具。
顯然,A與B并不是一一對應的關系。洗發之后,應該分配剪發員執行下一步驟。讓洗發員找每個剪發員查詢狀態顯然不是明智的作法,而且,此時可能每個剪發員都不空閑,A還有接下來的工作,也不能一接等在那兒。
于是就引入了另一個角色:接待員broker,當某個A的工作做完全后,則向broker的topic發一個消息,告訴它本層已完成,需要下一層處理,此時A是發送者producer,中介是broker(它也位于一臺機器上,這里沒用方框畫出來),如果某個B空閑時,也會連接到topic,等待下一個工作(如上圖所示),此時B是接受者customer。B和C的通訊也是一樣,不過它們間通訊時B是producer,C是customer。
Broker是Kafka的一個實例,broker按功能不同又可建立多個topic,topic里又可包含多個partition,每個partition都可保證先入先出,但partition之間不保證順序。多個broker又可以做成Kafka群組。綜上,Kafka是傳送消息的工具,或者說是一套機制,它實現了消息創建,存取等工作。
在producer,customer,broker的背后又有著ZooKeeper的支持,它就好像理發店的排班員,在這里主要負責負載均衡,將工作平均分配給customer,避免產生閑的閑死忙的忙死這種問題。ZooKeeper也可以有多個,即使某一個死掉,整個系統仍可正常運轉。
從此處可見Kafka和Zookeeper上跑的不是執行具體工作的程序(洗剪吹),它們的角色是提供通訊和負載均衡的協調者。具體洗剪吹運行在哪個服務器上是另外的工作.
3. 配置過程
1) 配置ZooKeeper
在一臺或幾臺機器上配置和運行ZooKeeper服務。
2) 配置Kafka
配置Kafka的 broker
創建topic及partition。
3) 修改程序
在程序中分別加入對producer和consumer的調用,以傳遞信息。
4) 說明
通過以上步驟,程序就可以在不同的機器通過簡單地調用函數傳遞消息了。上述的ZooKeeper,Kafka,程序可以運行在同一臺機器上,可以分別在運行在不同機器上。
4. ZooKeeper
1) 介紹
ZooKeeper是一個快速、高可靠、容錯、分布式的協調服務。
2) 配置
$ cp conf/zoo_sample.cfg conf/zoo.cfg
$ vi conf/zoo.cfg #修改配置文件
配置文件中server*是zookeeper服務器之間交互用的,它使得一臺服務器死機時,另外一臺,能快速轉換為主zookeeper服務器
dataDir是數據目錄,clientPort為ZooKepper端口號,一般不用改
$ ./startserver.sh start # 啟動zooKeeper服務
3) 調試工具
$ bin/zkCli.sh -server 127.0.0.1:2181 #client端連上看一下
$ jps #查看進程, 其中QuorumPeerMain是zooKeeper的主進程
$ netstat -nap|grep 2181 # 查看配置文件中設置的端口是否打開
正常顯示為:
tcp 0 0 0.0.0.0:2181 0.0.0.0:* LISTEN 10737/java
5. Kafka
1) 介紹
Kafka是一個分布式的流數據處理平臺。
2) 配置文件
$ vi config/server.properties
這是默認的配置文件,以下幾項比較重要
broker.id=1 # broker的標識,具有唯一性
port=9092 # kafka服務的端口號
log.dirs=/tmp/kafka-logs # 存儲log的目錄,交互的信息就存在該目錄下
zookeeper.connect=127.0.0.1:2181 # zookeeper服務器的IP和端口,多個用逗號分開
host.name=127.0.0.1 # 運行本程序機器的IP地址,在btcpool的cfg中指定
delete.topic.enable=true #建議加這句,否則刪topic時候特別麻煩
message.max.bytes=20000000 # 支持大數據msg,否則傳輸時將丟棄大數據塊
replica.fetch.max.bytes=30000000 # 同上
3) 啟動服務
$ bin/kafka-server-start.sh config/server.properties
4) 創建供btcpool使用的topic
需要先啟后臺服務,再創建topic,我這里使用了一個本機的zookeeper,如果有多個,請使用逗號分隔。
$ ./bin/kafka-topics.sh --create --topic test --zookeeper 127.0.0.1:2181 --replication-factor 1 --partitions 1
5) 相關工具
i. 查看topic
$ ./bin/kafka-topics.sh --describe --zookeeper 127.0.0.1:2181 #查看topic
ii. 查看kafka服務
$ netstat -nap|grep 9092
正常運行時返回
tcp 0 0 127.0.0.1:9092 0.0.0.0:* LISTEN 24961/java
6) 刪除topic
先刪除kafka存儲目錄(server.properties文件log.dirs配置,默認為"/tmp/kafka-logs")相關topic目錄。注意partition的數據都存在這個目錄中。
./bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --topic test -delete
如果在server.properties中未指定delete.topic.enable=true,則只會做一個刪除標記,不會真正刪除,刪除需要在zookeeper服務器上,通過zkCli.sh連進去刪除。
7) 常出現的錯誤
i. kafka-server-start.sh報錯找不到主機,然后直接退出
解決方法,在配置文件中設置主機
host.name=主機名
主機名通過命令hostname查看
ii. kafka-server-start.sh雖不退出,但不停報錯java.lang.NoClassDefFoundError: Could not initialize class kafka.network.RequestChannel$
這也是主機名相關的問題,在/etc/hosts的最后填加一句
127.0.0.1 主機名
主機名通過命令hostname查看
8) 測試kafka
正常情況下,producer上發的,consumer都應該能收到
i. 創建
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
ii. 接收
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning
iii. 發送
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
如果topic沒建立,producer會自動建立top,但參數可能與你想要的不同.
6. C程序調用kafka發消息
一般使用librdkafka庫,下載庫源碼編譯,其中example目錄中的程序也可以用于測試。
7. 參考
1) Apache Kafka 分布式消息隊列中間件安裝與配置
http://blog.csdn.net/wangjia184/article/details/37921183
2) Kafka&Zookeeper原理與應用場景介紹
https://wenku.baidu.com/view/a47389116ad97f192279168884868762caaebbd4.html