kafka

kafka

流處理消息隊列

1. 安裝

    // 環境centos7,jdk8
    wget https://mirrors.cnnic.cn/apache/kafka/2.2.0/kafka_2.11-2.2.0.tgz
    tar -zxvf kafka_2.11-2.2.0.tgz
    cd kafka_2.11-2.2.0
    // 配置zookeeper的broker.id、log.dir、zookeeper.connect,broker.idp配置成集羣內唯一
    vim config/server.properties
    // 啓動zookeeper
    bin/zookeeper-server-start.sh -daemon config/zookeeper.properties
    // 啓動kafka
    bin/kafka-server-start.sh config/server.properties &

2. 配置

kafka配置

3. 相關概念

  1. Broker:Kafka集羣包含一個或多個服務器,這些服務器就是Broker
  2. Topic:每條發佈到Kafka集羣的消息都必須有一個Topic, 一個Topic可以認爲是一類消息的集合。
  3. Partition:是物理概念上的分區,爲了提供系統吞吐率,在物理上每個Topic會分成一個或多個Partition,每個Partition對應一個文件夾;每個partition在存儲層面是append log文件。任何發佈到此partition的消息都會被直接追加到log文件的尾部,每條消息在文件中的位置稱爲offset(偏移量),offset爲一個long型數字,它是唯一標記一條消息。
  4. Producer:消息產生者,負責生產消息併發送到Kafka Broker;Producer將消息發佈到指定的Topic中,同時Producer也能決定將此消息歸屬於哪個partition;
  5. Consumer:消息消費者,向kafka broker讀取消息並處理的客戶端。 每個consumer屬於一個consumer group;反過來說,每個group中可以有多個consumer.發送到Topic的消息,只會被訂閱此Topic的每個group中的一個consumer消費.如果所有的consumer都具有相同的group,這種情況和queue模式很像;消息將會在consumers之間負載均衡. 如果所有的consumer都具有不同的group,那這就是"發佈-訂閱";消息將會廣播給所有的消費者.

  6. Consumer Group:每個Consumer屬於一個特定的組,組可以用來實現組內消息分發負載均衡功能。
  7. zookeeper:服務註冊發現, 無論是kafka集羣,還是producer和consumer都依賴於zookeeper來保證系統可用性集羣保存一些meta信息。

kafka和activeMQ不同的是:即使消息被消費,消息仍然不會被立即刪除.日誌文件將會根據broker中的配置要求,保留一定的時間之後刪除;比如log文件保留 2天,那麼兩天後,文件會被清除,無論其中的消息是否被消費.kafka通過這種簡單的手段,來釋放磁盤空間,以及減少消息消費之後對文件內容改動的磁盤IO開支.

對於consumer而言,它需要保存消費消息的offset,對於offset的保存和使用,有consumer來控制;當consumer正常消費消息時,offset將會"線性"的向前驅動,即消息將依次順序被消費.事實上consumer可以使用任意順序消費消息,它只需要將offset重置爲任意值.

kafka集羣幾乎不需要維護任何consumer和producer狀態信息,這些信息有zookeeper保存;因此producer和consumer的客戶端實現非常輕量級,它們可以隨意離開,而不會對集羣造成額外的影響.

partitions的設計目的有多個.最根本原因是kafka基於文件存儲.通過分區,可以將日誌內容分散到多個server上,來避免文件尺寸達到單機磁盤的上限,每個partiton都會被當前server(kafka實例)保存;可以將一個topic切分多任意多個partitions,來消息保存/消費的效率.此外越多的partitions意味着可以容納更多的consumer,有效提升併發消費的能力.

基於replicated方案,那麼就意味着需要對多個備份進行調度;每個partition都有一個server爲"leader";leader負責所有的讀寫操作,如果leader失效,那麼將會有其他follower來接管(成爲新的leader);follower只是單調的和leader跟進,同步消息即可..由此可見作爲leader的server承載了全部的請求壓力,因此從集羣的整體考慮,有多少個partitions就意味着有多少個"leader",kafka會將"leader"均衡的分散在每個實例上,來確保整體的性能穩定.

在kafka中,一個partition中的消息只會被group中的一個consumer消費;每個group中consumer消息消費互相獨立;我們可以認爲一個group是一個"訂閱"者,一個Topic中的每個partions,只會被一個"訂閱者"中的一個consumer消費,不過一個consumer可以消費多個partitions中的消息.kafka只能保證一個partition中的消息被某個consumer消費時,消息是順序的.事實上,從Topic角度來說,消息仍不是有序的.

kafka的設計原理決定,對於一個topic,同一個group中不能有多於partitions個數的consumer同時消費,否則將意味着某些consumer將無法得到消息.
如果一個topic的名稱爲"my_topic",它有2個partitions,那麼日誌將會保存在my_topic_0和my_topic_1兩個目錄中;日誌文件中保存了一序列"log entries"(日誌條目)

4. kafka的優缺點

優點

  • 大數據量流式操作
  • 可異步操作,性能好
  • 批量操作,性能好
  • kafka是對日誌文件進行append操作,因此磁盤檢索的開支是較小的;同時爲了減少磁盤寫入的次數,broker會將消息暫時buffer起來,當消息的個數(或尺寸)達到一定閥值時,再flush到磁盤,這樣減少了磁盤IO調用的次數.
  • 消息傳送機制
    • at most once: 最多一次,這個和JMS中"非持久化"消息類似.發送一次,無論成敗,將不會重發.
    • at least once: 消息至少發送一次,如果消息未能接受成功,可能會重發,直到接收成功.[首選]

缺點:

  • 尚未確保消息的發送與接收絕對可靠

5. 常見命令行操作

  1. topic相關操作

     // 創建topic, replication-factor:每個partition的副本個數
     bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
     // 查看所有topic
     bin/kafka-topics.sh --list --zookeeper localhost:2181
     // 查看某個topic詳情
     bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --topic test --describe
  2. group相關操作

     // 創建消費者組,消費者登錄時自動指定group,如果group不存在,kafka broker自動創建group;
     // 查看消費者組列表
     bin/kafka-consumer-groups.sh test --bootstrap-server localhost:9092 --list
     // 查看某個消費者組詳情
     bin/kafka-consumer-groups.sh test --bootstrap-server localhost:9092 --grop test --describe
    
     // 生產者登錄
     bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test 
    
     // 消費者登錄(指定topic,指定group)
     bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning --group 'test-group'

6. node操作 kafka-node

  1. ConsumerGroup可以實現同組中只有一個可以收到信息,可以配合pm2負載均衡 + 數據庫的唯一索引使用, consumer不可以實現同組中只有一個可以收到信息,會同時受到信息,想來是groupId的設置沒有起作用,

  2. kafka-node

  3. 生產者負載均衡

     const kafka = require('kafka-node'),
     HighLevelProducer = kafka.HighLevelProducer,       
     client = new kafka.KafkaClient('127.0.0.1:9092'),
     producer = new HighLevelProducer(client);
    
     producer.on('ready',function() {
     console.log('1')
     let payloads = [{
             topic: 'test',
             messages: [
             '1|xiaoming|23',
             '2|lili|22'
             ],
             partition:0,
             attributes: 2,
             timestamp: Date.now()
     }]
     producer.send(payloads, function(err, data) {
             console.log(data)
         })
     })
    
     producer.on('error', function(err) {
             console.log(err);
     })
  4. 消費者負載均衡

     const kafka = require('kafka-node'),
     Producer = kafka.Producer,
     ConsumerGroup = kafka.ConsumerGroup;
    
     var options = {
             kafkaHost: '127.0.0.1:9092', 
             groupId: 'test-group',
             protocol: ['roundrobin'],
             sessionTimeout: 15000,
             fromOffset: 'latest'       // 'latest'標記每次從最近開始消費,'earliest'從最初開始消費,一旦確定後,後續無法更改,只能換組;
     };
     consumerGroup = new ConsumerGroup(options,['test']);
    
     consumerGroup.on('message', function(message) {
             console.log(message);
     });
     consumerGroup.on('error', function(message) {
             console.log(message);
     })
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章