在面試的時候,發現很多面試官特別愛問Kafka相關的問題,這也不難理解,誰讓Kafka是大數據領域中消息隊列的唯一王者,單機十萬級別的吞吐量,毫秒級別的延遲,這種天生的分佈式消息隊列,誰能不愛?
在最近的一場面試中,有個面試官看到簡歷中的項目上寫Kafka了,就直接開問Kafka,其他問題基本沒問。下面來看下面試官的Kafka八連問:
(以下答案是面試完之後整理而成,實際面試時只回答了大約三分之一)
1. 爲什麼要使用 kafka?
緩衝和削峯:上游數據時有突發流量,下游可能扛不住,或者下游沒有足夠多的機器來保證冗餘,kafka在中間可以起到一個緩衝的作用,把消息暫存在kafka中,下游服務就可以按照自己的節奏進行慢慢處理。
解耦和擴展性:項目開始的時候,並不能確定具體需求。消息隊列可以作爲一個接口層,解耦重要的業務流程。只需要遵守約定,針對數據編程即可獲取擴展能力。
冗餘:可以採用一對多的方式,一個生產者發佈消息,可以被多個訂閱topic的服務消費到,供多個毫無關聯的業務使用。
健壯性:消息隊列可以堆積請求,所以消費端業務即使短時間死掉,也不會影響主要業務的正常進行。
異步通信:很多時候,用戶不想也不需要立即處理消息。消息隊列提供了異步處理機制,允許用戶把一個消息放入隊列,但並不立即處理它。想向隊列中放入多少消息就放多少,然後在需要的時候再去處理它們。
2. Kafka消費過的消息如何再消費?
kafka消費消息的offset是定義在zookeeper中的, 如果想重複消費kafka的消息,可以在redis中自己記錄offset的checkpoint點(n個),當想重複消費消息時,通過讀取redis中的checkpoint點進行zookeeper的offset重設,這樣就可以達到重複消費消息的目的了
3. kafka的數據是放在磁盤上還是內存上,爲什麼速度會快?
kafka使用的是磁盤存儲。
速度快是因爲:
- 順序寫入:因爲硬盤是機械結構,每次讀寫都會尋址->寫入,其中尋址是一個“機械動作”,它是耗時的。所以硬盤 “討厭”隨機I/O, 喜歡順序I/O。爲了提高讀寫硬盤的速度,Kafka就是使用順序I/O。
- Memory Mapped Files(內存映射文件):64位操作系統中一般可以表示20G的數據文件,它的工作原理是直接利用操作系統的Page來實現文件到物理內存的直接映射。完成映射之後你對物理內存的操作會被同步到硬盤上。
- Kafka高效文件存儲設計: Kafka把topic中一個parition大文件分成多個小文件段,通過多個小文件段,就容易定期清除或刪除已經消費完文件,減少磁盤佔用。通過索引信息可以快速定位
message和確定response的 大 小。通過index元數據全部映射到memory(內存映射文件),
可以避免segment file的IO磁盤操作。通過索引文件稀疏存儲,可以大幅降低index文件元數據佔用空間大小。
注:
- Kafka解決查詢效率的手段之一是將數據文件分段,比如有100條Message,它們的offset是從0到99。假設將數據文件分成5段,第一段爲0-19,第二段爲20-39,以此類推,每段放在一個單獨的數據文件裏面,數據文件以該段中 小的offset命名。這樣在查找指定offset的
Message的時候,用二分查找就可以定位到該Message在哪個段中。- 爲數據文件建 索引數據文件分段 使得可以在一個較小的數據文件中查找對應offset的Message 了,但是這依然需要順序掃描才能找到對應offset的Message。
爲了進一步提高查找的效率,Kafka爲每個分段後的數據文件建立了索引文件,文件名與數據文件的名字是一樣的,只是文件擴展名爲.index。
4. Kafka數據怎麼保障不丟失?
分三個點說,一個是生產者端,一個消費者端,一個broker端。
- 生產者數據的不丟失
kafka的ack機制:在kafka發送數據的時候,每次發送消息都會有一個確認反饋機制,確保消息正常的能夠被收到,其中狀態有0,1,-1。
如果是同步模式:
ack設置爲0,風險很大,一般不建議設置爲0。即使設置爲1,也會隨着leader宕機丟失數據。所以如果要嚴格保證生產端數據不丟失,可設置爲-1。
如果是異步模式:
也會考慮ack的狀態,除此之外,異步模式下的有個buffer,通過buffer來進行控制數據的發送,有兩個值來進行控制,時間閾值與消息的數量閾值,如果buffer滿了數據還沒有發送出去,有個選項是配置是否立即清空buffer。可以設置爲-1,永久阻塞,也就數據不再生產。異步模式下,即使設置爲-1。也可能因爲程序員的不科學操作,操作數據丟失,比如kill -9,但這是特別的例外情況。
注:
ack=0:producer不等待broker同步完成的確認,繼續發送下一條(批)信息。
ack=1(默認):producer要等待leader成功收到數據並得到確認,才發送下一條message。
ack=-1:producer得到follwer確認,才發送下一條數據。
- 消費者數據的不丟失
通過offset commit 來保證數據的不丟失,kafka自己記錄了每次消費的offset數值,下次繼續消費的時候,會接着上次的offset進行消費。
而offset的信息在kafka0.8版本之前保存在zookeeper中,在0.8版本之後保存到topic中,即使消費者在運行過程中掛掉了,再次啓動的時候會找到offset的值,找到之前消費消息的位置,接着消費,由於 offset 的信息寫入的時候並不是每條消息消費完成後都寫入的,所以這種情況有可能會造成重複消費,但是不會丟失消息。
唯一例外的情況是,我們在程序中給原本做不同功能的兩個consumer組設置
KafkaSpoutConfig.bulider.setGroupid的時候設置成了一樣的groupid,這種情況會導致這兩個組共享同一份數據,就會產生組A消費partition1,partition2中的消息,組B消費partition3的消息,這樣每個組消費的消息都會丟失,都是不完整的。 爲了保證每個組都獨享一份消息數據,groupid一定不要重複纔行。
- kafka集羣中的broker的數據不丟失
每個broker中的partition我們一般都會設置有replication(副本)的個數,生產者寫入的時候首先根據分發策略(有partition按partition,有key按key,都沒有輪詢)寫入到leader中,follower(副本)再跟leader同步數據,這樣有了備份,也可以保證消息數據的不丟失。
5. 採集數據爲什麼選擇kafka?
採集層 主要可以使用Flume, Kafka等技術。
Flume:Flume 是管道流方式,提供了很多的默認實現,讓用戶通過參數部署,及擴展API.
Kafka:Kafka是一個可持久化的分佈式的消息隊列。 Kafka 是一個非常通用的系統。你可以有許多生產者和很多的消費者共享多個主題Topics。
相比之下,Flume是一個專用工具被設計爲旨在往HDFS,HBase發送數據。它對HDFS有特殊的優化,並且集成了Hadoop的安全特性。
所以,Cloudera 建議如果數據被多個系統消費的話,使用kafka;如果數據被設計給Hadoop使用,使用Flume。
6. kafka 重啓是否會導致數據丟失?
- kafka是將數據寫到磁盤的,一般數據不會丟失。
- 但是在重啓kafka過程中,如果有消費者消費消息,那麼kafka如果來不及提交offset,可能會造成數據的不準確(丟失或者重複消費)。
7. kafka 宕機瞭如何解決?
- 先考慮業務是否受到影響
kafka 宕機了,首先我們考慮的問題應該是所提供的服務是否因爲宕機的機器而受到影響,如果服務提供沒問題,如果實現做好了集羣的容災機制,那麼這塊就不用擔心了。
- 節點排錯與恢復
想要恢復集羣的節點,主要的步驟就是通過日誌分析來查看節點宕機的原因,從而解決,重新恢復節點。
8. 爲什麼Kafka不支持讀寫分離?
在 Kafka 中,生產者寫入消息、消費者讀取消息的操作都是與 leader 副本進行交互的,從 而實現的是一種主寫主讀的生產消費模型。
Kafka 並不支持主寫從讀,因爲主寫從讀有 2 個很明顯的缺點:
數據一致性問題:數據從主節點轉到從節點必然會有一個延時的時間窗口,這個時間 窗口會導致主從節點之間的數據不一致。某一時刻,在主節點和從節點中 A 數據的值都爲 X, 之後將主節點中 A 的值修改爲 Y,那麼在這個變更通知到從節點之前,應用讀取從節點中的 A 數據的值並不爲最新的 Y,由此便產生了數據不一致的問題。
延時問題:類似 Redis 這種組件,數據從寫入主節點到同步至從節點中的過程需要經歷 網絡→主節點內存→網絡→從節點內存 這幾個階段,整個過程會耗費一定的時間。而在 Kafka 中,主從同步會比 Redis 更加耗時,它需要經歷 網絡→主節點內存→主節點磁盤→網絡→從節 點內存→從節點磁盤 這幾個階段。對延時敏感的應用而言,主寫從讀的功能並不太適用。
而kafka的主寫主讀的優點就很多了:
- 可以簡化代碼的實現邏輯,減少出錯的可能;
- 將負載粒度細化均攤,與主寫從讀相比,不僅負載效能更好,而且對用戶可控;
- 沒有延時的影響;
- 在副本穩定的情況下,不會出現數據不一致的情況。