今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

喬二爺發表於2019-05-10

訊息中介軟體/系統

中介軟體

中介軟體是一類連線軟體元件和應用的計算機軟體,它包括一組服務。以便於執行在一臺或多臺機器上的多個軟體通過網路進行互動。

該技術所提供的互操作性,推動了一致分散式體系架構的演進,該架構通常用於支援並簡化那些複雜的分散式應用程式,它包括 web伺服器、事務監控器和訊息佇列軟體

訊息佇列

在電腦科學中,訊息佇列(英語:Message queue)是一種程式間通訊或同一程式的不同執行緒間的通訊方式,軟體的貯列用來處理一系列的輸入,通常是來自使用者。

訊息佇列提供了非同步的通訊協議,每一個貯列中的紀錄包含詳細說明的資料,包含發生的時間,輸入裝置的種類,以及特定的輸入引數,也就是說:訊息的傳送者和接收者不需要同時與訊息佇列互動。訊息會儲存在佇列中,直到接收者取回它。

訊息佇列常常儲存在連結串列結構中。擁有許可權的程式可以向訊息佇列中寫入或讀取訊息。

--以上來自 維基百科

讓我們用快遞員送快遞的例子來理解。

最開始送上門,你有時候不在家,又只有等第二天,現在多了個菜鳥驛站,快遞小哥只需要往裡面放,你有快遞自己去驛站拿就行了。

快遞小哥也不用直接對接這麼多的客戶,有包裹往驛站丟就行,然後我們去驛站拿,就算有時候我們不空,也可以讓包裹在驛站多放幾天,這也就是它的堆積能力。

為什麼我們要用訊息佇列

非同步處理

假設你有一個系統呼叫的鏈路,系統A 呼叫系統B 耗時 50ms,系統B 呼叫系統C 又需要200ms ,系統C 呼叫系統 D ,需要做比較超時的操作,需要 2s,如下圖所示:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

現在上面最大的問題在於:一個使用者請求過來,整個鏈路的呼叫時間是 50ms + 200ms + 2000ms = 2250ms,也就是2秒多。

而事實上,呼叫鏈路中,系統A 呼叫系統 B,系統B 呼叫系統 C 總共加起來也才 250ms,但是系統C呼叫系統D 卻用了 2S。

正是加入系統C呼叫系統D 這個鏈路,導致系統響應時間 從 250ms 增加到了 2250 ms,足足慢了 10倍。

如果說,我們把系統D 從鏈路中抽離出去,讓 C 系統非同步呼叫D,那麼在 B系統呼叫 C,C 處理完成自己的邏輯,傳送一個非同步的請求去呼叫D系統,不用阻賽等到 D系統響應了再返回。這是不是好很多了呢?

舉一個例子,就以我們平常點外賣為例:

我們平常點完餐,付完款,系統然後平給賬戶扣款、建立訂單、通知商家準備菜品。

接著,是不是需要找個騎手給你送餐?那這個找騎手的過程,是需要一套複雜演算法來實現排程的,比較耗時。

那麼我們是不是就可以把找騎手給你送餐的這個步驟從鏈路中抽離出去,做成非同步化的,哪怕延遲個幾十秒,但是隻要在一定時間範圍內給你找到一個騎手去送餐就可以了。

這樣是不是就可以讓你下訂單點外賣的速度變得超快?支付成功之後,直接建立好訂單、賬戶扣款、通知商家立馬給你準備做菜就ok了,這個過程可能就幾百毫秒。然後後臺非同步化的耗費可能幾十秒通過排程演算法給你找到一個騎手去送餐,但是這個步驟不影響我們快速下訂單。

所以上面的鏈路也是同理,如果業務流程支援非同步化的話,是不是就可以考慮把系統C對系統D的呼叫抽離出去做成非同步化的,不要放在鏈路中同步依次呼叫。

整個過程如下:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

訊息解耦

假如你現在系統A,這個系統會產出一個核心資料,下游系統 B和 C 都需要這個資料。

那麼我們平常做的就是直接呼叫系統 B 和系統 C,傳送資料過去。

過程如下:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

過幾天,其他的業務系統D、E 也需要這個資料,然後成了這樣

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

如果後續還有系統要呢?你不該程式碼改死。。。

這種情況系統耦合非常的嚴重,如果你傳送一個系統的呼叫失敗了怎麼整?

針對上面的問題,我們可以使用訊息佇列來實現系統解藕。

系統A 把資料傳送到訊息佇列中,其他的系統,誰需要,自己去 訊息佇列 取就完了。

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

流量消峰&日誌收集

假設你有一個系統,平時正常的時候每秒可能就幾百個請求,系統部署在8核16G的機器的上,正常處理都是ok的,每秒幾百請求是可以輕鬆抗住的。

但是如下圖所示,在高峰期一下子來了每秒鐘幾千請求,瞬時出現了流量高峰,此時你的選擇是要搞10臺機器,抗住每秒幾千請求的瞬時高峰嗎?

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

那如果瞬時高峰每天就那麼半個小時,接著直接就降低為了每秒就幾百請求,如果你線上部署了很多臺機器,那麼每臺機器就處理每秒幾十個請求就可以了,這不是有點浪費機器資源嗎?

大部分時候,每秒幾百請求,一臺機器就足夠了,但是為了抗那每天瞬時的高峰,硬是部署了10臺機器,每天就那半個小時有用,別的時候都是浪費資源的。

此時我們就可以使用訊息佇列來幫忙了,進行消峰。所有機器前面部署一層MQ,平時每秒幾百請求大家都可以輕鬆接收訊息。

一旦到了瞬時高峰期,一下湧入每秒幾千的請求,就可以積壓在MQ裡面,然後那一臺機器慢慢的處理和消費。

等高峰期過了,再消費一段時間,MQ裡積壓的資料就消費完畢了。

如下圖:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

以上內容來自於【石杉的架構筆記】,圖是自個畫的,算是自己的一些理解吧。

要了解他的更多內容,移步 juejin.im/user/5be058…

訊息佇列有哪些

四種常用的訊息佇列 ActiveMQ、RabbitMQ、RocketMQ、Kafka

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

juejin.im/post/5b41fe…

Kafka 是什麼

Kafka是一種高吞吐量的分散式釋出訂閱訊息系統,使用Scala編寫。

對於熟悉JMS(Java Message Service)規範的同學來說,訊息系統已經不是什麼新概念了(例如ActiveMQ,RabbitMQ等)。

Kafka擁有作為一個訊息系統應該具備的功能,但是確有著獨特的設計。可以這樣來說,Kafka借鑑了JMS規範的思想,但是確並沒有完全遵循JMS規範。

kafka是一個分散式的,分割槽的訊息(官方稱之為commit log)服務。它提供一個訊息系統應該具備的功能,但是確有著獨特的設計。首先,讓我們來看一下基礎的訊息(Message)相關術語:

  • Topic: Kafka按照Topic分類來維護訊息
  • Producer: 我們將釋出(publish)訊息到Topic的程式稱之為生產者(producer)
  • Consumer: 我們將訂閱(subscribe)Topic並且處理Topic中訊息的程式稱之為消費者(consumer)
  • Broker: Kafka以叢集的方式執行,叢集中的每一臺伺服器稱之為一個代理(broker)。

因此,從一個較高的層面上來看,producers 通過網路傳送訊息到Kafka叢集,然後consumers來進行消費,如下圖:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

服務端(brokers)和客戶端(producer、consumer)之間通訊通過TCP協議來完成。我們為Kafka提供了一個Java客戶端,但是也可以使用其他語言編寫的客戶端。

Kafka的架構圖

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

Kafka的核心概念

Topic 和 Log

讓我們首先深入理解Kafka提出一個高層次的抽象概念 --Topic。

可以理解Topic是一個類別的名稱,所有的message傳送到Topic下面。對於每一個Topic,kafka叢集按照如下方式維護一個分割槽(Partition,可以就理解為一個佇列Queue)日誌檔案:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

partition 是一個有序的 message 序列,這些 message 按順序新增到一個叫做 commit log 的檔案中。每個 partition 中的訊息都有一個唯一的編號,稱之為 offset,用來唯一標示某個分割槽中的message。

partition 支援訊息位移讀取,訊息位移有消費者自身管理,比如下圖:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

由上圖可以看出,不同消費者對同一分割槽的訊息讀取互不干擾,消費者可以通過設定訊息位移(offset)來控制自己想要獲取的資料,比如:可以從頭讀取,最新資料讀取,重讀讀取等功能。

Distribution

log 的 partitions 分佈在 kafka 叢集中不同的 broker 上,每個 broker 可以請求備份其他broker 上 partition 上的資料。kafka 叢集支援配置一個 partition 備份的數量。針對每個partition,都有一個 broker 起到“leader”的作用,0個多個其他的 broker 作為“follwers”的作用。

leader 處理所有的針對這個 partition 的讀寫請求,而 followers 被動複製 leader 的結果。如果這個 leader 失效了,其中的一個 follower 將會自動的變成新的 leader。

每個 broker 都是自己所管理的 partition 的 leader,同時又是其他 broker 所管理 partitions 的 followers,kafka 通過這種方式來達到負載均衡。

Producers

生產者將訊息傳送到topic中去,同時負責選擇將message傳送到topic的哪一個partition中。通過round-robin做簡單的負載均衡。也可以根據訊息中的某一個關鍵字來進行區分。通常第二種方式使用的更多。

Consumers

傳統的訊息傳遞模式有2種:佇列( queuing)和( publish-subscribe)。

在queuing模式中,多個consumer從伺服器中讀取資料,訊息只會到達一個consumer。

在 publish-subscribe 模型中,訊息會被廣播給所有的consumer。

Kafka基於這2種模式提供了一種consumer的抽象概念:consumer group

每個consumer都要標記自己屬於哪一個consumer group。釋出到topic中的message中message會被傳遞到consumer group中的一個consumer 例項。consumer例項可以執行在不同的程式上,也可以在不同的物理機器上。

如果所有的consumer都位於同一個consumer group 下,這就類似於傳統的queue模式,並在眾多的consumer instance之間進行負載均衡。

如果所有的consumer都有著自己唯一的consumer group,這就類似於傳統的publish-subscribe模型。

更一般的情況是,通常一個topic會有幾個consumer group,每個consumer group都是一個邏輯上的訂閱者( logical subscriber )。每個consumer group由多個consumer instance組成,從而達到可擴充套件和容災的功能。這並沒有什麼特殊的地方,僅僅是將publish-subscribe模型中的執行在單個程式上的consumers中的consumer替換成一個consumer group。如下圖所示:

今天給公司小夥伴培訓的 Kafka 入門,瞭解一下?

說明:由2個broker組成的kafka叢集,總共有4個Parition(P0-P3)。這個叢集由2個Consumer Group, A有2個 consumer instances ,而B有四個.

消費順序

Kafka比傳統的訊息系統有著更強的順序保證。在傳統的情況下,伺服器按照順序保留訊息到佇列,如果有多個consumer來消費佇列中的訊息,伺服器 會接受訊息的順序向外提供訊息。

但是,儘管伺服器是按照順序提供訊息,但是訊息傳遞到每一個consumer是非同步的,這可能會導致先消費的 consumer獲取到訊息時間可能比後消費的consumer獲取到訊息的時間長,導致不能保證順序性。

這表明,當進行並行的消費的時候,訊息在多個 consumer之間可能會失去順序性。

訊息系統通常會採取一種“ exclusive consumer”的概念,來確保同一時間內只有一個consumer能夠從佇列中進行消費,但是這實際上意味著在訊息處理的過程中是不支援並行的。

Kafka在這方面做的更好。通過Topic中並行度的概念,即partition,Kafka可以同時提供順序性保證和多個consumer同時消費時的負載均衡。實現的原理是通過將一個topic中的partition分配給一個consumer group中的不同consumer instance。

通過這種方式,我們可以保證一個partition在同一個時刻只有一個consumer instance在訊息,從而保證順序。

雖然一個topic中有多個partition,但是一個consumer group中同時也有多個consumer instance,通過合理的分配依然能夠保證負載均衡。

需要注意的是,一個consumer group中的consumer instance的數量不能比一個Topic中的partition的數量多。如果多了,它將分配不上分割槽訊息。

Kafka只在partition的範圍內保證訊息消費的區域性順序性,不能在同一個topic中的多個partition中保證總的消費順序性。通常來說,這已經可以滿足大部分應用的需求。

但是,如果的確有在總體上保證消費的順序的需求的話,那麼我們可以通過將topic的partition數量設定為1,將consumer group中的consumer instance數量也設定為1。

但是這樣做,Kafka 的吞吐量就會下降。

kafka的安裝與使用

安裝前的環境準備

由於Kafka是用Scala語言開發的,執行在JVM上,因此在安裝Kafka之前需要先安裝JDK。

# yum install java-1.8.0-openjdk* -y
複製程式碼

kafka依賴zookeeper,所以需要先安裝zookeeper

# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
# tar -zxvf zookeeper-3.4.12.tar.gz
# cd zookeeper-3.4.12
# cp conf/zoo_sample.cfg conf/zoo.cfg 啟動zookeeper
# bin/zkServer.sh start
# bin/zkCli.sh
# ls /   #檢視zk的根目錄相關節點
複製程式碼

第一步:下載安裝包

下載1.1.0 release版本,並解壓:

# wget https://archive.apache.org/dist/kafka/1.1.0/kafka_2.11-1.1.0.tgz
# tar -xzf kafka_2.11-1.1.0.tgz
# cd kafka_2.11-1.1.0
複製程式碼

第二步:啟動服務

現在來啟動kafka服務: 啟動指令碼語法:kafka-server-start.sh [-daemon] server.properties

可以看到,server.properties的配置路徑是一個強制的引數,-daemon表示以後臺程式執行,否則ssh客戶端退出後,就會停止服務。(注意,在啟動kafka時會使用linux主機名關聯的ip地址,所以需要把主機名和linux的ip對映配置到本地host裡,用vim /etc/hosts)

# bin/kafka-server-start.sh -daemon config/server.properties
複製程式碼

我們進入zookeeper目錄通過zookeeper客戶端檢視下zookeeper的目錄樹

# bin/zkCli.sh
# ls /   #檢視zk的根目錄kafka相關節點
# ls /brokers/ids #檢視kafka節點
複製程式碼

第三步:建立主題

現在我們來建立一個名字為“test”的Topic,這個topic只有一個partition,並且備份因子也設定為1:

# bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
複製程式碼

現在我們可以通過以下命令來檢視kafka中目前存在的topic

# bin/kafka-topics.sh --list --zookeeper localhost:2181
複製程式碼

除了我們通過手工的方式建立Topic,我們可以配置broker,當producer釋出一個訊息某個指定的Topic,但是這個Topic並不存在時,就自動建立。

第四步:傳送訊息

kafka自帶了一個producer命令客戶端,可以從本地檔案中讀取內容,或者我們也可以以命令列中直接輸入內容,並將這些內容以訊息的形式傳送到kafka叢集中。在預設情況下,每一個行會被當做成一個獨立的訊息。

首先我們要執行釋出訊息的指令碼,然後在命令中輸入要傳送的訊息的內容:

# bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
>this is a msg
>this is a another msg
複製程式碼

第五步:消費訊息

對於consumer,kafka同樣也攜帶了一個命令列客戶端,會將獲取到內容在命令中進行輸出:

# bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test   --from-beginning #老版本

# bin/kafka-console-consumer.sh --bootstrap-server localhost:9092  --consumer-property group.id=testGroup --consumer-property client.id=consumer-1  --topic test    #新版本
複製程式碼

如果你是通過不同的終端視窗來執行以上的命令,你將會看到在producer終端輸入的內容,很快就會在consumer的終端視窗上顯示出來。

Kafka實操的一些命令

啟動zk 
bin/zkServer.sh start
啟動kafka
bin/kafka-server-start.sh config/server.properties &
停止kafka 如果不管用 就是用kill -9 
bin/kafka-server-stop.sh
1.建立主題
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
2.列出主題
bin/kafka-topics.sh --list --zookeeper localhost:2181
3.生產訊息
bin/kafka-console-producer.sh --broker-list localhost:9092 -topic test
4.消費訊息
bin/kafka-console-consumer.sh --zookeeper localhost:2181 -topic test --from-beginning
5.刪除主題
 1. 刪除 kafka 主題 
    bin/kafka-topics.sh --delete --zookeeper localhost:2181 --topic sceniccenter-base-ticket
 2. 在kafka 資料目錄刪除主題資料夾
 3. 刪除 zookeeper 上的 記錄
    1)登入zookeeper客戶端:命令:./zkCli.sh 
        2)找到topic所在的目錄:ls /brokers/topics
        3)找到要刪除的topic,執行命令:rmr /brokers/topics/【topic name】即可,此時topic被徹底刪除。    
    另外被標記為 marked for deletion 的topic你可以在zookeeper客戶端中通過命令獲得: ls /admin/delete_topics/【topic name】
  總結  徹底刪除topic:
     1、刪除kafka儲存目錄(server.properties檔案log.dirs配置,預設為"/tmp/kafka-logs")相關topic目錄
     2、如果配置了delete.topic.enable=true直接通過命令刪除,如果命令刪除不掉,直接通過 zookeeper-client 刪除掉broker下的topic即可。
6.檢視toplic 的分割槽等情況 
bin/kafka-topics --describe --zookeeper hadoop1:2181 --topic wwcc1
Topic:wwcc1    PartitionCount:3    ReplicationFactor:3    Configs:
    Topic: wwcc1    Partition: 0    Leader: 127    Replicas: 127,128,129    Isr: 127,128,129
    Topic: wwcc1    Partition: 1    Leader: 128    Replicas: 128,129,127    Isr: 128,129,127
    Topic: wwcc1    Partition: 2    Leader: 129    Replicas: 129,127,128    Isr: 129,127,128

複製程式碼

一些學習地址

系統架構中為什麼要用訊息中介軟體-中華石杉:juejin.im/post/5c0fba…

官方地址:kafka.apache.org/

中文教程: orchome.com/kafka/index

訊息中介軟體MQ詳解:blog.51cto.com/leexide/210…

相關文章