將大文件切分爲更容易處理的多個更小的文件。less
單一的日誌文件可能會增加到很大,而且在程序啓動時讀取從而成爲性能瓶頸。老的日誌須要定時清理,可是對於一個大文件進行清理操做很費勁。ide
將單一日誌切分爲多個,日誌在達到必定大小時,會切換到新文件繼續寫。性能
//寫入日誌 public Long writeEntry(WALEntry entry) { //判斷是否須要另起新文件 maybeRoll(); //寫入文件 return openSegment.writeEntry(entry); } private void maybeRoll() { //若是當前文件大小超過最大日誌文件大小 if (openSegment. size() >= config.getMaxLogSize()) { //強制刷盤 openSegment.flush(); //存入保存好的排序好的老日誌文件列表 sortedSavedSegments.add(openSegment); //獲取文件最後一個日誌id long lastId = openSegment.getLastLogEntryId(); //根據日誌id,另起一個新文件,打開 openSegment = WALSegment.open(lastId, config.getWalDir()); } }
若是日誌作了切分,那麼須要快速以某個日誌位置(或者日誌序列號)定位到某個文件的機制。能夠經過兩種方式實現:日誌
//建立文件名稱 public static String createFileName(Long startIndex) { //特定日誌前綴_起始位置_日誌後綴 return logPrefix + "_" + startIndex + "_" + logSuffix; } //從文件名稱中提取日誌偏移量 public static Long getBaseOffsetFromFileName(String fileName) { String[] nameAndSuffix = fileName.split(logSuffix); String[] prefixAndOffset = nameAndSuffix[0].split("_"); if (prefixAndOffset[0].equals(logPrefix)) return Long.parseLong(prefixAndOffset[1]); return -1l; }
在文件名包含這種信息以後,讀操做就分爲兩步:code
//給定偏移量,讀取全部日誌 public List<WALEntry> readFrom(Long startIndex) { List<WALSegment> segments = getAllSegmentsContainingLogGreaterThan(startIndex); return readWalEntriesFrom(startIndex, segments); } //給定偏移量,獲取全部包含大於這個偏移量的日誌文件 private List<WALSegment> getAllSegmentsContainingLogGreaterThan(Long startIndex) { List<WALSegment> segments = new ArrayList<>(); //Start from the last segment to the first segment with starting offset less than startIndex //This will get all the segments which have log entries more than the startIndex for (int i = sortedSavedSegments.size() - 1; i >= 0; i--) { WALSegment walSegment = sortedSavedSegments.get(i); segments.add(walSegment); if (walSegment.getBaseOffset() <= startIndex) { break; // break for the first segment with baseoffset less than startIndex } } if (openSegment.getBaseOffset() <= startIndex) { segments.add(openSegment); } return segments; }
基本全部主流 MQ 的存儲,例如 RocketMQ,Kafka 還有 Pulsar 的底層存儲 BookKeeper,都運用了分段日誌。blog
RocketMQ:
排序
Kafka:
seo
Pulsar存儲實現BookKeeper:
get
另外,基於一致性協議 Paxos 或者 Raft 的存儲,通常會採用分段日誌,例如 Zookeeper 以及 TiDB。it
每日一刷,輕鬆提高技術,斬獲各類offer: