加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 电商 > 正文

类Redis大容量存储-pika 主从复制原理之binlog

发布时间:2021-01-20 21:13:07 所属栏目:电商 来源:网络整理
导读:《类Redis大容量存储-pika 主从复制原理之binlog》要点: 本文介绍了类Redis大容量存储-pika 主从复制原理之binlog,希望对您有用。如果有疑问,可以联系我们。 我们在《大容量类 Redis 存储 有关 pika 的一切》里介绍过pika的诞生、pika的特点、pika的核心

《类Redis大容量存储-pika 主从复制原理之binlog》要点:
本文介绍了类Redis大容量存储-pika 主从复制原理之binlog,希望对您有用。如果有疑问,可以联系我们。

我们在《大容量类 Redis 存储 — 有关 pika 的一切》里介绍过pika的诞生、pika的特点、pika的核心以及pika的使用.本文来自pika用户bigpyer(小米公司),他在文章中非常详细的解析了pika同步逻辑中的重要文件:“write2file”的数据存储方式及实现原理,非常值得一看!

pika

pika 是 360 Web 平台部 DBA 与基础架构组合作开发的大容量类 Redis 存储,pika 的出现并不是为了替代 Redis,而是 Redis 的场景补充.pika 力求在完全兼容 Redis 协议、继承 Redis 便捷运维设计的前提下通过持久化存储的方式解决 Redis 在大容量场景下的问题,如恢复时间慢、主从同步代价高、单线程相对脆弱、承载数据较有限、内存成本高昂等.

pika主从复制原理之binlog

binlog相关的文件包含两部分: manifest和write2file,其中manifest记录了日志元信息,包括当前日志文件编号、当前日志文件偏移量,write2file+num记录了pika接收到的所有redis写命令、参数.

文件格式

manifest文件格式:

日志偏移量(8字节)|con_offset(8字节,未使用)|元素个数(4字节,未使用)|日志文件编号(4字节).

Binlog文件格式:

Binlog

Binlog文件固定大小为100MB,每个Binlog文件由多个Block组成,每个Block大小固定为64KB,每一个写redis命令称为一个Record.一个Record可以分布在多个Block中,但只会分布在一个Binlog文件里,所以Binlog文件有可能大于100MB.

Record格式:Header|Cmd?

Header: Record Length(3字节)|时间戳(4字节)|记录类型(1字节).

Cmd: redis命令的一部分或者全部,取决于当前Block剩余空间是否可以存放该Record.

实现类

基本类

Version: 元信息类,通过mmap与manifest文件映射.

Binlog: 日志类,通过mmap与write2file文件映射.

PikaBinlogSenderThread: 日志消费类,顺序读取日志文件内容,消费日志.

基本操作

构造Binlog

//file_size可以在配置文件指定,默认为100MB

Binlog::Binlog(const std::string& binlog_path,const int file_size)

1.1 创建binlog文件目录.

1.2 检查log目录下manifest文件是否存在,不存在则新建.

1.3 根据manifest文件初始化Version类.

1.4 根据manifest中的filenum找到对应的日志文

件,根据pro_offset定位到文件append的位置,初始化日志指针、记录日志内容长度、Block块数量.

更新当前日志生产状态

//pro_num: 日志文件编号

//pro_offset: 日志文件偏移量

//用在需要全量同步时更新slave实例对应的binlog信息

Status Binlog::SetProducerStatus(uint32_t pro_num,uint64_t pro_offset)

2.1 删除write2file0.

2.2 删除write2file+pro_num.

2.3 构造新的write2file+pro_num文件,填充pro_offset个空格,初始化version->pro_num为pro_num,version->pro_offset为pro_offset,并刷新到manifest文件中.

2.4 初始化当前filesize、block_offset.

更新当前日志生产状态

//filenum: 当前日志编号

//pro_offset: 当前日志偏移量

Status Binlog::GetProducerStatus(uint32_t* filenum,uint64_t* pro_offset)

3.1 读取version中的pro_num、pro_offset并返回.

生产日志

//Put->Produce->EmitPhysicalRecord

Status Binlog::Put(const std::string &item)

4.1检查当前日志文件是否满足切割条件,如果满足则进行切割.

4.1.1 pro_num自增加1,初始化新的日志文件,version->pro_num=pro_num,version->pro_offset = 0,binlog->filesize = 0,binlog->block_offset = 0.

4.1.2 如果当前block剩余大小<kHeaderSize(8字节),则填充剩余空间为’x00″.

4.1.3 Produce是一个循环,保证在item大小超过kBlockSize时,可以进行多次EmitPhysicalRecord,完成item全部数据落入binlog文件,循环正常退出的条件是left==0.

4.1.3.1 如果left<avail,代表当前block可以存放完整的item,则type=kFullType,调用EmitPhysicalRecord一次,循环退出.

4.1.3.2 如果left > avail,代表需要多个Block存放item,则第一次Type=kFirstType,调用EmitPhysicalRecord多次.

4.1.3.3 如果left > avail,且不是第一次EmitPhysicalRecord,则Type=kMiddleType,调用EmitPhysicalRecord多次.

4.1.4EmitPhysicalRecord.

4.1.4.1 拼接RecordHeader(3字节长度+4字节时间+1字节Type),写入数据,更新block_offset、pro_offset.

消费日志

//scratch: 消费结果返回一个完整的redis cmd

//Consume->ReadPhysicalRecord,ReadPhysicalRecord每次读取一个完整的Record,多个Record构成一个完整的redis cmd

Status PikaBinlogSenderThread::Consume(std::string &scratch)

5.1Consume是一个循环,可能多次调用ReadPhysicalRecord,循环退出的条件是读取到的record_type==kFullType或record_type==kLastType.

5.1.1如果读取到的kBlockSize-last_record_offset_ <= kHeaderSize代表读到了Block的末尾,且为填充数据,skip掉.

5.1.2读取数据,更新last_record_offset_,con_offset.

结束

以上就是pika主从复制媒介write2file的全部解析了,下篇文章将会对pika主从复制的工作流程进行拆解、分析,文章同样来自bigpyer(小米公司),敬请期待!

文章来自微信公众号:HULK一线技术杂谈

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读