日志除了记录报错还能干什么?不可不知的4种数据库日志

日志(Log)是系统行为的记录,它对追踪系统状态,排查系统故障起着重要作用。日志记录伴随着系统的运行过程,系统会把重要的内部状态信息记录到日志。在系统出错后,开发人员通过分析这些状态信息能够快速洞察隐藏在表象下的蛛丝马迹,快速恢复系统正常运行。

日志能用于排查错误,但日志的作用远不止于此。 在信息系统中,数据库是逻辑处理的核心,它决定了系统整体的性能和可靠性。要实现这些要求,数据库离不开日志,对日志的使用也最为复杂。看懂了数据库的日志处理,就可以做到全面地理解日志的作用。

数据库的日志最为复杂,不同的使用场景对日志有不同的期望:

  • 操作日志: 记录数据库操作,方便作归档和实现数据同步,常见的有 MySQL binlog。
  • 预写日志(可靠性日志) :快速地把数据操作持久化,避免数据丢失,也叫做 WAL(Write-Ahead Logging),常见的有 MySQL Redo Log、ElasticSearch Translog。
  • 回退日志:记录"反操作",实现回退已有操作,常见的有 MySQL Undo Log。
  • 数据存储日志:日志能记录系统状态,能不能直接存数据呢?不少 NoSQL 就使用 LSM(Log-Structured Merge-tree)这种特殊的日志来存储数据。

这些日志贯穿了数据库系统(Database System)运作的各个环节,在数据操作前先使用预写日志 保证持久化的可靠性,如果失败用回退日志 恢复到事前状态,操作成功记录操作日志 ,数据则存储到数据存储日志。不同的日志有不同的作用,也有大不相同的细节。

一、操作日志

操作日志的通用性很强,我们平常在自己系统记录的就属于这一类。对于数据库系统来说,操作日志有记录自身运行行为的日志,也有记录具体数据操作的归档日志。前者伴随数据库系统代码运行,主要用于排查数据库本身的问题,它记录了系统内部的运行状态信息。后者则更有针对性,只记录数据操作。这些数据操作相当于是所存储数据的"镜像",如果一个新的数据库来执行这些操作,就能够把数据存储同步到和当前数据库相同的状态。

数据操作日志可以实现数据的版本控制,以及跨服务器节点的数据一致性。在数据操作过程中,我们可能出现操作失误,例如误删了数据。这个时候操作日志作为历史记录,通过倒查它就能恢复数据到失误前的版本。恢复数据可以保证单服务器节点数据的正确性,如果要跨越多个服务器,保证多个数据库节点的一致性,操作日志同样有用。数据操作日志可以被复制,也可以通过网络传输。数据库从节点通过网络拉取不断刷新的操作日志,并重新执行日志操作来进行数据同步,从而实现了在网络层面的跨节点一致性。

不少数据库系统都提供了数据操作日志,比较知名的是 MySQL 的 binlog。binlog 在 MySQL 实现多节点集群、中间件数据同步上广泛使用。binlog 的解析、装载流程相对复杂,开源社区为了降低 binlog 的使用成本,衍生出了 Canal、Flink CDC 这样的以 binlog 为核心的数据框架。这些框架是应用层的模板整理与优化,离不开操作日志这个实现行为记录的核心元素。

二、预写日志(可靠性日志)

OLTP (在线事务处理)型数据库有个非常重要的特性,能够支持事务操作。事务把一组操作看作逻辑上的一个操作。这些操作有较高的相互依赖性,要么全部成功,要么全部失败。事务有四大特点:A(Atomicity,原子性)、C(Consistency,一致性)、I(Isolation,隔离性)、D(Durability,持久性)。要实现这些特点,最基本的是打好持久性(Durability)这个"地基"。预写日志(WAL,Write-Ahead Logging)是为了满足这个需求而设计的,它保证事务一旦执行成功,数据就不会丢失。

要保证数据不丢失,数据要尽可能快地从易丢失的内存保存到持久化的外存中。要对内存中的结构化数据实现快速持久化有很大的困难:

  1. 外存 I/O 慢,要保存的数据量越大,需要的保存时间越久。
  2. 数据是以结构化的形式留存在内存中,数据分散,数据变动的影响范围大。这就像要跨部门协作完成一个任务,虽然任务的工作量不大,但每个部门为了响应任务都需要作出相应的变动,存在较高的协调成本。

为了加快持久化,需要一种特殊的数据格式,数据量要尽可能小,变动范围要尽可能收敛 。预写日志(WAL)是解决这些问题的有效手段。预写日志(WAL)在真正地进行数据操作前,先把将要执行的操作 (只是操作,而不是最终的结构化数据。以部门协作的例子为背景,预写日志只记录要做的任务,先不联系各部门)以顺序写入的形式快速 I/O 到外存。由于预写日志只记录操作,并且是按顺序记录,I/O 时间可以做到很短,事务的持久性(Durability)也就得到了较高的保证。但 I/O 时间没法完全消除,时间间隔仍然存在。数据可能会丢失,但概率已经大大下降。

预写日志(WAL)和结构化数据本质上是重复的,这些日志存得越多,存储空间浪费越大。为了压缩这块的成本,预写日志(WAL)采用了循环写入固定大小存储空间的形式。一旦日志记录到了这块固定空间的结尾,写入指针就回到空间的开头,用新数据覆盖掉老数据。为了保证这些老数据的内容不丢失,在写入覆盖前,先把预写日志对应的结构化数据同步到外存,再标记这些老数据为失效状态。

预写日志(WAL)存在于有较高可靠性要求的数据库系统,比如有 MySQL Redo Log、ElasticSearch TransLog。预写日志虽然能保证较高的可靠性,但并非必须。它对成本存在一定的消耗,且大部分的使用场景对可靠性不会有很高的要求。

三、回退日志

事务在保证持久性外,还有一个重要的特性,原子性。在逻辑上看,事务里的一组操作是一个操作,要么都成功数据都更新,要么都失败数据都回退。当事务执行到一半时出现错误,这时数据的状态已经更新到一半。既然没法都更新成功,要怎么才能都回退,回到初始状态?我们是不是要记录操作前的原始数据?

回退日志(Undo)是用来记录原始状态的,但它记录的不是数据,而是"反操作"。反操作是正常数据操作的反转,比如删除数据对应插入数据,插入数据则对应删除数据。假设现在删除了一个用户张三,回退日志(Undo)就会记录一条插入用户张三的"反操作"。当事务执行到一半失败时,系统就能读取回退日志(Undo),通过执行这些反操作来恢复到初始状态。

四、数据存储日志

不论是操作日志,预写日志,还是回退日志,它们都是对数据行为的记录。根据这些行为能实现数据的同步、数据可靠的持久化、以及数据的回退,这都是对数据存储的辅助,并不是数据库系统所保存的数据本身的结构。能不能做得更彻底一点,直接用日志存储数据。LSM(Log-Structured Merge-tree)就是一种实现数据存储的"日志"。

LSM 由一组日志文件组成,日志文件内和日志文件间保持了高度的有序性。维持有序性是为了实现高效的数据检索。B+ 树常作为实现高效数据检索的常用数据结构,它通过离散的有序树来存储数据,具有相对大小的树节点间靠指针串联起来。LSM 不是这样的离散结构,LSM 里的有序日志文件就像是一个排好序的"数组",它用连续的空间来存储数据。对这个空间进行数据查找,我们可以类比下二分查找法,数据扫描时不停地比较和数组中位数的相对大小,便能快速的缩小数据查找范围,实现数据检索过滤。

LSM 能在大量的 NoSQL 中得到采用,它的连续有序存储结构发挥了重要的作用。连续有序存储结构让 LSM 既能实现不错的数据检索速率,也能快速地完成数据写入,因为连续的存储结构在物理上保障了 LSM 的性能。数据库极度依赖快速的 I/O,最好的 I/O 形式就是连续的进行顺序 I/O,且 I/O 进入外存的数据都是有效数据。由于 LSM 本质上是日志,这些日志没有任何多余,都是有效数据。而且日志记录都是以追加的形式连续写入,天生就是顺序 I/O。

LSM 检索性能不错,写入性能优良,要实现大规模数据存储的 NoSQL 都大量使用 LSM,比如 ElasticSearch。

五、总结

好了,4 种实用的日志类型就介绍到这了。数据操作很复杂,有了日志就"好办"。我们要保证数据的一致、可靠,做好数据的归档、存储,这都离不开日志。

看到这里如果觉得有帮助,请点赞👍、收藏⭐、关注❤️,我会一直保持更新。

六、参考资料

  1. 数据同步工具之FlinkCDC/Canal/Debezium对比,腾讯云开发者社区
  2. Write-ahead logging,Wikipedia
  3. Introduction to Log structured merge (LSM) Tree,GeeksforGeeks
相关推荐
pany14 分钟前
体验一款编程友好的显示器
前端·后端·程序员
DyLatte19 分钟前
节食正在透支程序员的身体
程序员
Java水解20 分钟前
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
后端·spring
开始学java26 分钟前
继承树追溯
后端
何中应31 分钟前
分布式事务的两种解决方案
java·分布式·后端
TDengine (老段)1 小时前
TDengine IDMP 运维指南(管理策略)
大数据·数据库·物联网·ai·时序数据库·tdengine·涛思数据
SimonKing1 小时前
无需重启!动态修改日志级别的神技,运维开发都哭了
java·后端·程序员
Full Stack Developme1 小时前
PostgreSQL interval 转换为 int4 (整数)
数据库·postgresql
larance1 小时前
FastAPI + SQLAlchemy 数据库对象转字典
数据库·fastapi