Kafka_核心

kafka集群

image.png

Kafka的設計都是為了實現kafak消息隊列消費數據的語義
Kafka消息隊列中數據消費的三種語義:

  • at-most-once:至多一次
    會出現數據丟失的問題
  • at-least-once:至少一次
    會出現數據重復的問題
  • exactly-once:有且僅有一次
    只消費處理成功一次
    所有消息隊列的目標

kakfa卡只能保證局部有序,如何實現全局有序

image.png

kafka中每個分區(qū)內有offset保證局部有序
1.如果topic只有 一個分區(qū)可以實現全局有序
2.寫數據的時候指定分區(qū)編號,只想一個分區(qū)內寫數據

Kafka如何保證自身數據安全

多副本機制
生產者和消費者跟leader副本進行讀寫
follower副本跟leader副本同步數據
且讀寫的內容只能在hw高水位線之前

副本同步機制
為什么會存在同步?因為讀寫只跟leader副本打交道。所以follower副本需要同步數據。
副本集合概念:

  • AR 該分區(qū)的所有副本 ALL

  • ISR 所有副本中處在同步狀態(tài)的 健康良好的 IN Sync
    只有ISR中的副本才有選舉資格 成為新的leader 優(yōu)先順序 從左往右

    誰來負責leader副本選舉? kafka中主角色controller
    誰來kafka主角色controller選舉呢? 通過zk集群選舉?!九R時節(jié)點 監(jiān)聽 唯一性】

  • OSR 非同步狀態(tài)的 Out Sync
    正常情況下 OSR集合中應該是空的 每個副本都應該處于健康的狀態(tài)
    ISR同步超時 就會被打入OSR

          AR=ISR+OSR
          
      名詞:
          LSO  start  每個副本的第一個消息offset 正常是0。如果開啟了刪除清理 之前的數據就會被刪除
          LEO  end    每個副本的【下一個待寫入】的offset值 
          HW  高水位線  只有它之前的消息才能被消費者拉取消費
              hw=min(leo)  類似于木桶效應
    

Producer生產者如何保證生產的數據不丟失\不重復

  • 如何保證kafka數據不丟失
    ack校檢和重試機制

    • ACK級別
      0 不管ack 只發(fā)送數據
      1 當leader副本保存成功 返回ack給生產者
      -1|all 當所有的ISR副本都保存同步成功 返回ack 【最安全 最慢】
    • 重試機制
      因為網絡質量等偶發(fā)因素導致的消息發(fā)送失敗 可以通過重試機制
      如果因為代碼問題 集群環(huán)境問題 重試一百萬次有沒有意義
  • 如何保證數據寫入kafka不重復?
    為什么會重復?
    1_重試機制,如果前一個ack還沒有返回 生產者認為失敗了基于重試機制重新發(fā)了一遍
    2_ack結果延遲 丟失
    實際上kafka已經存儲成功了 只不過生產者沒有正確準確的收到ack

    內部設計了什么機制?
    1_冪等性機制 操作一次和操作多次 效果是一樣的。 不跟次數有關。 重復支付 重復提交 常量函數。
    2_給每個生產者發(fā)送的消息內部編號 自增id
    kafka在保存數據的時候 就會判斷編號 如果已經有了 不保存了直接返回ack

生產者寫入數據分區(qū)規(guī)則

當Producer生產者向Topic隊列中發(fā)送數據時,如何確定發(fā)送到哪個分區(qū)Partition呢?

  • 1.如果用戶指定了分區(qū),就向指定分寫入數據

  • 2.如果用戶不指定分區(qū),看是否有自定義分區(qū)規(guī)則

    • 2_1 如果沒有指定自定義分區(qū)規(guī)則,按照默認的規(guī)則分區(qū)規(guī)則
      如果有key,根據 key的hash值%分區(qū)個數

    Utils.murmur2(keyBytes) % numPartitions
    計算key哈希值,對partition分區(qū)個數進行取模操作 結果就是分區(qū)編號。
    只要key一樣,一定到同一個分區(qū)。

    如果沒有key:

    a_老版本 采用輪詢策略
    b_新版本 stickyPartition 黏性策略
    if (keyBytes == null) {
    return stickyPartitionCache.partition(topic, cluster);
    }

    什么叫做黏性策略呢?
    首先判斷當前有沒有partition的連接 如果連接有效 直接使用這個連接
    Integer newPart = oldPart;
    如果沒有分區(qū)連接,那就隨機選擇一個分區(qū)創(chuàng)建連接 把數據都寫入這個分區(qū)
    random

    • 2_2 如果有自定義分區(qū)規(guī)則,按照自定義分區(qū)規(guī)則分配

Consumer消費者如何保證數據不重復不丟失

Kafka記錄了每次消費者消費后的消費記錄
當消費者來消費的時候,只需消費上一次offset+1的數據就可以了

  • 消費者消費數據的三種方式
    指定topic ????~~~~ ~~~~ ~~~~讀取的是指定topic下所有分區(qū)的數據
    指定topic partition ~~~~ ~~~~ 讀取的是指定topic下的某個分區(qū)的數據
    指定topic partition offset ~~~~讀取的是指定topic下 指定分區(qū)的 某個offset開始

訂閱主題 subscribe 消費該主題的所有分區(qū)數據
訂閱主題指定分區(qū) assign 消費指定主題分區(qū)的數據
精準消費 定位消費 seek 消費指定主題分區(qū) 指定偏移量消費
需要先訂閱topic 和 分區(qū),然后才能seek 偏移量


消費者開始消費數據時,從哪里開始消費

  • step1: 第一次消費規(guī)則 由屬性決定
    lastest 從0開始
    earliest 從最新的開始(默認)
      //設置消費的位置 從哪里開始消費  合法參數:latest |  earliest
      props.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
  • step2:第二次及以后 從上一次消費完的offset +1位置開始消費

  • 以上成為消費記錄,那么kafka如何保存消費記錄的呢?
    ~~~~消費者內存中 自己維護 程序不斷 不重啟的情況下 【優(yōu)先使用】。
    ~~~~持久化存儲在磁盤、存儲介質: 【重啟程序的依據】
    ~~~~ ~~~~存儲kafka中(默認) 自創(chuàng)了主題_consumer_offsets
    ~~~~ ~~~~ 存儲zk/mysql/redis

內存消費記錄:kafka自己記錄的非常標準,但是程序重啟之后就沒有了,需要從文件當中讀

文件消費記錄:kafka自己有一個topic 專門用來存儲每個消費者消費的offset


image.png

offset偏移量管理
消費者消費完的記錄需要提交,怎樣提交?

  • 自動提交
    • 根據時間周期提交下一下的消費的offset,默認每五秒提交一次
    • 風險:
      數據丟失
      數據重復


      image.png

為了防止數據丟失,或者重復消費我們選擇手動提交

  • 手動提交offset
    先消費數據,然后再提交offset
    風險:如果此時我已經消費了兩個分區(qū)的數據,第三個分區(qū)還沒有消費完,程序崩潰了,offset沒有提交,就會導致,下次程序啟動的時候 重復消費數據
  • 手動提交--基于分區(qū)提交offset
    offsets.put(partition,new OffsetAndMetadata(consumerOffset+1));
    把當前分區(qū)消費的最后一條日志的offset +1,提交上去。
  • 手動提交分區(qū)offset探秘


    image.png

消費者在自己的內存中維護了消費記錄
當內存中有記錄的時候,程序之間從內存當中讀取消費記錄,這個消費記錄是自己維護的正確的

而磁盤中的消費記錄,只有在程序重啟 內存中的消費記錄丟失了 才會根據磁盤去消費


消費者消費數據分配策略

問題:Kafka 消費組Consumer Group中多個消費者Consumer如何消費Topic隊列中數據?
前提-kafka中同一個消費組中的消費者規(guī)則:
一個分區(qū)只能被一個消費者消費
一個消費者可以消費多個分區(qū)

另 一個分區(qū)的內容,可以被不同消費組內的消費者消費
最理想的狀態(tài):消費者和分區(qū) 一對一
策略:
范圍分配
輪詢分配
粘性分配

1_RangeAssignor 分配策略-范圍分配

  • Kafka中默認的分配規(guī)則
  • 一個topic中所有的分區(qū)按照消費者的個數平均分,多的就分配給編號小的消費者
    優(yōu)點:適用于消費topic比較少的情況,分配會比較平均
    ex: 一個topic內有七個分區(qū) 有三個消費者c1 c2 c3
    c1 (0,1,2) c2(3,4) c3(56)
    缺點: 不適應于多個消費者消費多個topic,會造成編號小的負載壓力大的情況
    列如:三個消費者 消費三個topic 每個topic有7個分區(qū)會導致
    c1 -t1(0,1,2) t2(0,1,2) t3(0,1,2)

c2 -t1(3,4) t2(3,4) t3(3,4)
c3 t1(5,6) t2(5,6) t3(5,6)

2_RoundRobinAssignor 分配策略-輪詢策略

  • 給每個Topic和其分區(qū)編號,輪詢分配給消費者
    一個消費者分配一個 輪詢分配
    適合:所有消費者都訂閱相同的主題。
    缺點:如果有消費者故障 或者加入新的消費者 之前全推倒 重新分配

image.png

缺點: c1、c2消費第一個topic,c2、c3消費第二個Topic、c3消費第三個Topic,指定消費者消費Topic
會導致c3 (t2-p2,t3-p1-p2-p3)負載過大
3_StickyAssignor 分配策略-粘性策略(推薦)
粘性策略注意針對的是消費過程者,如果有消費者掛掉了.該如何分配其正在消費的分區(qū).
不出故障的時候跟輪詢一樣,出故障之后正常的都不動,輪詢的分配故障后的分區(qū)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容