kafkaspot在ack機制下如何保證記憶體不溢

来源:http://www.cnblogs.com/intsmaze/archive/2016/10/10/5947078.html
-Advertisement-
Play Games

新浪微博:intsmaze劉洋洋哥。 storm框架中的kafkaspout類實現的是BaseRichSpout,它裡面已經重寫了fail和ack方法,所以我們的bolt必須實現ack機制,就可以保證消息的重新發送;如果不實現ack機制,那麼kafkaspout就無法得到消息的處理響應,就會在超時以 ...


新浪微博:intsmaze劉洋洋哥。   storm框架中的kafkaspout類實現的是BaseRichSpout,它裡面已經重寫了fail和ack方法,所以我們的bolt必須實現ack機制,就可以保證消息的重新發送;如果不實現ack機制,那麼kafkaspout就無法得到消息的處理響應,就會在超時以後再次發送消息,導致消息的重覆發送。   但是回想一下我們自己寫一個spout類實現BaseRichSpout並讓他具備消息重發,那麼我們是會在我們的spout類裡面定義一個map集合,並以msgId作為key。
public class MySpout extends BaseRichSpout {
    private static final long serialVersionUID = 5028304756439810609L;
    // key:messageId,Data
    private HashMap<String, String> waitAck = new HashMap<String, String>();
    private SpoutOutputCollector collector;
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("sentence"));
    }
    public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
        this.collector = collector;
    }
    public void nextTuple() {
        String sentence = "the cow jumped over the moon";
        String messageId = UUID.randomUUID().toString().replaceAll("-", "");
        waitAck.put(messageId, sentence);
        //指定messageId,開啟ackfail機制
        collector.emit(new Values(sentence), messageId);
    }
    @Override
    public void ack(Object msgId) {
        System.out.println("消息處理成功:" + msgId);
        System.out.println("刪除緩存中的數據...");
        waitAck.remove(msgId);
    }
    @Override
    public void fail(Object msgId) {
        System.out.println("消息處理失敗:" + msgId);
        System.out.println("重新發送失敗的信息...");
        //重發如果不開啟ackfail機制,那麼spout的map對象中的該數據不會被刪除的,而且下游
        collector.emit(new Values(waitAck.get(msgId)),msgId);
    }
}
  那麼kafkaspout會不會也是這樣還保存這已發送未收到bolt響應的消息呢?如果這樣,如果消息處理不斷失敗,不斷重發,消息不斷積累在kafkaspout節點上,kafkaspout端會不就會出現記憶體溢出?   其實並沒有,回想kafka的原理,Kafka會為每一個consumergroup保留一些metadata信息–當前消費的消息的position,也即offset。這個offset由consumer控制。正常情況下consumer會在消費完一條消息後線性增加這個offset。當然,consumer也可將offset設成一個較小的值,重新消費一些消息。也就是說,kafkaspot在消費kafka的數據是,通過offset讀取到消息併發送給bolt後,kafkaspot只是保存者當前的offset值。 當失敗或成功根據msgId查詢offset值,然後再去kafka消費該數據來確保消息的重新發送。   那麼雖然offset數據小,但是當offset的數據量上去了還是會記憶體溢出的? 其實並沒有,kafkaspout發現緩存的數據超過限制了,會把某端的數據清理掉的。     kafkaspot中發送數據的代碼
collector.emit(tup, new KafkaMessageId(_partition, toEmit.offset));
可以看到msgID裡面包裝了offset參數。 它不緩存已經發送出去的數據信息。   當他接收到來至bolt的響應後,會從接收到的msgId中得到offset。以下是從源碼中折取的關鍵代碼:
public void ack(Object msgId) {
     KafkaMessageId id = (KafkaMessageId) msgId;
     PartitionManager m = _coordinator.getManager(id.partition);
     if (m != null) {
          m.ack(id.offset);
     }
 }
 m.ack(id.offset);
 public void ack(Long offset) {
     _pending.remove(offset);//處理成功移除offset
     numberAcked++;
 }

public void fail(Object msgId) { KafkaMessageId id = (KafkaMessageId) msgId; PartitionManager m = _coordinator.getManager(id.partition); if (m != null) { m.fail(id.offset); } } m.fail(id.offset); public void fail(Long offset) {     failed.add(offset);//處理失敗添加offset numberFailed++; } SortedSet<Long> _pending = new TreeSet<Long>(); SortedSet<Long> failed = new TreeSet<Long>();

 

關於kafkaspot的源碼解析大家可以看這邊博客:http://www.cnblogs.com/cruze/p/4241181.html

源碼解析中涉及了很多kafka的概念,所以僅僅理解kafka的概念想完全理解kafkaspot源碼是很難的,如果不理解kafka概念,那麼就只需要在理解storm的ack機制上明白kafkaspot做了上面的兩件事就可以了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這個代理傳值是經常使用的一種傳值方式,下麵介紹一種View 和 Controller 之間的代理傳值方法。 先建立一個View視圖 如 LoginView 是繼承於一個UIView 在LoginView.h裡面聲明協議 LoginView.h文件 import @class LoginView; / ...
  • 背景: 雖然Azure sql database有DMVs可以查看DTU等使用情況,但記錄有時間限制,不會一直保留。為了更好監控Azure_sql_database上各個庫的DTU使用情況、資料庫磁碟使用情況、阻塞等情況。通過本地的Agent的job使用link server 鏈接到各個Azure ...
  • SQL 基礎知識梳理(四) - 數據更新 【博主】反骨仔 【原文】http://www.cnblogs.com/liqingwen/p/5929786.html 序 這是《SQL 基礎知識梳理(三) - 聚合和排序》的下篇。 目錄 插入數據 刪除數據 更新數據 事務 一、插入數據 1.INSERT ...
  • 本設計基於以下需求提出 1. 快速接入數據源表(貼源/落地) 2. 無須給單獨表開發轉換/作業 3. 動態生成數據源連接, 表欄位等信息(預先保存在數據倉庫中) 本設計所需條件 1. 數據源為關係型資料庫 2. 不同數據源需要寫一小段Java Scripts以保證數據源連接可用 總體作業結構 jb_ ...
  • 487down vote Differences KEY or INDEX refers to a normal non-unique index. Non-distinct values for the index are allowed, so the index may contain row ...
  • 1.在my.ini的 [mysqld] 下添加 skip-grant-tables 2.重啟mysql服務即可 ...
  • 上學時學的東西,都忘了,用到了,就翻出來學習了一下。使用存儲過程編寫,可直接運行該存儲過程註釋都寫好了,變數賦值也比較清楚,需要的可以直接複製下來然後替換就好。 ...
  • 需求:按照分組,將多條記錄內容合併成一條,效果如下: 資料庫示例: 根據不同的SQL版本,可以有以下方法: 一、SQL 2000 不支持FOR XML,不支持CONCAT。只能寫自定義函數。 二、SQL 2012 支持 concat,2000版本自定義函數的基礎上可少量優化 三、SQL2005支持f ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...