柚子快報邀請碼778899分享:分布式 Kafka問題紀要
柚子快報邀請碼778899分享:分布式 Kafka問題紀要
1. 取 如何獲取 topic 主題的列表
bin/kafka-topics.sh --list --zookeeper localhost:2181
2. 生產(chǎn)者和消費者的命令行是什么?
生產(chǎn)者在主題上發(fā)布消息: bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 --topicHello-Kafka 注意這里的 IP 是 server.properties 中的 listeners 的配置。接下來每個新行就是輸入一條 新消息。 消費者接受消息: bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topicHello-Kafka --from-beginning
3. consumer 是推還是拉?
Kafka 最初考慮的問題是,customer 應該從 brokes 拉取消息還是 brokers 將消息推送到 consumer,也就是 pull 還 push。在這方面,Kafka 遵循了一種大部分消息系統(tǒng)共同的傳統(tǒng) 的設計: producer 將消息推送到 broker,consumer 從 broker 拉取消息。 一些消息系統(tǒng)比如 Scribe 和 Apache Flume 采用了 push 模式,將消息推送到下游的 consumer。這樣做有好處也有壞處:由 broker 決定消息推送的速率,對于不同消費速率的 consumer 就不太好處理了。消息系統(tǒng)都致力于讓 consumer 以最大的速率最快速的消費消 息,但不幸的是,push 模式下, 當 broker 推送的速率遠大于 consumer 消費的速率時,consumer 恐怕就要崩潰了。最終 Kafka 還是選取了傳統(tǒng)的 pull 模式。 Pull 模式的另外一個好處是 consumer 可以自主決定是否批量的從 broker 拉取數(shù)據(jù) 。 Push 模式必須在不知道下游 consumer 消費能力和消費策略的情況下決定是立即推送每條 消息還是緩存之后批量推送。如果為了避免 consumer 崩潰而采用較低的推送速率,將可能 導致一次只推送較少的消息而造成浪費。Pull 模式下,consumer 就可以根據(jù)自己的消費能 力去決定這些策略。 Pull 有個缺點是,如果 broker 沒有可供消費的消息,將導致 consumer 不斷在循環(huán)中輪詢, 直到新消息到 t 達。為了避免這點,Kafka 有個參數(shù)可以讓 consumer 阻塞知道新消息到達 (當然也可以阻塞知道消息的數(shù)量達到某個特定的量這樣就可以批量發(fā)送)。
4. 講 講講 kafka 維護消費狀態(tài)跟蹤的方法
大部分消息系統(tǒng)在 broker 端的維護消息被消費的記錄:一個消息被分發(fā)到 consumer 后 broker 就 上進行標記或者等待 customer 的通知后進行標記。這樣也可以在消息在消費后 立 就刪除以減少空間占用。但是這樣會不會有什么問題呢?如果一條消息發(fā)送出去之后就 立即被標記為消費過的,旦 consumer 處理消息時失敗了(比如程序崩潰)消息就丟失了。 為了解決這個問題,很多消息系統(tǒng)提供了另外一個個功能:當消息被發(fā)送出去之后僅僅被標 記為已發(fā)送狀態(tài),當接到 consumer 已經(jīng)消費成功的通知后才標記為已被消費的狀態(tài)。這雖 然解決了消息丟失的問題,但產(chǎn)生了新問題,首先如果 consumer 處理消息成功了但是向 broker 發(fā)送響應時失敗了,這條消息將被消費兩次。第二個問題時,broker 必須維護每條 消息的狀態(tài),并且每次都要先鎖住消息然后更改狀態(tài)然后釋放鎖。這樣麻煩又來了,且不說 要維護大量的狀態(tài)數(shù)據(jù),比如如果消息發(fā)送出去但沒有收到消費成功的通知,這條消息將一 直處于被鎖定的狀態(tài),Kafka 采用了不同的策略。Topic 被分成了若干分區(qū),每個分區(qū)在同 一時間只被一個 consumer 消費。這意味著每個分區(qū)被消費的消息在日志中的位置僅僅是一 個簡單的整數(shù):offset。這樣就很容易標記每個分區(qū)消費狀態(tài)就很容易了,僅僅需要一個整 數(shù)而已。這樣消費狀態(tài)的跟蹤就很簡單了。 這帶來了另外一個好處:consumer 可以把 offset 調(diào)成一個較老的值,去重新消費老的消息。
5. 講一下主從同步
Kafka 允許 topic 的分區(qū)擁有若干副本,這個數(shù)量是可以配置的,你可以為每個 topci 配置副 本的數(shù)量。Kafka 會自動在每個個副本上備份數(shù)據(jù),所以當一個節(jié)點 down 掉時數(shù)據(jù)依然是 可用的。 Kafka 的副本功能不是必須的,你可以配置只有一個副本,這樣其實就相當于只有一份數(shù)據(jù)。
6. 為什么需要消息系統(tǒng),mysql 不能滿足需求嗎?
(1)解耦: 允許你獨立的擴展或修改兩邊的處理過程,只要確保它們遵守同樣的接口約束。 (2)冗余: 消息隊列把數(shù)據(jù)進行持久化直到它們已經(jīng)被完全處理,通過這一方式規(guī)避了數(shù)據(jù)丟失 險。 許多消息隊列所采用的”插入-獲取-刪除”范式中,在把一個消息從隊列中刪除之前,需要 你的處理系統(tǒng)明確的指出該消息已經(jīng)被處理完畢,從而確保你的數(shù)據(jù)被安全的保存直到你使 用完畢。 (3)擴展性: 因為消息隊列解耦了你的處理過程,所以增大消息入隊和處理的頻率是很容易的,只要另外 增加處理過程即可。 (4)靈活性 & 峰值處理能力: 在訪問量劇增的情況下,應用仍然需要繼續(xù)發(fā)揮作用,但是這樣的突發(fā)流量并不常 。如果 為以能處理這類峰值訪問為標準來投入資源隨時待命無疑是巨大的浪費。使用消息隊列能夠 使關鍵組件頂住突發(fā)的訪問壓力,而不會因為突發(fā)的超負荷的請求而完全崩潰。 (5)可恢復性: 系統(tǒng)的一部分組件失效時,不會影響到整個系統(tǒng)。消息隊列降低了進程間的耦合度,所以即 使一個處理消息的進程掛掉,加入隊列中的消息仍然可以在系統(tǒng)恢復后被處理。 (6)順序保證: 在大多使用場景下,數(shù)據(jù)處理的順序都很重要。大部分消息隊列本來就是排序的,并且能保 證數(shù)據(jù)會按照特定的順序來處理。(Kafka 保證一個 Partition 內(nèi)的消息的有序性) (7)緩沖: 有助于控制和優(yōu)化數(shù)據(jù)流經(jīng)過系統(tǒng)的速度,解決生產(chǎn)消息和消費消息的處理速度不一致的情 況。 (8)異步通信: 很多時候,用戶不想也不需要立即處理消息。消息隊列提供了異步處理機制,允許用戶把一 個消息放入隊列,但并不立即處理它。想向隊列中放入多少消息就放多少,然后在需要的時 候再去處理它們。
7. Zookeeper 于 對于 Kafka 的作用是什么?
Zookeeper 是一個開放源碼的、高性能的協(xié)調(diào)服務,它用于 Kafka 的分布式應用。 Zookeeper 主要用于在集群中不同節(jié)點之間進行通信 在 Kafka 中,它被用于提交偏移量,因此如果節(jié)點在任何情況下都失敗了,它都可以從之 前提交的偏移量中獲取除此之外,它還執(zhí)行其他活動,如: leader 檢測、分布式同步、配置 管理、識別新節(jié)點何時離開或連接、集群、節(jié)點實時狀態(tài)等等。
8. 數(shù)據(jù)傳輸?shù)氖聞斩x有哪三種?
和 MQ TT 的事務定義一樣都是 3 種。 (1)最多一次: 消息不會被重復發(fā)送,最多被傳輸一次,但也有可能一次不傳輸 (2)最少一次: 消息不會被漏發(fā)送,最少被傳輸一次,但也有可能被重復傳輸. (3)精確的一次(Exactly once): 不會漏傳輸也不會重復傳輸,每個消息都傳輸被一次而且 僅僅被傳輸一次,這是大家所期望的
9. Kafka 判斷一個節(jié)點是否還活著有那兩個條件?
(1)節(jié)點必須可以維護和 ZooKeeper 的連接,Zookeeper 通過心跳機制檢查每個節(jié)點的連 接 (2)如果節(jié)點是個 follower,他必須能及時的同步 leader 的寫操作,延時不能太久
10. Kafka 統(tǒng) 與傳統(tǒng) MQ 消息系統(tǒng)之間有三個關鍵區(qū)別
(1).Kafka 持久化日志,這些日志可以被重復讀取和無限期保留 (2).Kafka 是一個分布式系統(tǒng):它以集群的方式運行,可以靈活伸縮,在內(nèi)部通過復制數(shù)據(jù) 提升容錯能力和高可用性 (3).Kafka 支持實時的流式處理
11. 講 講一講 kafka 的 的 ack 的三種機制
request.required.acks 有三個值 0 1 -1(all) 0:生產(chǎn)者不會等待 broker 的 ack,這個延遲最低但是存儲的保證最弱當 server 掛掉的時候 就會丟數(shù)據(jù)。 1:服務端會等待 ack 值 leader 副本確認接收到消息后發(fā)送 ack 但是如果 leader 掛掉后 他不確保是否復制完成新 leader 也會導致數(shù)據(jù)丟失。 -1(all):服務端會等所有的 follower 的副本受到數(shù)據(jù)后才會受到 leader 發(fā)出的 ack,這樣數(shù) 據(jù)不會丟失
12. 消費者如何不自動提交偏移量,由應用提交?
將 auto.commit.offset 設為 false,然后在處理一批消息后 commitSync() 或者異步提交 commitAsync()
13. 消費者故障,出現(xiàn)活鎖問題如何解決?
出現(xiàn)“活鎖”的情況,是它持續(xù)的發(fā)送心跳,但是沒有處理。為了預防消費者在這種情況下 一直持有分區(qū),我們使用 max.poll.interval.ms 活躍檢測機制。 在此基礎上,如果你調(diào)用的 poll 的頻率大于最大間隔,則客戶端將主動地離開組,以便其他消費者接管該分區(qū)。 發(fā)生 這種情況時,你會看到 offset 提交失敗(調(diào)用 commitSync ()引發(fā)的 CommitFailedException)。 這是一種安全機制,保障只有活動成員能夠提交 offset。所以要留在組中,你必須持續(xù)調(diào)用 poll。 消費者提供兩個配置設置來控制 poll 循環(huán): max.poll.interval.ms:增大 poll 的間隔,可以為消費者提供更多的時間去處理返回的消息(調(diào) 用 poll(long)返回的消息,通常返回的消息都是一批)。缺點是此值越大將會延遲組重新平衡。 max.poll.records:此設置限制每次調(diào)用 poll 返回的消息數(shù),這樣可以更容易的預測每次 poll 間隔要處理的最大值。通過調(diào)整此值,可以減少 poll 間隔,減少重新平衡分組的 對于消息處理時間不可預測地的情況,這些選項是不夠的。 處理這種情況的推薦方法是將 消息處理移到另一個線程中,讓消費者繼續(xù)調(diào)用 poll。 但是必須注意確保已提交的 offset 不超過實際位置。另外,你必須禁用自動提交,并只有在線程完成處理后才為記錄手動提交 偏移量(取決于你)。 還要注意,你需要 pause 暫停分區(qū),不會從 poll 接收到新消息,讓 線程處理完之前返回的消息(如果你的處理能力比拉取消息的慢,那創(chuàng)建新線程將導致你機 器內(nèi)存溢出)。
14. 如何控制消費的位置
kafka 使用 seek(TopicPartition, long)指定新的消費位置。用于查找服務器保留的最早和最新 的 offset 的特殊的方法也可用(seekToBeginning(Collection) 和 seekToEnd(Collection))
15. kafka 分布式 ( 不是單機 ) 的情況下 , 如何保證消息的
順序消費? Kafka 分布式的單位是 partition,同一個 partition 用一個 write ahead log 組織,所以可以 保證 FIFO 的順序。不同 partition 之間不能保證順序。但是絕大多數(shù)用戶都可以通過 message key 來定義,因為同一個 key 的 message 可以保證只發(fā)送到同一個 partition。 Kafka 中發(fā)送 1 條消息的時候,可以指定(topic, partition, key) 3 個參數(shù)。partiton 和 key 是 可選的。如果你指定了 partition,那就是所有消息發(fā)往同 1 個 partition,就是有序的。并 且在消費端, Kafka 保證,1 個 partition 只能被 1 個 consumer 消費。或者你指定 key ( 比如 order id),具有同 1 個 key 的所有消息,會發(fā)往同 1 個 partition。
16. kafka 如何減少數(shù)據(jù)丟失
Kafka 到底會不會丟數(shù)據(jù)(data loss)? 通常不會,但有些情況下的確有可能會發(fā)生。下面的參 數(shù)配置及 Best practice 列表可以較好地保證數(shù)據(jù)的持久性(當然是 trade-off,犧牲了吞吐量)。
block.on.buffer.full = true
acks = all
retries = MAX_VALUE
max.in.flight.requests.per.connection = 1
使用 KafkaProducer.send(record, callback)
callback 邏輯中顯式關閉 producer:close(0)
unclean.leader.election.enable=false
replication.factor = 3
min.insync.replicas = 2
replication.factor > min.insync.replicas
enable.auto.commit=false
消息處理完成之后再提交位移
17. kafka 如何不消費重復數(shù)據(jù)?比如扣款。
其實還是得結合業(yè)務來思考,我這里給幾個思路: 比如你拿個數(shù)據(jù)要寫庫,你先根據(jù)主鍵查一下,如果這數(shù)據(jù)都有了,你就別插入了,update 一下好吧。 比如你是寫 Redis,那沒問題了,反正每次都是 set,天然冪等性。 比如你不是上面兩個場景,那做的稍微復雜一點,你需要讓生產(chǎn)者發(fā)送每條數(shù)據(jù)的時候,里 面加一個全局唯一的 id,類似訂單 id 之類的東西,然后你這里消費到了之后,先根據(jù)這個 id 去比如 Redis 里查一下,之前消費過嗎?如果沒有消費過,你就處理,然后這個 id 寫 Redis。如果消費過了,那你就別處理了,保證別重復處理相同的消息即可。 比如基于數(shù)據(jù)庫的唯一鍵來保證重復數(shù)據(jù)不會重復插入多條。因為有唯一鍵約束了,重復數(shù) 據(jù)插入只會報錯,不會導致數(shù)據(jù)庫中出現(xiàn)臟數(shù)據(jù)。
小白路漫漫,讓我們一起加油?。?!
柚子快報邀請碼778899分享:分布式 Kafka問題紀要
好文推薦
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權,聯(lián)系刪除。