自從 2011 年被捐獻(xiàn)給 Apache 基金會到現(xiàn)在,Kafka 項目已經(jīng)走過了七個年頭。作為一個優(yōu)秀的分布式消息系統(tǒng),Kafka 已經(jīng)被許多企業(yè)采用并成為其大數(shù)據(jù)架構(gòu)中不可或缺的一部分。但 Kafka 的野心明顯不止于此。從去年 11 月推出 KSQL,到今年 7 月發(fā)布 2.0 版本增加諸多新特性,無不是在宣告:Kafka 已經(jīng)不再只是分布式消息隊列,而是集成了分發(fā)、存儲和計算的“流式數(shù)據(jù)平臺”。
與此同時,競爭對手的崛起也給 Kafka 的未來帶來了新的變數(shù)。在今年 9 月 InfoWorld 發(fā)布的最佳開源數(shù)據(jù)庫與數(shù)據(jù)分析平臺獎中,大數(shù)據(jù)新秀 Pulsar 首次獲獎,而在獲獎點評中明確提到“Pulsar 旨在取代 Apache Kafka 多年的主宰地位”。
從最早的“分布式消息系統(tǒng)”,到現(xiàn)在集成了分發(fā)、存儲和計算的“流式數(shù)據(jù)平臺”,Kafka 經(jīng)歷了哪些挑戰(zhàn)?又經(jīng)過了什么樣的演進(jìn)變化?Kafka 社區(qū)踩過哪些“坑”?本文將為你一一道來。本文整理自王國璋老師在 QCon 2018 上海站的演講。
Kafka 的小歷史
嘗試
Kafka 是 2010 年左右在 LinkedIn 研發(fā)的一套流數(shù)據(jù)處理平臺。當(dāng)時 LinkedIn 也和很多大的互聯(lián)網(wǎng)公司一樣,分很多的組,有很多的產(chǎn)品,每天收集非常多的數(shù)據(jù)。這些數(shù)據(jù)都是實時生成的,比如用戶活躍度、日志,我們有各種各樣的產(chǎn)品來利用這些數(shù)據(jù),數(shù)據(jù)的產(chǎn)生者和消費者之間采用點對點的數(shù)據(jù)傳輸,在運維方面非常耗費人力和物力。所以我們需要一個集中式的數(shù)據(jù)通道,所有的人都只跟這個數(shù)據(jù)通道進(jìn)行交互,不再點對點地傳輸數(shù)據(jù)。
從 2010 年開始,我們開始做這方面的嘗試,包括消息系統(tǒng)和 MQ 系統(tǒng)。但是后來發(fā)現(xiàn),所有這些 MQ 系統(tǒng)都有兩個比較通用的缺陷:一是當(dāng)消費者出現(xiàn),無法及時消費的時候,數(shù)據(jù)就會丟掉;二是可延展性問題,MQ 系統(tǒng)很難很好地配合數(shù)據(jù)的波峰或波谷。
所以 2010 年我們開始自己開發(fā) Kafka。它的設(shè)計理念非常簡單,就是一個以 append-only 日志作為核心的數(shù)據(jù)存儲結(jié)構(gòu)。簡單來說,就是我們把數(shù)據(jù)以日志的方式進(jìn)行組織,所有對于日志的寫操作,都提交在日志的最末端,對日志也只能是順序讀取。Kafka 的日志存儲是持久化到磁盤上的,雖然普遍感覺上 HDD 非常慢,但其實如果能夠把所有的讀和寫都按照順序來進(jìn)行操作,會發(fā)現(xiàn)它幾乎可以媲美內(nèi)存的隨機訪問。另外,我們直接使用文件系統(tǒng)的緩存,如果你讀取的基本上是在日志最尾端,那么絕大可能性只會訪問到這個文件系統(tǒng)的緩存,而不需落盤。所以它的速度非???。
接下來要做的是如何做到規(guī)模上的可延展性,我們把所有的數(shù)據(jù)以 Topic 為單位來組織,每個 Topic 可以被分片,存儲在不同的服務(wù)器上。數(shù)據(jù)的發(fā)布和訂閱都基于 Topic,數(shù)據(jù)更新時,消費端的客戶端會自動把它們從服務(wù)器上拉取下來?;?Partition 的擴容會變得非常簡單,增加 Partition,然后把它們放在新加入的服務(wù)器上,就可以保證 Topic 不斷擴容。
歡迎工作一到五年的Java工程師朋友們加入Java技術(shù)交流:611481448
群內(nèi)提供免費的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構(gòu)資料)合理利用自己每一分每一秒的時間來學(xué)習(xí)提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
0.7 版本,進(jìn)入 Apache 孵化器
大概不到一年之后, Kafka 就進(jìn)入了 Apache 孵化器,并且發(fā)布了第一個開源的版本 0.7.0。最主要的兩個特征就是壓縮以及 MirrorMaker,也就是跨集群之間的數(shù)據(jù)拷貝。
關(guān)于壓縮,我們是按純字節(jié)組織數(shù)據(jù)的,也就是說在 0.7.0 版本里面的偏移量是基于字節(jié)的。當(dāng)一個發(fā)布者客戶端積攢了很多數(shù)據(jù),要一次性發(fā)布的時候,所有這些數(shù)據(jù)會被打包成為一個大的 Wrapper message,它可能會包含很多真正的 Message。Wrapper message 其實會存儲的所有這些 Message 是加在一起的總的數(shù)據(jù)偏移量,比如每個 message 是 100,那么總偏移量就是 300。壓縮,就是要讓它的字節(jié)數(shù)變少。舉個例子,比方說壓縮之前是 300 字節(jié),壓縮后變成了 50 字節(jié)。
但這樣的做法,數(shù)據(jù)的消費端提交這個偏移量的時候,它就只能提交在這些大的、壓縮過的 Wrapper message 的邊界上。比如,消費一個大的 Message 的時候,這個 Message 里面有一百條數(shù)據(jù),只有把這一百條數(shù)據(jù)全部都消費完以后,才能提交準(zhǔn)確的偏移量。原因在于,這個偏移量是壓縮過后的偏移量,中途停止或者失敗的話,無法提交一個中間的偏移量。這是我們當(dāng)時用物理的字節(jié)作為偏移量的一個弊端,這對于用戶來說不夠靈活。但它的好處是,服務(wù)器不需要知道任何關(guān)于這個數(shù)據(jù)的元數(shù)據(jù),它是 bytes-in-bytes-out,而所有的邏輯都是在客戶端的。度量結(jié)果顯示,服務(wù)器端的 CPU 利用率基本上不到 10%,而網(wǎng)絡(luò) 99.9% 的時間都是滿的,也就是說我們基本上完全利用了所有的網(wǎng)絡(luò)帶寬。
在 2010 年的時候,我們基本上所有的 Traffic 和 Logging Data 都已經(jīng)通過 Kafka 來傳輸了,這是 Kafka 當(dāng)時在領(lǐng)英的第一個用戶,也可以說是第一個使用場景。
0.8 版本,高可用性
在 2012 年的時候,Kafka 就正式從孵化器里面畢業(yè),成為了 Apache 的頂級項目。同時,我們發(fā)布了 0.8.0。日后來看,它是一個將 Kafka 區(qū)別于非常多其他流數(shù)據(jù)平臺的版本。因為我們在 0.8.0 里面加入了高可用性,也就是基于備份的一個高可用性的特性。
在之前,一個服務(wù)器端失敗了,會導(dǎo)致這個服務(wù)器端所存的流數(shù)據(jù)在恢復(fù)之前無法再被取得,更有甚者,這些流數(shù)據(jù)永遠(yuǎn)丟失了。這也是為什么在 0.7 版本的時候,當(dāng)時最大的使用場景是 Logging Data 以及 User Data,這些 Data 丟了就丟了,對于公司影響不是那么大。但是,如果要保存重要的數(shù)據(jù),每條價值幾美元,沒有高可用性是不合適的,所以在 0.8 版本里面我們提出要增加這樣一個特性。
這里我簡單講一下 Kafka 0.8 的 replication。每一個 Topic 都被分片 partition,每個 partition 會被備份到多臺機器上。我們把每個 partition 叫做一個 replica,至于 Partition 的 replica 置放,基本上是一個簡單的輪詢。比如,Topic1 的第一個 Partition 被分配到 123,第二個 Partition 被分配到 231 等等。每一個 Group 里,有一個 Partition 會成為 Leader,這個 Leader 來進(jìn)行所有讀寫請求的操作。也就是說,當(dāng)客戶端發(fā)布信息、讀取信息的時候,都是和這個 leader 交互,并且 Leader 負(fù)責(zé)把已經(jīng)發(fā)布的數(shù)據(jù)再備份到其他的 replica 上。
2011 年的時候呢,我們看了很多備份、管理數(shù)據(jù)的協(xié)議,提出了一個理念:對于流數(shù)據(jù),我們希望基于簡單的協(xié)議做數(shù)據(jù)備份,而備份之間的管理要基于復(fù)雜的協(xié)議。當(dāng)時很多產(chǎn)品都是以同一套協(xié)議來做兩件事情。所以,在 0.8 版本里面,相當(dāng)于我們自己開發(fā)了一套數(shù)據(jù)備份協(xié)議。
我們當(dāng)時提出了一個叫做 ISR,或者叫做實時備份列表的機制。我們把所有的備份分為已同步和未同步的備份。已同步的備份指,Leader 所有的 Data 在 replica 里面都有;未同步的很簡單,由于可能比較慢,或者備份還不完整,也許有些數(shù)據(jù)在 Leader 上面有,但是在 replica 上沒有。Leader 可以通過來管理這樣的一個列表來做到實時的修改。同時,發(fā)布者發(fā)布信息的時候,可以要求備份方式。
我們在 0.8 中通過一個控制器來做到備份的靈活處理,它主要包括三點:第一點就是通過 Zookeeper 來監(jiān)測每一個服務(wù)器是否還在運轉(zhuǎn),當(dāng)需要選擇新的 Leader 甚至 RSR 時,這個控制器可以進(jìn)行 Leader 的選舉,最后把這個 Leader 上新的數(shù)據(jù)發(fā)布到所有 broker 上。當(dāng)時我們做了很多測試,所有的客戶、所有的服務(wù)器端都跟 Zookeeper 進(jìn)行直接交互的話,那么 Zookeeper 的壓力會非常大。而這個控制器就起到一個在 Zookeeper 跟其他服務(wù)器之間協(xié)同的角色,也就是說只有控制器需要跟 Zookeeper 之間進(jìn)行大量的交互,當(dāng)它得到了一些新的元數(shù)據(jù)的更新以后,再把這些數(shù)據(jù)發(fā)布到其他所有的 broker 上。
在 2012 年的時候,Kafka 就已經(jīng)在 LinkedIn 公司內(nèi)部完成了對所有在線流數(shù)據(jù)的傳輸整合,不僅對 LinkedIn 內(nèi)部,對整個業(yè)界也產(chǎn)生了很大的影響。由于這個高可用性的特性,Kafka 脫穎而出,成為了當(dāng)時整合流數(shù)據(jù)傳輸?shù)募惺酵ǖ赖母眠x擇。
在 0.8 版本里我們還更新了消息的數(shù)據(jù)結(jié)構(gòu),把數(shù)據(jù)偏移量改成了按邏輯的,每條信息的數(shù)據(jù)偏移量就是 1,不管消息有多大。當(dāng)壓縮和解壓縮時,你就需要知道壓縮過后的數(shù)據(jù)里包含了多少小數(shù)據(jù),可以通過增加偏移量來增加大數(shù)據(jù)的偏移量。舉個例子,第一個大的數(shù)據(jù),壓縮包里面包含了三個小數(shù)據(jù),它們本身的偏移量是 012,那么包壓縮的偏移量就是 2,也就是最后那個數(shù)據(jù)所對應(yīng)的邏輯偏移量。當(dāng)下一個消息被發(fā)布的時候,再根據(jù)已有的偏移量和壓縮的數(shù)據(jù)重新計算偏移量。所以在 0.8 里,已經(jīng)逐漸將系統(tǒng)性能壓力向 CPU 轉(zhuǎn)移,要花一些 CPU 來做解壓縮、重新壓縮、偏移量的計算,以及由于加了數(shù)據(jù)的備份,CPU 占用率在當(dāng)時已經(jīng)不再是 10% 了。
0.9 版本,配額和安全性
2014 年,我們成立了 Confluent,是當(dāng)時 LinkedIn Kafka 的幾個技術(shù)核心人員離開公司成立的基于 Kafka 的流數(shù)據(jù)平臺公司。同年,發(fā)布了 0.8.2 和 0.9.0,在 0.9.0 這個版本里面,加入了兩個非常重要的特性,配額和安全性。
當(dāng) Kafka 集群不斷變大、使用場景不斷增多的時候,多租戶之間的影響就會非常顯著,一個人可以影響其他所有用戶。當(dāng)時,有一個員工寫的客戶端,當(dāng)獲取元數(shù)據(jù)失敗時會一直發(fā)請求,并部署到了幾十臺機器上,結(jié)果就影響了所有的其他用戶。所以我們在 0.9 里第一個要加的重大機制就是配額,限定每一個 user 能夠用多大的流量跟 Kafka 交互。如果你超過配額,Kafka broker 就故意延遲你的請求,使一個 User 不會影響別人。這就是 0.9 的配額機制。
另一個很重要的機制是安全性,我們現(xiàn)在都知道安全性很大的三個方面就是授權(quán)、認(rèn)證、加密。授權(quán)、認(rèn)證說的直白一點,就是誰能干什么,這個誰就是認(rèn)證,能干什么就是授權(quán)。那么認(rèn)證在 Kafka 0.9 版本里面,我們用的是 SSL 認(rèn)證。認(rèn)證是一個一次性的過程,也就是說當(dāng)一個新的客戶端,第一次和服務(wù)器端建立連接的時候,會通過 SSL 進(jìn)行一次認(rèn)證。但是授權(quán),讀、寫、修改或者管理操作的時候,每一次都需要做我們所謂的授權(quán)檢查。
當(dāng)然了,這些授權(quán)和認(rèn)證其實對我們的性能是有一定影響的。正如剛剛我提到的 Kafka 本身的高性能來自于幾點,一是用日志作為文件存儲系統(tǒng);二是利用文件系統(tǒng)作為緩存;三是我們當(dāng)時采用了 Java 7 中新加入的零拷貝機制,原來將數(shù)據(jù)從磁盤寫入網(wǎng)卡需要經(jīng)過四次拷貝,有了零拷貝機制能夠省去其中從用戶端到內(nèi)核端的數(shù)據(jù)拷貝過程。但我們加了安全機制,除了認(rèn)證和授權(quán)以外,還做了數(shù)據(jù)加密,即使別人惡意竊聽了你的網(wǎng)卡,也不能得到真正的數(shù)據(jù)。由于這些中間處理,就不能使用零拷貝機制直接把網(wǎng)卡數(shù)據(jù)寫入磁盤了,最后只能放棄了 Java 7 里新加的零拷貝機制。
好在在 Java 11 對 TLS 做了重大的性能改革。我們自己做的基準(zhǔn)測試顯示,在 0.9 版本如果加入了加密和 SSL,Kafka 的性能可能會有 20% 甚至 23% 左右的影響。后來我們到了 Kafka 0.10、0.11 以后,用了 Java 11,性能只會受到最多 9% 的影響。
在 0.9 版本里面加了授權(quán)和認(rèn)證以后,就發(fā)現(xiàn)了一個非常新的使用場景,就是用 Kafka 來作為數(shù)據(jù)庫、多數(shù)據(jù)中心數(shù)據(jù)復(fù)制的骨干,當(dāng)拷貝元數(shù)據(jù)從一個數(shù)據(jù)中心到另外一個數(shù)據(jù)中心的時候,很多人開始使用 Kafka 來拷貝數(shù)據(jù)捕獲。因為我們加入了配額和安全性,很多用戶開始敢于把數(shù)據(jù)敏感、安全性敏感、延遲性敏感的使用場景放到 Kafka 集群上。
另外一個非常重要的新特性,就是基于消息 Key 的清理。在 0.8 版本以前,Kafka 僅以時間或者數(shù)據(jù)大小來清理,可以配置為數(shù)據(jù)存四天,過期一天的數(shù)據(jù)就自動清理掉。但數(shù)據(jù)其實是以 Key 作為標(biāo)識的,所以數(shù)據(jù)清理的時候,應(yīng)該是以 Key 作為核心,而不是通過時間。即使 7 天之內(nèi)沒有被更新過,也不代表它就應(yīng)該被清理掉。
由于這些特性的加入,現(xiàn)在 CPU 上要做壓縮、解壓縮、加密、解密、備份間的協(xié)調(diào)等操作,所以對 CPU 的消耗逐漸加大了,但網(wǎng)絡(luò)帶寬一直不變。
0.10 版本,更細(xì)粒度的時間戳
0.10 版本里,我們又加入了一個非常重要的特性,就是時間戳,除了語義上的增強,也是對于 CPU 損耗的優(yōu)化。在 0.9 版本或者更老的版本里面,對于時間的概念是非常粗粒度的,每一個分片是一個文件,所有 record 僅以這個文件的時間作為基準(zhǔn),也就是說 record 在語義上的時間被認(rèn)為是一樣的。那么當(dāng)需要依據(jù)時間進(jìn)行回溯時,無法得到非常確切的偏移量。在 0.10 版本里面,對每一個 record 會打一個具體的時間戳,發(fā)布端生成一個新的 record 時可以打一個時間戳,這樣可以有細(xì)粒度的時間管理,并且可以基于偏移量進(jìn)行快速的數(shù)據(jù)查找,找到所要的時間戳。
這樣首先可以做到更細(xì)粒度的 log rolling/log retention;第二,很多基于時間上的操作的準(zhǔn)確性大大提升。每個時間戳可以有兩種語義,第一種是發(fā)布的時候在客戶端可以蓋一個時間戳;第二種客戶端不蓋,交由 broker,當(dāng)它收到 record,append 到日志上時蓋一個時間戳。區(qū)別在于,append time 一定是順序的,而 create time 會是亂序的,因為會有很多 producer 同時蓋時間戳,發(fā)布到 partition 上。這是時間戳語義上的增強。
在性能上也有一個好處,在蓋時間戳的同時,把偏移量位移從絕對位移改成相對位移,當(dāng)一個壓縮包里面有位移的時候,只需要記錄相對位移,把相對位移加上絕對的基礎(chǔ)位移,就可以計算出絕對位移。它的好處是 0.10 版本的 producer 進(jìn)來的時候,不需要做解壓縮,但如果你是 0.9 和更老的版本請求進(jìn)來的時候,還需要做一步解壓縮和 up conversion。測試表明,這一改進(jìn)使 CPU 的占有率大大降低。
Kafka Streams 是在 0.10 里面加入的,它是一個流處理的平臺,或者叫它是流處理的一個庫。它是基于發(fā)布端和消費端的處理平臺,它能夠做到的是 Event-at-a-time、Stateful,并且支持像 Windowing 這樣的操作,支持 Highly scalable、distributed、fault tolerant。所有這些都很大程度上利用了 Kafka broker,也就是服務(wù)器端本身的延展性和高可用性。因為 Kafka Streams 是一個庫,也就是說,你不只是在很大的集群上,甚至在筆記本電腦上、黑莓上都可以安裝它來進(jìn)行流處理的計算。而且你所要做的很簡單,只要把它作為你應(yīng)用的 dependency 進(jìn)行編程就可以了。用 Kafka Streams 編好流處理應(yīng)用的時候,可以用各種方法來部署和監(jiān)控。你可以只把它作為一個很普通的 Java 應(yīng)用,或者用 Docker 也可以,任何地點、任何時候、任何方式均可。這就是我們的設(shè)計初衷,如果你的集群管理已經(jīng)有自己的一套成熟工具,不需要再為了用 Kafka Streams 而進(jìn)行一些調(diào)整。
簡單來說,Kafka Streams 所做的就是從 Kafka 的 Topic 里實時地抓取數(shù)據(jù)。這個數(shù)據(jù)會通過用戶所寫拓?fù)浣Y(jié)構(gòu),把所有的 record 實時進(jìn)行 transform 之后,最終再寫回到 Kafka 里面,是個很簡單的流數(shù)據(jù)處理。那么它怎么做延展性呢?也很簡單,當(dāng)用戶寫好一個拓?fù)浣Y(jié)構(gòu)以后,可以在多個機器,或者多個容器、多個虛擬機、甚至是多個 CPU 上面,部署多個應(yīng)用,當(dāng)應(yīng)用同時進(jìn)行的時候,會利用 Kafka 自動地劃分每一個不同的應(yīng)用所抓取的不同 partition 的數(shù)據(jù)。
Kafka Streams 是基于 Kafka 流處理的一個庫。如果流處理操作平臺不在 Kafka 上,怎么把數(shù)據(jù)先寫到 Kafka,再用 Kafka Streams 呢?可以利用 Kafka Connect,它是一個 Kafka 的 ingress、egress 框架。元數(shù)據(jù)可以是一個數(shù)據(jù)庫,也可以是 Web Server,可以是各種各樣不同的數(shù)據(jù)節(jié)點,它可以通過 Kafka Connect 實時把數(shù)據(jù)導(dǎo)入到 Kafka 數(shù)據(jù)流里面,也可以通過 Kafka Connect 把 Kafka 的流數(shù)據(jù)實時導(dǎo)出到最終的終端上。Kafka Connect 本身是一個框架,我們歡迎所有人參與貢獻(xiàn)。到目前為止,我們已經(jīng)有了 45 個以上基于不同系統(tǒng)的 Kafka Connect 可以自動被下載和使用,其中開源社區(qū)、合作伙伴做了很多的貢獻(xiàn)。未來,我也希望能夠看到更多來自于國內(nèi)的同學(xué)參與到 Kafka Connect 框架的貢獻(xiàn)中。
1.0 & 1.1 版本,Exactly-Once 與運維性提升
大家共同的指標(biāo),是我們要?做到 Exactly-Once 才發(fā)布 1.0 版本,這才能使 Kafka 作為一個成熟的流數(shù)據(jù)平臺持續(xù)發(fā)展。
什么是 Exactly-Once?非 Exactly-Once 是指由于網(wǎng)絡(luò)延遲或其他各種原因,導(dǎo)致消息重復(fù)發(fā)送甚至重復(fù)處理。那么直白來說 Exactly-Once 的定義,就是從應(yīng)用的角度來說,當(dāng)發(fā)生了錯誤,希望做到每一個接收到的 record,處理結(jié)果會被反映到它的處理狀態(tài)中,一次且僅有一次,也就是 Exactly-Once。
那么在 0.11 以及之前的版本里面,Kafka 的用戶普遍是如何保證 Exactly-Once 的呢?很簡單,就是基于 Kafka 的 At-Least-Once 加上去重,把處理過的 record 記錄下來,發(fā)現(xiàn)重復(fù)處理時就把它扔掉。這樣做的復(fù)雜性在于,對于一個機構(gòu)或者一個公司,實時操作系統(tǒng)不只是一個應(yīng)用,可以是多個應(yīng)用,每一個 output record 可能就是下一個應(yīng)用的 input record,那么做去重的時候,需要在每一個階段都做去重,這樣一是成本高,二是運維難度大。
所以在 0.11 里面,我們給兩個基礎(chǔ)的 Building blocks 來做 Exactly-Once。第一點是冪等性,意味著對于同一個 partition data 的多次發(fā)布,Kafka broker 端就可以做到自動去重;第二點是 Transactions,當(dāng)在一個事務(wù)下發(fā)布多條信息到多個 topic partition 時,我們可以使它以原子性的方式被完成?;谶@一點,我們在 Kafka Connect 和 Kafka Streams 上面就加入了簡單的 Exactly-Once 機制,也就是一個配置。以 Kafka Streams 為例,只要配置一個 config,就可以使 processing 從 At-Least-Once 變成 Exactly-Once。
在 0.11 以后,我們更加關(guān)注運維能力,因為大家反饋了很多這方面的問題。比如 Controller shut down,想要關(guān)閉一個 broker 的時候,需要一個很長很復(fù)雜的過程,需要通知所有 broker,完成所有相關(guān)操作,并完成相關(guān)記錄,才能完成整個 shut down 的過程。在這個過程中,需要發(fā)送很多次請求,對元數(shù)據(jù)進(jìn)行多次修改,這對于延遲性有很多的要求,使這個過程變得很緩慢,是當(dāng)時普遍存在的一個問題。所以在 1.0 和 1.1 版本,我們進(jìn)行了一次重寫,進(jìn)行了大面積的優(yōu)化。在 1.0 版本,在五個 broker node 的集群下,要進(jìn)行一次 Controller shutdown,10k partition per brocker 的規(guī)模,需要 6 分鐘的時間,而在 1.1 版本里只需要 3 秒鐘,而 Controller failover 的延遲也從 28 秒降到了 14 秒。除了 Controller,我們在 1.1 里對運維性、進(jìn)化性也做了很多工作。
未來愿景
Global Kafka:就是 Kafka 對于多數(shù)據(jù)中心的原生支持,我們想做到一個 Kafka 集群可以部署在多個數(shù)據(jù)中心。這需要 Kafka 能夠做到更好的延展性、更便捷的可運維性等。
Infinite Kafka:目前 Kafka 的用戶都是配置存儲 4 到 7 天或者最多一個月的數(shù)據(jù),但越來越多的用戶想在 Kafka 存儲過去更久的流數(shù)據(jù),但是同時不會因為長時效的數(shù)據(jù)流而導(dǎo)致數(shù)據(jù)拷貝或者遷移的時候造成大量延遲。這同時也意味著 Kafka 需要有更好的云架構(gòu)兼容性。
經(jīng)驗教訓(xùn)
構(gòu)建可進(jìn)化的系統(tǒng)
Kafka 作為一個流處理平臺,是一個不斷進(jìn)化的平臺,也就是說,你不能把 Kafka Shut down 來進(jìn)行更新,只能一邊用一邊更新。
我們在 0.8 版本里面改了數(shù)據(jù)格式,但是并沒有一個非常好的升級補丁。當(dāng)時很多人的做法是通過數(shù)據(jù)復(fù)制器把 0.7 版本的數(shù)據(jù)同步復(fù)制到 0.8 版本的集群里,也就說在很長一段時間內(nèi),需要同時運維 0.7 版本和 0.8 版本的 Kafka 集群,只有當(dāng) 0.7 版本的所有客戶端全部轉(zhuǎn)移到 0.8 版本以后,才能關(guān)閉 0.7 版本的客戶端。這是一個非常痛苦和漫長的過程。所以我們現(xiàn)在認(rèn)為,當(dāng)你需要構(gòu)建一個可以長時間使用并且永遠(yuǎn)不下線的系統(tǒng)時,在線可進(jìn)化性是最重要的特性。
要做到一個能夠?qū)崿F(xiàn)百分之百在線可進(jìn)化的系統(tǒng),首先要提供一個簡單的升級過程,其次能讓所有的用戶自主地、只通過閱讀文檔或者協(xié)議更新文件,就能做到在線升級。
只有能被度量的問題才能得到最終解決
如果想要知道,每一個發(fā)布的 record,是否最終通過了所有的 Kafka 集群,通過了所有的 Tier,最終到了消費端,并且到每個 Tier 的時候耗費了多少時間,只有對 Kafka 進(jìn)行全方位的觀測和監(jiān)測,才能知道哪里出現(xiàn)了問題,需要在哪里進(jìn)行優(yōu)化,需要在哪里進(jìn)行改進(jìn)。
API 保持不變
新版本發(fā)布后,所有 API 就再也不能變了。舉個例子,Kafka1481 是社區(qū)貢獻(xiàn)的一個特性,我們所有的度量是用下劃線作為分隔符,由于在很多系統(tǒng)中下滑線是不被允許的字符,我們就把下劃線改成了單杠,在當(dāng)時我們沒有想太多,就把合并到主干里了。結(jié)果,所有的度量板都變成白屏了。因為度量名中的分隔符從下劃線變成單杠,所有的度量項全都抓不到了。
所以我們每次設(shè)計 API 的時候,都要想清楚,到底這些 API 應(yīng)該怎么設(shè)計,每次做一個更新的時候,我們都要想,這個更新有沒有可能對用戶造成一些沒有想到的影響。
服務(wù)需要把關(guān)
一個壞用戶可以影響所有人。Kafka 進(jìn)化到 1.0 版本以后,更多的人開始在云上使用 Kafka,對安全性、多租戶的特性提出了更高的要求,包括端到端的加密、ACL/RBAC。除了安全性以外,在配額方面也有更多新的要求,不僅要有流量的限制,還有 CPU 的限制。
生態(tài)系統(tǒng)是關(guān)鍵
生態(tài)系統(tǒng)對一個開源社區(qū)來說是非常重要的。舉個例子,當(dāng)時我們在 0.8.2 版本里面把所有的貢獻(xiàn)直接放到了 Kafka 里面,但是之后發(fā)現(xiàn),與其把所有的代碼、組件都放到一個 repo 里面,不如構(gòu)建一個原生態(tài)的生態(tài)系統(tǒng),比方說容器的支持、語言的支持,大家可以在官網(wǎng)上找到跟這些相關(guān)的所有生態(tài)系統(tǒng)的鏈接。
構(gòu)建一個開源產(chǎn)品或者開源項目的時候,要做的并不是把所有的組件或者所有的貢獻(xiàn)都放在同一個項目里面,而應(yīng)該構(gòu)建一個繁榮的開源生態(tài)系統(tǒng),所有人都可以基于核心組件做不同組件的開發(fā)。不同組件的開發(fā)維護周期也不一樣,不需要跟 Kafka 核心組件同步更新或者同步維護。
寫在最后
我們講了這么多,到底什么是 Kafka?
最早的時候,我們說 Kafka 是一個可擴展的訂閱發(fā)布的消息系統(tǒng);2013 年的時候,我們說 Kafka 是一個實時數(shù)據(jù)通道;2015 年的時候,我們說 Kafka 是一個分布式的備份 Log,同年,我們提出了 Kafka Architecture,是針對 Lamda Architecture 提出的一個新的框架,我們認(rèn)為 Kafka 是一個統(tǒng)一數(shù)據(jù)集成堆棧。
以微服務(wù)為例,什么是微服務(wù)?我們在構(gòu)建一個架構(gòu)的時候,每一個小組、每一個模塊只需要負(fù)責(zé)自己的生態(tài)和邏輯,而它跟所有其他小組或模塊的交互,都可以通過一個異步的流處理平臺來傳輸。形象一點說,可以把每一個應(yīng)用看作流水線上的一個工人,它從流水線的上端取得一個任務(wù),處理之后把結(jié)果發(fā)布到流水線的下端,而它的下端可能是下一個應(yīng)用的流水線的上端,每一個應(yīng)用之間只需要通過這樣一個異步的流水線來協(xié)作,每個應(yīng)用升級、運維、開發(fā)都是不需要進(jìn)行對偶或者重構(gòu)的,可以做到完全異步,這就是 Async Micro-Services 的核心。Kafka 在這樣一個架構(gòu)下被很多應(yīng)用作為異步的流式消息框的不二之選。
我們對于 Kafka 有這么多不同的理解,那么 Kafka 到底是什么?我的答案是,以上皆是。
最早的時候,我們說 Kafka 是一個訂閱消息系統(tǒng),但是從 0.7 版本一直升級到 1.0,或者說現(xiàn)在的 2.0 版本以后,Kafka 已經(jīng)進(jìn)化成為一個流處理平臺。這個平臺不光是流數(shù)據(jù)的發(fā)布,還能涵蓋流處理的存儲、處理、鏡像、備份等等,所有的用戶都可以在上面進(jìn)行各種各樣的實時流數(shù)據(jù)處理的應(yīng)用的開發(fā)以及維護。這是我想要說的關(guān)鍵的一點。
最后再提一下 Kafka 現(xiàn)在在全世界的應(yīng)用情況。今年上半年,我們做過一個統(tǒng)計,在福布斯 500 強公司里面,大概有 35% 的公司都在使用 Kafka。具體到不同的行業(yè),全世界前 10 大旅行公司中有 6 個在使用 Kafka,全世界最大的 10 個銀行有 7 個在用 Kafka,最大的 10 個保險公司有 8 個在用 Kafka,最大的 10 個通訊公司中有 9 個在用 Kafka。
可以看到,雖然 Kafka 在 2010 年發(fā)布 0.7 版本的時候還是一個由互聯(lián)網(wǎng)公司提出來的流數(shù)據(jù)的數(shù)據(jù)通道,但是發(fā)展到今天,它已經(jīng)橫跨了非常多的領(lǐng)域,在非常多的平臺上被用來做各種不同的事情,但其中有一個核心,就是這些事情都是針對實時流數(shù)據(jù)的處理。
喜歡小編輕輕點個關(guān)注吧!