掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
作者:佚名 2017-07-27 14:32:05
大數(shù)據(jù)
分布式
Kafka Kafka是最初由Linkedin公司開發(fā),是一個分布式、分區(qū)的、多副本的、多訂閱者,基于zookeeper協(xié)調(diào)的分布式日志系統(tǒng)(也可以當做MQ系統(tǒng)),常見可以用于web/nginx日志、訪問日志,消息服務(wù)等等,Linkedin于2010年貢獻給了Apache基金會并成為頂級開源項目。

創(chuàng)新互聯(lián)為企業(yè)提供:品牌網(wǎng)站設(shè)計、網(wǎng)絡(luò)營銷策劃、小程序設(shè)計、營銷型網(wǎng)站建設(shè)和網(wǎng)站運營托管,一站式網(wǎng)絡(luò)營銷整體服務(wù)。實現(xiàn)不斷獲取潛在客戶之核心目標,建立了企業(yè)專屬的“成都全網(wǎng)營銷”,就用不著再為了獲取潛在客戶而苦惱,相反,客戶會主動找您,生意就找上門來了!
Kafka的基本介紹
Kafka是最初由Linkedin公司開發(fā),是一個分布式、分區(qū)的、多副本的、多訂閱者,基于zookeeper協(xié)調(diào)的分布式日志系統(tǒng)(也可以當做MQ系統(tǒng)),常見可以用于web/nginx日志、訪問日志,消息服務(wù)等等,Linkedin于2010年貢獻給了Apache基金會并成為***開源項目。
主要應(yīng)用場景是:日志收集系統(tǒng)和消息系統(tǒng)。
Kafka主要設(shè)計目標如下:
Kafka的設(shè)計原理分析
一個典型的kafka集群中包含若干producer,若干broker,若干consumer,以及一個Zookeeper集群。Kafka通過Zookeeper管理集群配置,選舉leader,以及在consumer group發(fā)生變化時進行rebalance。producer使用push模式將消息發(fā)布到broker,consumer使用pull模式從broker訂閱并消費消息。
Kafka專用術(shù)語:
Kafka數(shù)據(jù)傳輸?shù)氖聞?wù)特點
通常情況下”at-least-once”是我們***。
Kafka消息存儲格式
Topic & Partition
一個topic可以認為一個一類消息,每個topic將被分成多個partition,每個partition在存儲層面是append log文件。
在Kafka文件存儲中,同一個topic下有多個不同partition,每個partition為一個目錄,partiton命名規(guī)則為topic名稱+有序序號,***個partiton序號從0開始,序號***值為partitions數(shù)量減1。
這樣做的好處就是能快速刪除無用文件,有效提高磁盤利用率。
segment中index與data file對應(yīng)關(guān)系物理結(jié)構(gòu)如下:
上圖中索引文件存儲大量元數(shù)據(jù),數(shù)據(jù)文件存儲大量消息,索引文件中元數(shù)據(jù)指向?qū)?yīng)數(shù)據(jù)文件中message的物理偏移地址。
其中以索引文件中元數(shù)據(jù)3,497為例,依次在數(shù)據(jù)文件中表示第3個message(在全局partiton表示第368772個message),以及該消息的物理偏移地址為497。
了解到segment data file由許多message組成,下面詳細說明message物理結(jié)構(gòu)如下:
參數(shù)說明:
| 關(guān)鍵字 | 解釋說明 |
|---|---|
| 8 byte offset | 在parition(分區(qū))內(nèi)的每條消息都有一個有序的id號,這個id號被稱為偏移(offset),它可以唯一確定每條消息在parition(分區(qū))內(nèi)的位置。即offset表示partiion的第多少message |
| 4 byte message size | message大小 |
| 4 byte CRC32 | 用crc32校驗message |
| 1 byte “magic” | 表示本次發(fā)布Kafka服務(wù)程序協(xié)議版本號 |
| 1 byte “attributes” | 表示為獨立版本、或標識壓縮類型、或編碼類型。 |
| 4 byte key length | 表示key的長度,當key為-1時,K byte key字段不填 |
| K byte key | 可選 |
| value bytes payload | 表示實際消息數(shù)據(jù)。 |
副本(replication)策略
Kafka的高可靠性的保障來源于其健壯的副本(replication)策略。
1) 數(shù)據(jù)同步
kafka在0.8版本前沒有提供Partition的Replication機制,一旦Broker宕機,其上的所有Partition就都無法提供服務(wù),而Partition又沒有備份數(shù)據(jù),數(shù)據(jù)的可用性就大大降低了。所以0.8后提供了Replication機制來保證Broker的failover。
引入Replication之后,同一個Partition可能會有多個Replica,而這時需要在這些Replication之間選出一個Leader,Producer和Consumer只與這個Leader交互,其它Replica作為Follower從Leader中復(fù)制數(shù)據(jù)。
2) 副本放置策略
為了更好的做負載均衡,Kafka盡量將所有的Partition均勻分配到整個集群上。
Kafka分配Replica的算法如下:
3) 同步策略
Producer在發(fā)布消息到某個Partition時,先通過ZooKeeper找到該Partition的Leader,然后無論該Topic的Replication Factor為多少,Producer只將該消息發(fā)送到該Partition的Leader。Leader會將該消息寫入其本地Log。每個Follower都從Leader pull數(shù)據(jù)。這種方式上,F(xiàn)ollower存儲的數(shù)據(jù)順序與Leader保持一致。Follower在收到該消息并寫入其Log后,向Leader發(fā)送ACK。一旦Leader收到了ISR中的所有Replica的ACK,該消息就被認為已經(jīng)commit了,Leader將增加HW并且向Producer發(fā)送ACK。
為了提高性能,每個Follower在接收到數(shù)據(jù)后就立馬向Leader發(fā)送ACK,而非等到數(shù)據(jù)寫入Log中。因此,對于已經(jīng)commit的消息,Kafka只能保證它被存于多個Replica的內(nèi)存中,而不能保證它們被持久化到磁盤中,也就不能完全保證異常發(fā)生后該條消息一定能被Consumer消費。
Consumer讀消息也是從Leader讀取,只有被commit過的消息才會暴露給Consumer。
Kafka Replication的數(shù)據(jù)流如下圖所示:
對于Kafka而言,定義一個Broker是否“活著”包含兩個條件:
Leader會跟蹤與其保持同步的Replica列表,該列表稱為ISR(即in-sync Replica)。如果一個Follower宕機,或者落后太多,Leader將把它從ISR中移除。這里所描述的“落后太多”指Follower復(fù)制的消息落后于Leader后的條數(shù)超過預(yù)定值或者Follower超過一定時間未向Leader發(fā)送fetch請求。
Kafka只解決fail/recover,一條消息只有被ISR里的所有Follower都從Leader復(fù)制過去才會被認為已提交。這樣就避免了部分數(shù)據(jù)被寫進了Leader,還沒來得及被任何Follower復(fù)制就宕機了,而造成數(shù)據(jù)丟失(Consumer無法消費這些數(shù)據(jù))。而對于Producer而言,它可以選擇是否等待消息commit。這種機制確保了只要ISR有一個或以上的Follower,一條被commit的消息就不會丟失。
4) leader選舉
Leader選舉本質(zhì)上是一個分布式鎖,有兩種方式實現(xiàn)基于ZooKeeper的分布式鎖:
Majority Vote的選舉策略和ZooKeeper中的Zab選舉是類似的,實際上ZooKeeper內(nèi)部本身就實現(xiàn)了少數(shù)服從多數(shù)的選舉策略。kafka中對于Partition的leader副本的選舉采用了***種方法:為Partition分配副本,指定一個ZNode臨時節(jié)點,***個成功創(chuàng)建節(jié)點的副本就是Leader節(jié)點,其他副本會在這個ZNode節(jié)點上注冊Watcher監(jiān)聽器,一旦Leader宕機,對應(yīng)的臨時節(jié)點就會被自動刪除,這時注冊在該節(jié)點上的所有Follower都會收到監(jiān)聽器事件,它們都會嘗試創(chuàng)建該節(jié)點,只有創(chuàng)建成功的那個follower才會成為Leader(ZooKeeper保證對于一個節(jié)點只有一個客戶端能創(chuàng)建成功),其他follower繼續(xù)重新注冊監(jiān)聽事件。
Kafka消息分組,消息消費原理
同一Topic的一條消息只能被同一個Consumer Group內(nèi)的一個Consumer消費,但多個Consumer Group可同時消費這一消息。
這是Kafka用來實現(xiàn)一個Topic消息的廣播(發(fā)給所有的Consumer)和單播(發(fā)給某一個Consumer)的手段。一個Topic可以對應(yīng)多個Consumer Group。如果需要實現(xiàn)廣播,只要每個Consumer有一個獨立的Group就可以了。要實現(xiàn)單播只要所有的Consumer在同一個Group里。用Consumer Group還可以將Consumer進行自由的分組而不需要多次發(fā)送消息到不同的Topic。
Push vs. Pull
作為一個消息系統(tǒng),Kafka遵循了傳統(tǒng)的方式,選擇由Producer向broker push消息并由Consumer從broker pull消息。
push模式很難適應(yīng)消費速率不同的消費者,因為消息發(fā)送速率是由broker決定的。push模式的目標是盡可能以最快速度傳遞消息,但是這樣很容易造成Consumer來不及處理消息,典型的表現(xiàn)就是拒絕服務(wù)以及網(wǎng)絡(luò)擁塞。而pull模式則可以根據(jù)Consumer的消費能力以適當?shù)乃俾氏M消息。
對于Kafka而言,pull模式更合適。pull模式可簡化broker的設(shè)計,Consumer可自主控制消費消息的速率,同時Consumer可以自己控制消費方式——即可批量消費也可逐條消費,同時還能選擇不同的提交方式從而實現(xiàn)不同的傳輸語義。
Kafak順序?qū)懭肱c數(shù)據(jù)讀取
生產(chǎn)者(producer)是負責向Kafka提交數(shù)據(jù)的,Kafka會把收到的消息都寫入到硬盤中,它絕對不會丟失數(shù)據(jù)。為了優(yōu)化寫入速度Kafak采用了兩個技術(shù),順序?qū)懭牒蚆MFile。
順序?qū)懭?/strong>
因為硬盤是機械結(jié)構(gòu),每次讀寫都會尋址,寫入,其中尋址是一個“機械動作”,它是最耗時的。所以硬盤最“討厭”隨機I/O,最喜歡順序I/O。為了提高讀寫硬盤的速度,Kafka就是使用順序I/O。
每條消息都被append到該Partition中,屬于順序?qū)懘疟P,因此效率非常高。
對于傳統(tǒng)的message queue而言,一般會刪除已經(jīng)被消費的消息,而Kafka是不會刪除數(shù)據(jù)的,它會把所有的數(shù)據(jù)都保留下來,每個消費者(Consumer)對每個Topic都有一個offset用來表示讀取到了第幾條數(shù)據(jù)。
即便是順序?qū)懭胗脖P,硬盤的訪問速度還是不可能追上內(nèi)存。所以Kafka的數(shù)據(jù)并不是實時的寫入硬盤,它充分利用了現(xiàn)代操作系統(tǒng)分頁存儲來利用內(nèi)存提高I/O效率。
在Linux Kernal 2.2之后出現(xiàn)了一種叫做“零拷貝(zero-copy)”系統(tǒng)調(diào)用機制,就是跳過“用戶緩沖區(qū)”的拷貝,建立一個磁盤空間和內(nèi)存空間的直接映射,數(shù)據(jù)不再復(fù)制到“用戶態(tài)緩沖區(qū)”系統(tǒng)上下文切換減少2次,可以提升一倍性能。
通過mmap,進程像讀寫硬盤一樣讀寫內(nèi)存(當然是虛擬機內(nèi)存)。使用這種方式可以獲取很大的I/O提升,省去了用戶空間到內(nèi)核空間復(fù)制的開銷(調(diào)用文件的read會把數(shù)據(jù)先放到內(nèi)核空間的內(nèi)存中,然后再復(fù)制到用戶空間的內(nèi)存中。)
消費者(讀取數(shù)據(jù))
試想一下,一個Web Server傳送一個靜態(tài)文件,如何優(yōu)化?答案是zero copy。傳統(tǒng)模式下我們從硬盤讀取一個文件是這樣的。
先復(fù)制到內(nèi)核空間(read是系統(tǒng)調(diào)用,放到了DMA,所以用內(nèi)核空間),然后復(fù)制到用戶空間(1、2);從用戶空間重新復(fù)制到內(nèi)核空間(你用的socket是系統(tǒng)調(diào)用,所以它也有自己的內(nèi)核空間),***發(fā)送給網(wǎng)卡(3、4)。
Zero Copy中直接從內(nèi)核空間(DMA的)到內(nèi)核空間(Socket的),然后發(fā)送網(wǎng)卡。這個技術(shù)非常普遍,Nginx也是用的這種技術(shù)。
實際上,Kafka把所有的消息都存放在一個一個的文件中,當消費者需要數(shù)據(jù)的時候Kafka直接把“文件”發(fā)送給消費者。當不需要把整個文件發(fā)出去的時候,Kafka通過調(diào)用Zero Copy的sendfile這個函數(shù),這個函數(shù)包括:

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流