請問你知道分布式系統設計模式的最低水位線思想麼?

2021-10-19 10:10:52 字數 4182 閱讀 7758

最低水位線是指在 wal(write ahead log)預寫日誌這種設計模式中,標記在這個位置之前的日誌可以被丟棄。

wal(write ahead log)預寫日誌維護了對於儲存的每次更新,隨著時間不斷增長,這個日誌檔案會變得無限大。segmented log 分割日誌這種設計模式可以讓我們每次只處理乙個更小的檔案,但是日誌如果不清理,會無休止增長以至於硬碟被佔滿。

最低水位線這種設計模式會告訴系統哪一部分的日誌可以被刪除了,即在最低水位線之前的所有日誌可以被清理掉。一般的方式是,程式內有乙個執行緒執行乙個定時任務,不斷地檢查哪一部分的日誌可以被清理並且刪除這些日誌檔案。

this.logcleaner = newlogcleaner(config);

this.logcleaner.startup();

這裡的 logcleaner 可以用定時任務實現:

public void startup() 

private void schedulelogcleaning() , config.getcleantaskintervalms(), timeunit.milliseconds);

}

大部分的分布式一致性系統(例如 zookeeper(zab 簡化 paxos協議),etcd(raft協議)),都實現了快照機制。在這種機制下,他們的儲存引擎會定時的進行全量快照,並且記錄下快照對應的日誌位置,將這個位置作為最低水位線。

//進行快照

public snapshot takesnapshot()

當生成了快照並成功儲存到了磁碟上,對應的最低水位線將用來清理老的日誌:

//根據位置獲取這個位置之前的所有日誌檔案

listgetsegmentsbefore(long snapshotindex)

}return markedfordeletion;

}

定時任務位於datadircleanupmanagerstart方法:

public void start() 

//檢查定時間隔有效性

if (purgeinterval <= 0)

//啟動定時任務

timer = new timer("purgetask", true);

timertask task = new purgetask(datalogdir, snapdir,snapretaincount);

timer.scheduleatfixedrate(task, 0, timeunit.hours.tomillis(purgeinterval));

purgetaskstatus = purgetaskstatus.started;

}

核心方法為purgetxnlogpurge方法:

public static void purge(file datadir, file snapdir, int num) throws ioexception 

filetxnsnaplog txnlog = new filetxnsnaplog(datadir, snapdir);

//統計檔案數量

listsnaps = txnlog.findnvalidsnapshots(num);

int numsnaps = snaps.size();

if (numsnaps > 0)

}static void purgeoldersnapshots(filetxnsnaplog txnlog, file snapshot)

public boolean accept(file f)

if (retainedtxnlogs.contains(f))

long fzxid = util.getzxidfromname(f.getname(), prefix);

//根據檔名稱代表的zxid,過濾出要刪除的檔案

return fzxid < leastzxidtoberetain;}}

//篩選出符合條件的 log 檔案和 snapshot 檔案

file logs = txnlog.getdatadir().listfiles(new myfilefilter(prefix_log));

listfiles = new arraylist<>();

if (logs != null)

file snapshots = txnlog.getsnapdir().listfiles(new myfilefilter(prefix_snapshot));

if (snapshots != null)

//進行刪除

for (file f : files) }}

那麼是什麼時候 snapshot 呢?檢視syncrequestprocessorrun方法,這個方法時處理請求,處理請求的時候記錄操作日誌到 log 檔案,同時在有需要進行 snapshot 的時候進行 snapshot:

public void run()  else  catch (exception e)  finally 

}}.start();}}

} //省略其他

}} catch (throwable t)

}

resetsnapshotstats()設定隨機起始位,避免集群內所有例項同時進行 snapshot:

private void resetsnapshotstats()
shouldsnapshot()根據啟動時設定的隨機起始位以及配置,判斷是否需要 snapshot

private boolean shouldsnapshot()
在某些系統中,日誌不是用來更新系統的狀態,可以在一段時間之後刪除,並且不用考慮任何子系統這個最低水位線之前的是否可以刪除。例如,kafka 預設保留 7 天的 log,rocketmq 預設保留 3 天的 commit log。

defaultmeesagestoreaddscheduletask()方法中,定義了清理的定時任務:

private void addscheduletask() 

}, 1000 * 60, this.messagestoreconfig.getcleanresourceinterval(), timeunit.milliseconds);

//忽略其他定時任務

}private void cleanfilesperiodically()

我們這裡只關心清理訊息儲存檔案,即defaultmessagestoredeleteexpiredfiles方法:

private void deleteexpiredfiles()  else if (spacefull) }}

public int deleteexpiredfilebytime(final long expiredtime,

final int deletefilesinterval,

final long intervalforcibly,

final boolean cleanimmediately)

//如果配置了刪除檔案時間間隔,則需要等待

if (deletefilesinterval > 0 && (i + 1) < mfslength) catch (interruptedexception e)

}} else

} else }}

//從檔案列表裡面裡將本次刪除的檔案剔除

deleteexpiredfile(files);

return deletecount;

}

每日一刷,輕鬆提公升技術,斬獲各種offer:

請問你知道分布式系統設計模式的分割日誌思想麼?

將大檔案切分為更容易處理的多個更小的檔案。單一的日誌檔案可能會增長到很大,並且在程式啟動時讀取從而成為效能瓶頸。老的日誌需要定時清理,但是對於乙個大檔案進行清理操作很費勁。將單一日誌切分為多個,日誌在達到一定大小時,會切換到新檔案繼續寫。寫入日誌 public long writeentry wal...

分布式 分布式系統的設計

在計算機領域,當單機效能達到瓶頸時,一般有兩種方式解決效能問題 而分布式系統的設計說白了就是 如何合理將乙個系統拆分成多個子系統部署到不同機器上。講設計方法前,先介紹分布式系統的特性 1 分布性 空間中隨機分布。這些計算機可以分布在不同的機房,不同的城市,甚至不同的國家。2 對等性 分布式系統中的計...

分布式系統設計準則

該文章需要整理 2015.3.13修改 分布式系統通常服務大請求 維護著大資料 快速響應 長時間可用。設計分布式後台服務需要考慮的東西很多,本文給出一些常用的設計準則,以備檢視。效能 快速響應 低延遲 可靠性 系統可靠就是同樣的請求返回同樣的資料 更新能夠持久化 資料不會丟失 可管理性 便於運維,整...