Kafka是一個優(yōu)秀的分布式消息隊列着憨,以高并發(fā)和高性能著稱柒爵,我們以簡單全面的視角剖析一下Kafka框架的設(shè)計。
作為一個分布式消息隊列一般有三個角色
- 服務(wù)端 即broker抄腔,負責消息的存儲楞抡,消費伟众,分區(qū)等管理
- 生產(chǎn)者 對于服務(wù)端來說也是一個客戶端,用于將消息發(fā)送到服務(wù)端
- 消費者 用于消費生產(chǎn)者生產(chǎn)的消息
服務(wù)端
服務(wù)端的架構(gòu)和Netty有些類似召廷,其實完全可以使用Netty實現(xiàn)凳厢,可能是考慮到框架的依賴以及包管理的原因,Kafka實現(xiàn)了一個迷你版本的Netty竞慢,對于Netty知道它使用了Reator模式實現(xiàn)先紫,所以kafka的服務(wù)端實現(xiàn)也不例外,下面我們來列舉一下關(guān)鍵的一些類:
- SocketServer 從名字我們可以知道它是服務(wù)端管理的核心類筹煮,用于管理服務(wù)端的連接遮精,消息的消費請求以及請求的響應(yīng)等,和Netty一樣里面有接待線程和工作線程寺谤,只不過將工作線程劃分得更具體仑鸥,分為同步集群消息的控制線程和接受處理生產(chǎn)和消費消息的數(shù)據(jù)線程。
- KafkaRequestHandler 這個才是真正的工作線程变屁,也就是實質(zhì)性干活的對象眼俊,SocketServer的Processer線程其實只是將請求緩存到RequestChannel,KafkaRequestHandler就是從RequestChannel的請求隊列里面獲取請求進行實質(zhì)的請求處理粟关,其實KafkaRequestHandler是將請求又交給了KafkaApis這個類處理疮胖,我們以發(fā)送請求為例描述一下過程:
首先請求過來將消息由Acceptor交給Processer處理,Processer將請求交給KafkaRequestHandler闷板,KafkaRequestHandler又將響應(yīng)消息交給Processer發(fā)送給客戶端澎灸,有沒有發(fā)現(xiàn)這個過程就像一個傳遞游戲,為什么Processer不直接將活干了遮晚,反而又KafkaRequestHandler處理事務(wù)呢性昭?原因就是拉長戰(zhàn)線,人多好干活县遣,KafkaRequestHandler就像一個蓄水池的容器將所有請求穩(wěn)在自己的池子里面滿滿處理糜颠,而Processer負責響應(yīng)請求就好了,這樣減輕Processer的很多負擔萧求,從而系統(tǒng)的吞吐量其兴。
生產(chǎn)者
生產(chǎn)者主要有以下幾個關(guān)鍵部件組成:
KafkaProducer 這個是生產(chǎn)者的主要類,用于供客戶端發(fā)布消息使用夸政,生產(chǎn)者發(fā)布消息必須要知道消息發(fā)布到哪里元旬,所以其依賴于元數(shù)據(jù)管理類ProducerMetadata,同時生產(chǎn)者發(fā)布消息不是馬上發(fā)布守问,需要把消息緩存到一個地方匀归,使用得是RecordAccumulator這個消息累加器,同時它還有自己的管家Sender酪碘,Sender使用NetworkClient進行消息發(fā)送朋譬,Sender又使用SendBuilder進行消息緩存,SendBuilder使用ByteBuffer進行消息的存儲兴垦,最終將消息緩存到KafkaChannel的send字段徙赢,NetworkClient又在poll方法使用Selector發(fā)送消息,最終真正的發(fā)送是在Selector的pollSelectionKeys方法完成探越,最終調(diào)用NetworkSend的writeTo方法狡赐,入?yún)⑹荰ransferableChannel,這個參數(shù)從哪里來钦幔?其實來自于Selector的connect方法枕屉,它是一個java NIO的SocketChannel類,NetworkSend的writeTo方法的send其實是ByteBufferSend鲤氢,它來自于SendBuilder的build方法構(gòu)建搀擂,調(diào)用flushPendingSend構(gòu)造產(chǎn)生西潘,代碼如下:
private void flushPendingSend() {
flushPendingBuffer();
if (!buffers.isEmpty()) {
ByteBuffer[] byteBufferArray = buffers.toArray(new ByteBuffer[0]);
addSend(new ByteBufferSend(byteBufferArray, sizeOfBuffers));
clearBuffers();
}
}
消費者
消費者的核心線程是KafkaConsumer,其核心方法是subscribe和poll哨颂,subscribe主要是用來進行主題訂閱喷市,里面有分區(qū)重平衡邏輯,poll方法借助于其核心組件Fetcher分區(qū)消息的拉取威恼,它的輔助組件是ConsumerNetworkClient品姓,其本質(zhì)還是NetworkClient的poll完成實質(zhì)的消息拉取,對于消費者過程相對比較簡單箫措,拉取的消息最終是緩存到Fetcher組件供KafkaConsumer使用腹备。