作者简介:镜水,一个无限进步的数据库学徒。
作者简介:海芊,一个致力于当网红的 OceanBase 文档工程师。

本文主要介绍 OceanBase 数据库的 Slog 日志,从代码层面剖析 Slog 日志的模块结构和工作机制,帮助大家深入理解OceanBase 数据库的 Slog日志。

基本概念

我们都知道 OceanBase 数据库的 Clog 日志类似于传统数据库的 Redo 日志,因此在分布式场景下需要多副本同步。而 Slog 不一样,Slog 可以理解为服务器的本地日志,是一台服务器上一些全局信息变更操作(如新增租户、分区创建和新增 SSTable 等)的 redo log。

一个服务器只拥有一个 Slog 写入流,也就是说同一台服务器上具有不同资源池的不同租户并不具有单独的 Slog 文件,所有租户的 Slog 写入请求最后都会汇入服务器所拥有的 Slog 文件中。

一条 Slog 日志记录的格式为:

从上图可以看出,Slog 分为三部分,其中每个部分可以理解为一个 log 块,具有递增的 log_seq 序号,保存在LogEntry 内(log 块的 header):

1. Logs,有效的 redo log 内容,可能包含多条实际的子 redo log,每条子 log 有子 log_seq(从 0 开始递增)。

2.NopLog,无意义的 log 内容,只是为了让整条记录 4k 对齐。

3.SwitchLog,只在一个 slog 文件的最后一条记录出现,包含 next file id,便于切换下一个 Slog 文件继续读取,同时也会包含 padding buffer 做对齐。

代码分析

接下来从代码层面展开分析 Slog。(由于 NopLog 和 SwtichLog 没有实际的 redo log 内容,因此这里不展开分析)

日志结构

每条 Slog 记录的 logs 部分(上图所示的第一部分 log 块)的格式如下:

ObLogEntry + n * log content

ObLogEntry 可以理解为整个 log 块的 header:

struct ObLogEntry {ObRecordHeader header_;uint64_t seq_;  // 整个 log 的 log_seqint32_t cmd_;     // 该 log 的类型,比如 OB_LOG_NOP 表示该 log 的类型为 NopLog// 具体见 enum LogCommand
}struct ObRecordHeader {  int16_t magic_;            // magic numberint16_t header_length_;    // header lengthint16_t version_;          // versionint16_t header_checksum_;  // header checksumint64_t timestamp_;        //int32_t data_length_;      // length before compressint32_t data_zlength_;     // length after compress, if without compresssion// data_length_= data_zlength_int64_t data_checksum_;    // record checksum ...
}

n * log content 在内存中由 ObStorageLogActiveTrans 结构进行组织管理,以序列化的形式共同存放在 log_buffer_

struct ObStorageLogActiveTrans {enum common::LogCommand cmd_;            // 等同于 ObLogEntry 中的 cmd_int64_t log_count_;                    // log_buffer_ 中包含的 log 数量common::ObLogCursor start_cursor_;    // log_buffer_ 中第一条 log 刷盘的位置// 在 log_buffer_ 刷盘时被赋值ObStorageLogValidRecordEntry valid_record_;ObBaseStorageLogBuffer log_buffer_;  // 所有 log content 的 buffer...
}

每个 log content 由一个 log header(ObBaseStorageLogHeader 结构)和实际的 log data 组成。

struct ObBaseStorageLogHeader {...int64_t trans_id_; // 事务 id,每次 Slog 的写入对应有一个事务 idint64_t log_seq_;  // 每条 log content 在整个 logs 里的 seqint64_t subcmd_;    // 32bit(main_type)+32bit(sub_type)// main_type 表示日志与什么相关,sub_type 表示该日志的具体操作类型// 如main_type = OB_REDO_LOG_PARTITION 表示日志与分区相关,具体见 ObRedoLogMainType// 如sub_type = REDO_LOG_ADD_PARTITION 表示增加分区日志,每种 main_type 都有单独对应的 XXXRedoLogSubcmdint64_t log_len_;uint64_t tenant_id_;int64_t data_file_id_;...
}

每次 Slog 的写入可以看做是一次事务,包括了 trans begin/n * trans/trans commit,而每个事务的子操作对应着一个 log content(包括 begin/commit)。

写入流程

1.ObBaseStorageLogger::begin 开启一次 Slog 写事务:

(1)ObBaseStorageLogger 的 ObStorageActiveTrans 池中取出一个元素 trans_entry 用于本次 Slog 写事务。

(2)向 trans_entry 中 append 一条 begin 日志,即写入 trans_entry 的 log_buffer_

2.多次调用 ObBaseStorageLogger::write_log

(1)正常条件下每次调用都向 trans_entry 的 log_buffer_ append 一条 log content

(2)当 trans_entry 的 log_buffer_ 达到上限(512-3*4-4 KB)时,对 log_buffer_ 里已有的 log 内容进行 flush。

(3)当 log 本身长度超出上限(512-3*4-4 KB)时,首先对 log_buffer_ 里已有的 log 内容进行 flush,然后扩大 trans_entry 的 log_buffer_,将超长 log append 到 log_buffer_,并再次 flush,最后恢复 trans_entry 的 log_buffer_ 大小。

3.ObBaseStorageLogger::commit 提交(结束)Slog 写事务:

(1)向 trans_entry 中 append 一条 begin 日志,即写入 trans_entry 的 log_buffer_

(2)直接对 log_buffer_ 进行 flush。

flush 流程

1.ObBaseStorageLogger::flush_log 对一个 log_buffer_ 已满(或超长 log)的 ObStorageActiveTrans 进行刷盘操作:

(1)调用 Slog 写盘类 ObStorageLogWriter 的 flush_log 函数进行 Slog 落盘。

(2)首先从 ObStorageLogWriter 的 ObStorageLogItem(结构如下)池中取出一个元素 log_item,然后使用 log_buffer_ 构造 Logs 的 log 块(log_buffer_ 就对应了前文的 n*log content),并依次构造 NopLog 的 log 块以及 SwitchLog 的 log 块(如果有的话),最终构造成完整的一条 Slog 记录(最长为 32 MB)并填充到 log_item 的 buf_

(3)log_item 构造完成后进行写盘操作(涉及到异步操作,这里不做介绍)。

class ObStorageLogItem : public common::ObIBaseLogItem {...bool is_inited_;bool is_local_;  // indicate whether buf_ is allocated locally or notint64_t buf_size_;char* buf_;int64_t len_;common::ObThreadCond flush_cond_;bool flush_finish_;int flush_ret_;
}

flush 流程的核心是通过写流程中得到的 n * log content 构造出一条完整的 Slog 记录,通常可以直接用 ObStorageLogItem 结构指代。

示例

上图是 ob_admin 的 slog_tool 工具所显示的某 slog 文件的部分日志内容。

1.log_seq=1 的 redo log 共有三个 log content,其中每个 log content 都有自身的 sub_seq

(1)每个 log content 的 command = 626(OB_LOG_TABLE_MGR),表明都是与 TableMgr 相关的 log。

(2)sub_seq=1 的子日志的 main_type = 3(OB_REDO_LOG_TABLE_MGR),表明是与 TableMgr 相关的 log,而 sub_type 在图中没有以值的方式标出,实际上其 sub_type = 8(REDO_LOG_COMPELTE_SSTABLE),也就是图中的 complete sstable 含义。

2.log_seq=2 的 log 为第一条 Slog 记录的 NopLog,因此图中并没有显示该 log,而是只显示了 log_seq=1 以及 log_seq=3 的 redo log。

优化版本

由于一次事务的所有 redo log 数据量可能很小,如果每一次事务都直接增加 noplog 构造 ObStorageLogItem 刷盘,空间浪费且带宽浪费,因此可以聚合多次事务,flush 时将多次事务的 redo log 添加到队列,真正异步写盘时将多次事务的 logs 聚合成新的 ObStorageLogItem,从而形成如下结构:

checkpoint

这里不介绍 checkpoint 的具体触发条件和执行流程,感兴趣的同学可以进一步阅读代码。

工作机制

为了加快恢复,Slog 提供 checkpoint 机制,生成 checkpoint 的过程也就是形成元数据宏块的过程,元数据宏块,也就是所谓的 Meta Block,会写入 block_file,Slog 同时会具有一个回放点(replay_start_point_),标明了 Slog 内尚未生成 checkpoint 的剩余日志的起始偏移位置。Meta Block 的入口点以及 Slog 的回放点都保存在 Super Block,想要了解更多相关内容可以阅读宏块或 OBServer 恢复的相关文章。

恢复

OBServer 对于 Slog 日志需要恢复的数据分为两部分,一部分是已经 checkpoint 形成 Meta Block 的基线元数据,另一部分是从 Slog 回放点开始的 Slog 日志,也就是增量元数据。

以上便是 OceanBase 数据库 Slog 的详细介绍,

更多知识和干货请点击链接查看原文及社区:

https://open.oceanbase.com/articles/8500124?sou0c001

最后的最后:

如果大家有任何疑问,可以通过以下方式与我们进行交流:

测试遇到问题?

企业用户想享受技术顾问的免费一对一咨询服务?

快加入 OB 创计划→

https://open.oceanbase.com/articles/8000125?sou0c001

钉钉群:33254054

欢迎大家一起参与社区贡献,指南请参考看 这里

社区答疑:请点击 这里

一文读懂 OceanBase 数据库的SLog日志相关推荐

  1. [数据库] 一文读懂Mysql数据库索引实现原理

    咱们用了这么久Mysql数据库做项目,你知道数据是怎么存在数据库里吗?他们是如何存储的吗? 今天咱们就来扒一扒Mysql数据库索引的底层实现,Mysql数据库的索引是由都是由B+树实现的,那为什么不是 ...

  2. 一文读懂 UniProt 数据库(2023 最新版)

    一.UniProt 数据库介绍 Uniprot (Universal Protein )是包含蛋白质序列,功能信息,研究论文索引的蛋白质数据库,整合了包括EBI( European Bioinform ...

  3. 一文搞懂MySQL数据库分库分表

    如果数据量过大,大家一般会分库分表.分库需要注意的内容比较少,但分表需要注意的内容就多了. 工作这几年没遇过数据量特别大的业务,那些过亿的数据,因为索引设置合理,单表性能没有影响,所以实战中一直没用过 ...

  4. 即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

    本文引用了"蔷薇Nina"的"Nginx 相关介绍(Nginx是什么?能干嘛?)"一文部分内容,感谢作者的无私分享. 1.引言 Nginx(及其衍生产品)是目前 ...

  5. 一文读懂大数据平台——写给大数据开发初学者的话!

     一文读懂大数据平台--写给大数据开发初学者的话! 文|miao君 导读: 第一章:初识Hadoop 第二章:更高效的WordCount 第三章:把别处的数据搞到Hadoop上 第四章:把Hado ...

  6. 一文读懂密码学中的证书

    一文读懂密码学中的证书 之前的文章中,我们讲到了数字签名,数字签名的作用就是防止篡改和伪装,并且能够防止否认.但是要正确运用数字签名技术还有一个非常大的前提,那就是用来验证签名的公钥必须真正的属于发送 ...

  7. gps导航原理与应用_一文读懂角速度传感器(陀螺仪)的应用场景

    前文我们大致了解陀螺仪的来历,原理和种类,那么,它与我们的日常生活有怎样的关系呢? 陀螺仪器最早是用于航海导航,但随着科学技术的发展,它在航空和航天事业中也得到广泛的应用.陀螺仪器不仅可以作为指示仪表 ...

  8. 区块链产业生态、存在问题及政策建议|一文读懂新趋势

    区块链产业生态.存在问题及政策建议|一文读懂新趋势 2017-03-03 09:47:50  来源: 腾讯研究院抢沙发 摘要:从技术上来讲,区块链是一种分布式的记账方法.说到记账,我们经历了从实物记账 ...

  9. mysql 默认事务隔离级别_一文读懂MySQL的事务隔离级别及MVCC机制

    回顾前文: <一文学会MySQL的explain工具> <一文读懂MySQL的索引结构及查询优化> (同时再次强调,这几篇关于MySQL的探究都是基于5.7版本,相关总结与结论 ...

最新文章

  1. cmake语法【一】
  2. 更换YUM及升级包方法
  3. Flutter 基础Widgets Text()之TextStyle详解
  4. Linux线程(五)
  5. iView 一周年了,同时发布了 2.0 正式版,但这只是开始...
  6. C++ 读取文件操作
  7. 中文版Visual Studio 2008 SP1 智能提示为英文的补丁发布
  8. [置顶文章]打豆豆的一些小问题、不小心会忘记的知识点
  9. 如何将多张图片合成一个pdf?
  10. Win10隐藏图标怎么恢复
  11. java中的g1_G1GC 概念与性能调优
  12. 常微分齐次方程的规范化通解
  13. 怪异,漂亮的几个数学恒等式(转)
  14. Linux下一种 ELF 文件的代码签名验证机制
  15. 微信小程序加入企业微信群聊
  16. 机器学习:决策树的预剪枝和后剪枝
  17. Tableau作图——动态图
  18. 除了闹过腥风血雨的fastjson,你还知道哪些Java解析JSON的利器?
  19. 2022-2028全球与中国智能家居监控和安全市场现状及未来发展趋势
  20. 微信小程序计算圆周长和面积

热门文章

  1. 【附源码】计算机毕业设计SSM面向智慧城市的智慧农业管理系统
  2. java计算机毕业设计企业管理系统源码+程序+lw文档+mysql数据库
  3. 爱情还你,骄傲还我!
  4. “两条腿”走路的德邦,如何拿下净利润大增超400%神话?
  5. c语言验证卡不列克常数,卡布列克数
  6. 基于SPI flash的 Multiboot远程更新
  7. 20万大奖等你拿!阿里聚安全攻防挑战赛报名开启!
  8. 智能家居平台乱战,京东欲借“超级APP”争夺控制中心
  9. 安利一个我喜欢的博主(鱼皮)的项目----鱼聪明AI
  10. 如何挑选水货诺基亚手机