前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式系统模式3-Segmented Log

分布式系统模式3-Segmented Log

作者头像
java达人
发布2020-12-03 10:41:00
3630
发布2020-12-03 10:41:00
举报
文章被收录于专栏:java达人java达人

作者: Unmesh Joshi

译者: java达人

来源: https://martinfowler.com/articles/patterns-of-distributed-systems/

将日志拆分为多个较小的文件,而不是单个较大的文件,以便于操作。

问题

单个日志文件可能会增长并在启动读取时成为性能瓶颈。需要定期清理较旧的日志,而对单个大文件执行清理操作是困难的

方案

单个日志分为多个段。在到达指定的大小限制后滚动日志文件。

代码语言:javascript
复制

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

使用日志分段,需要一种简单的方法将日志逻辑偏移量(或日志序列号)映射到日志段文件。这可以通过两种方式完成:

•每个日志段名称都是由一些众所周知的前缀和基准偏移量(或日志序列号)生成的。

•每个日志序列号分为两部分,文件名和事务偏移量。

代码语言:javascript
复制

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),将标识日志段,并从后续日志段中读取所有日志记录。

代码语言:javascript
复制

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

例子

•所有共识实现(例如Zookeeper和RAFT)中的日志实现都使用日志分段。

•Kafka中的存储实现遵循日志分段。

•所有数据库,包括像Cassandra这样的nosql数据库,都基于一些预先配置的日志大小使用roll over 策略。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 方案
  • 例子
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档