標籤:kafka jfaka 訊息中介軟體 原始碼
在Kafka中,LogManager負責管理broker上所有的Log(每一個topic-partition為一個Log)。通過閱讀原始碼可知其具體完成的功能如下:
1. 按照預設規則對訊息佇列進行清理。
2. 按照預設規則對訊息佇列進行持久化(flush操作)。
3. 串連ZooKeeper進行broker、topic、partition相關的ZooKeeper操作。
4. 管理broker上所有的Log。
下面一一對這些功能的實現進行詳細的解析。
一、對於Log的管理
LogManager包含成員變數logs。logs的key是topic,value是Pool<Integer,Log>(該value又是一個Map,主鍵是partition,value是該partition所對應的Log)。因此LogManager通過logs儲存該broker上所有的訊息佇列。
private final Pool<String, Pool<Integer, Log>> logs = new Pool<String, Pool<Integer, Log>>();
LogManager在初始化之後,需要根據設定檔配置的訊息佇列根目錄進行遍曆。通過遍曆,尋找並產生Log。該遍曆的具體實現在方法load中:
① 擷取訊息佇列根目錄下的所有檔案
② 對於根目錄下的每一個檔案進行如下操作
1.如果是目錄,則有可能是一個Log,否則不是並忽略
2.對於通過1的目錄分析其檔案名稱,目錄的檔案名稱由兩部分組成:topic-partition
3.對於通過2的目錄,用目錄、解析出的topic、解析出的partition產生Log
4.將3產生的Log放入logs日誌池
5.最後,判斷目錄解析的partition與設定檔中配置的partition的大小,如果設定檔較小,則更新配置
二、訊息佇列清理
訊息佇列的清理由Scheduler周期性的調用,具體的調用在load函數中,主要的刪除實現在cleanLogs函數中。訊息佇列的清理分為兩種情況:一種是超過預設的時間則刪除,二是超過預設的大小則刪除,分別對應兩個函數cleanupExpiredSegments和cleanupSegmentsToMaintainSize。第一種情況比較簡單,因為每一個segment對應一個檔案,通過對比檔案的lastModifiedTime和系統的現在時間來確定其是否逾時,如果逾時則刪除。對於第二種情況,首先比較Log的大小與配置的大小。如果小於配置的大小則不刪除;如果大於了配置的大小,則計算超過配置大小的長度(定為差值);然後將小於該差值的segment刪除(這地方有點疑惑,這樣刪除會不會把一些最新的訊息佇列給刪除了)。
if (this.scheduler != null) { this.scheduler.scheduleWithRate(new Runnable() { public void run() { try { cleanupLogs(); } catch (IOException e) { logger.error("cleanup log failed.", e); } } }, 60 * 1000, logCleanupIntervalMs);}
三、對於訊息佇列的持久化
對訊息佇列的flush操作同樣由單獨的線程來完成。該線程通過比較Log上一次的flush時間和當前的系統時間來確定是否需要flush,如果需要則持久化到檔案。注意,訊息的隊列的持久化在新增訊息的時候也會判斷,如果一個Log儲存的新增訊息的條數超過了預設值則進行flush操作。
在Kafka中,LogManager負責管理broker上所有的Log(每一個topic-partition為一個Log)。通過閱讀原始碼可知其具體完成的功能如下:
1. 按照預設規則對訊息佇列進行清理。
2. 按照預設規則對訊息佇列進行持久化(flush操作)。
3. 串連ZooKeeper進行broker、topic、partition相關的ZooKeeper操作。
4. 管理broker上所有的Log。
下面一一對這些功能的實現進行詳細的解析。
一、對於Log的管理
LogManager包含成員變數logs。logs的key是topic,value是Pool<Integer,Log>(該value又是一個Map,主鍵是partition,value是該partition所對應的Log)。因此LogManager通過logs儲存該broker上所有的訊息佇列。
private final Pool<String, Pool<Integer, Log>> logs = new Pool<String, Pool<Integer, Log>>();
LogManager在初始化之後,需要根據設定檔配置的訊息佇列根目錄進行遍曆。通過遍曆,尋找並產生Log。該遍曆的具體實現在方法load中:
① 擷取訊息佇列根目錄下的所有檔案
② 對於根目錄下的每一個檔案進行如下操作
1.如果是目錄,則有可能是一個Log,否則不是並忽略
2.對於通過1的目錄分析其檔案名稱,目錄的檔案名稱由兩部分組成:topic-partition
3.對於通過2的目錄,用目錄、解析出的topic、解析出的partition產生Log
4.將3產生的Log放入logs日誌池
5.最後,判斷目錄解析的partition與設定檔中配置的partition的大小,如果設定檔較小,則更新配置
二、訊息佇列清理
訊息佇列的清理由Scheduler周期性的調用,具體的調用在load函數中,主要的刪除實現在cleanLogs函數中。訊息佇列的清理分為兩種情況:一種是超過預設的時間則刪除,二是超過預設的大小則刪除,分別對應兩個函數cleanupExpiredSegments和cleanupSegmentsToMaintainSize。第一種情況比較簡單,因為每一個segment對應一個檔案,通過對比檔案的lastModifiedTime和系統的現在時間來確定其是否逾時,如果逾時則刪除。對於第二種情況,首先比較Log的大小與配置的大小。如果小於配置的大小則不刪除;如果大於了配置的大小,則計算超過配置大小的長度(定為差值);然後將小於該差值的segment刪除(這地方有點疑惑,這樣刪除會不會把一些最新的訊息佇列給刪除了)。
if (this.scheduler != null) { this.scheduler.scheduleWithRate(new Runnable() { public void run() { try { cleanupLogs(); } catch (IOException e) { logger.error("cleanup log failed.", e); } } }, 60 * 1000, logCleanupIntervalMs);}
三、對於訊息佇列的持久化
對訊息佇列的flush操作同樣由單獨的線程來完成。該線程通過比較Log上一次的flush時間和當前的系統時間來確定是否需要flush,如果需要則持久化到檔案。注意,訊息的隊列的持久化在新增訊息的時候也會判斷,如果一個Log儲存的新增訊息的條數超過了預設值則進行flush操作。