Skip to the content.

分段日志(Segmented Log)

描述:分割日志文件为小的文件替代,而不是为了简单只用一个单个大日志文件。

问题

当在启动时读日志的时候,单个日志文件随着时间会越来越大,成为性能瓶颈。旧日志要定时清理,要在单个大日志文件中清楚处理是非常困难的。

解决方案

把单个大日志文件拆分为多个小文件。日志文件在指定的大小操作

public Long writeEntry(WALEntry entry) {
    maybeRoll();
    return openSegment.writeEntry(entry);
}

private void maybeRoll() {
    if (openSegment.size() >= config.getMaxLogSize()) {
        openSegment.flush();
        sortedSavedSegments.add(openSegment);
        long lastId = openSegment.getLastLogEntryId();
        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;
}

通过这些信息,一个读操作分为两步。给定一个偏移量(或是事务 id),标识分段日志以及都能从随后的分段日志中读取所有的日志记录。

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;
}

例子

原文连接:https://martinfowler.com/articles/patterns-of-distributed-systems/log-segmentation.html