本文仅介绍wal的基本处理,如create、open、close、read等操作。鉴于篇幅原因,下面介绍replayWAL(启动raft节点时执行)函数涉及的读文件操作:从wal目录中加载snapshot,wal文件的创建,以及读取wal目录中的所有数据(主要是entryTypestateTypemetadataType这几类)。

WAL的处理还是比较复杂的可以借鉴的地方也很多。WAL在编码以及flush时使用缓存来提升效率。flush的单位为分页,每页又分为8个section,section的作用是用来检测写入的数据是否被破坏,检测逻辑为:如果某个section中的所有字节都为0,则说明数据遭到破坏,反之则认为数据正常。在isTornEntry中,主要通过section机制来检测WAL文件中最后一个record是否因为数据破坏而导致json解析或crc校验失败。

创建

下面是wal的create流程,在创建文件事先预分配文件大小(64MB),用于提升性能。wal通过encode()函数将编码后的数据写入文件,因此需要在对文件执行写操作时加锁,写入的数据以record为单位(record首先被写入缓存,当数据以页为单位对齐时通过flush写入文件)。先计算数据的crc校验码,然后计算record的帧数据。写数据时,先写入帧数据,再写入record。在写入数据(无论是帧数据还是record)时,会以页为单位将数据写入文件,不足一页的数据会暂存在缓存中。帧数据保存了实际的数据大小和pad的数据大小,在读取wal文件时会用到该信息。

wal的文件名由两部分构成:seq和index,前者应该顺序递增的,以保证日志文件的连续性(isValidSeq会根据seq校验日志文件的连续性)。

加载snapshot

下面是在wal目录中加载snapshot的操作,该操作中用到了上面的帧数据。wal使用decode()函数进行解码,首先取出在帧数据中解析出record的大小和padBytes的小,然后根据record的大小解码数据,最后根据record的类型采集并返回所有snapshot。

从上面可以看到,wal的encoder用于写文件,因此encoder会关联到当前正在编辑的文件,记录了文件句柄、当前字节偏移以及缓存等信息,一般会选择WAL.locks中的最后一个元素。而decoder用于读取所有文件,因此关联到多个wal文件,记录了这些文件句柄。

读取所有数据

下图是从wal目录中尝试读取所有信息(如metadata、entries、state)的过程。涉及读取wal目录中的文件信息,以此构建WAL结构,然后通过生成的decoder来将文件解码为不同类型的数据进行处理。最终返回解码后的数据。需要注意decoder的文件是有序的,可以从源码fileutil.ReadDir看出来,其对文件名进行了sort.Strings(names)操作。

此外,在读取文件时,根据文件的读写模式分别进行了处理。读模式下只需读完所有文件,关闭文件并返回结果即可。写模式下文件是加锁的,在decodeRecord中会读取lastValidOff(frameSizeBytes + recBytes + padBytes)长度的数据,并将该长度之后的数据归0,防止文件中出现被破坏的数据,由于对文件的修改会改变文件的crc校验,但好在新的record不会立即刷新到文件中(源码中的描述如下),更新文件的encoder,后续通过encoder将数据最终写入文件即可。

		// decodeRecord() will return io.EOF if it detects a zero record,
// but this zero record may be followed by non-zero records from
// a torn write. Overwriting some of these non-zero records, but
// not all, will cause CRC errors on WAL open. Since the records
// were never fully synced to disk in the first place, it's safe
// to zero them out to avoid any CRC errors from new writes.

WAL的保存

raftexample的serveChannels中当接收到node.Ready()传来的数据时,会对这些数据进行持久化。如下图,首先会保存状态和entry信息,如果locks中最后一个文件(该文件)的内容大于或等于SegmentSizeBytes时需要切割文件。

在切分文件时,将已有的数据同步到文件中,后面的操作就是新建一个文件。新文件来自于WAL.fp是在重命名文件或创建文件时创建的,可以看到一个WAL只有一个fp,用于在切割文件时提高效率。

首先在新文件中记录当前的crc,然后写入metadatastate信息,并重新计算crc,在读取时可以校验到此为止的crc。新文件作为WAL.locks中的最后一个文件。

原图连接

etcd raft 处理流程图系列2-wal的读写的更多相关文章

  1. etcd raft 处理流程图系列1-raftexample

    最近在看raft相关的代码和实现,发现etcd的raft模块在实现上还是比较灵活的,但缺点就是需要用户实现比较多的功能,如存储和网络等,同时带来的优点就是不会对用户的存储和传输作限制.网上对该模块的描 ...

  2. etcd raft 处理流程图系列3-wal的存储和运行

    存储和节点的创建 raftexample中的存储其实有两种,一个是通过raft.NewMemoryStorage()进行创建的raft.raftStorage,关联到单个raft节点,另一个是通过ne ...

  3. etcd raft 处理流程图系列2-transport

    本章给出了raftexample中使用的传输层代码,补全了上一节中传输层与raft节点(raft server和channel server)的交互细节.下图中流程的核心在于传输层中的streamRt ...

  4. etcd raft library设计原理和使用

    早在2013年11月份,在raft论文还只能在网上下载到草稿版时,我曾经写过一篇blog对其进行简要分析.4年过去了,各种raft协议的讲解铺天盖地,raft也确实得到了广泛的应用.其中最知名的应用莫 ...

  5. 彻底搞懂etcd raft选举、数据同步

    etcd raft选举机制 etcd 是一个分布式的k/V存储系统.核心使用了RAFT分布式一致性协议.一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服 ...

  6. etcd raft如何实现成员变更

    成员变更在一致性协议里稍复杂一些,由于不同的成员不可能在同一时刻从旧成员组切换至新成员组,所以可能出现两个不相交的majority,从而导致同一个term出现两个leader,进而导致同一个index ...

  7. etcd raft library

    https://github.com/coreos/etcd/tree/master/raft import "github.com/coreos/etcd/raft" ----- ...

  8. etcd raft如何实现leadership transfer

    leadership transfer可以把raft group中的leader身份转给其中一个follower.这个功能可以用来做负载均衡,比如可以把leader放在性能更好的机器或者离客户端更近的 ...

  9. etcd raft如何实现Linearizable Read

    Linearizable Read通俗来讲,就是读请求需要读到最新的已经commit的数据,不会读到老数据. 对于使用raft协议来保证多副本强一致的系统中,读写请求都可以通过走一次raft协议来满足 ...

随机推荐

  1. 9.4、安装zabbix(3)

    (10)监控mysql: 1)安装mariadb-server: [root@slave-node1 ~]# yum install mariadb-server [root@slave-node1 ...

  2. 图的存储与遍历C++实现

    1.图的存储 设点数为n,边数为m 1.1.二维数组 方法:使用一个二维数组 adj 来存边,其中 adj[u][v] 为 1 表示存在 u到 v的边,为 0 表示不存在.如果是带边权的图,可以在 a ...

  3. 关于PHP导出数据超时的优化

    一般情况下,导出超时可能都是以下三种情况: 一.sql语句复杂,查询时间过长: 二.处理查询后数据逻辑冗余: 三.数据量过大导致响应超时. 接下来分别给出这三种情况的优化建议. 一.sql语句复杂,查 ...

  4. zset如何解决内部链表查找效率低下

    zset作为有序集合,内部基于跳表或者说索引的方式实现了数据的快速查找.解决了链表查询效率低下的痛点 前言 紧接前文我们学习了Redis中Hash结构.在里面我们梳理了字典这个重要的内部结构并分析了h ...

  5. python base64(图片)编码

    参考:https://blog.csdn.net/Good_Luck_Kevin2018/article/details/80953312 通常会在网页中遇到用src="data:image ...

  6. python django与celery的集成

    一.celery与django 关于celery介绍和使用可以查看上篇Python中任务队列-芹菜celery的使用 关于django的介绍和使用可查看python django框架+vue.js前后 ...

  7. Codeforces Round #707 Editorial Div2 题解

    CF1501 Div2 题解 CF1501A 这道题其实是一道英语阅读题,然后样例解释又不清晰,所以我看了好久,首先它告诉了你每个站点的预期到达时间 \(a_i\) ,以及每个站点的预期出发时间 \( ...

  8. Linux常用命令 day day up系列3

    一.命令执行的优先级二.Linux目录结构三.cat--查看文件内容四.more--查看文件内容五.less--查看文件内容六.head.tail--查看文件内容七.wc--统计文件内容八.grep- ...

  9. Kubernetes实战:高可用集群的搭建和部署

    摘要:官方只提到了一句"使用负载均衡器将 apiserver 暴露给工作节点",而这恰恰是部署过程中需要解决的重点问题. 本文分享自华为云社区<Kubernetes 高可用集 ...

  10. 基于SSM框架的旅游网站

    介绍:spring+springmvc+mybatis三大框架,mysql数据库 功能结构图: 效果截图: 数据库表: CREATE TABLE `t_admin` ( `id` int(11) NO ...