作者:张旭 MO研发工程师
目录
Part 1. 事务回顾
Part 2. 事务的正确性问题
Part 3. 如何高效 DEBUG
熟悉数据库分布式事务的读者,应该能够理解DEBUG分布式事务正确性问题的BUG是一件非常有挑战的事情。本文主要是给大家介绍一下,MatrixOne在研发过程中,是如何DEBUG事务正确性问题的。
1. 事务回顾
我们首先来回顾一下,在 MatrixOne 中,事务是如何实现的。
1.1 数据存在哪儿
MatrixOne 是一个云原生的数据库,数据库中大部分的数据都存储在对象存储
(可以是任何S3
兼容的对象存储)中,这部分数据是不变的。数据不可变带来了非常多的好处,比如不需要考虑这些数据的一致性问题。
除了存储在对象存储
中的数据外,还有非常少的数据存储在LogService
中,LogService
是一个使用 Raft 实现的高性能的 WAL
服务。这部分数据在 MatrixOne 中被称为 LogTail
。这部分数据是变化的,可以认为是 MatrixOne 集群最新的 Commit 数据。
对象存储
+ LogTail
组成了 MatrixOne 的全量数据。
1.2 事务隔离级别
MatrixOne 的事务支持RC
和SI
的隔离级别,默认是RC
。
1.3 事务模式
MatrixOne 的事务支持悲观
和乐观
的模式,默认是悲观
。
1.4 事务并发控制
MatrixOne 使用 MVCC 来实现事务并发控制。并且使用 HLC
来实现事务时钟。
1.5 事务读操作
对于事务的读操作而言,首先需要确定的就是哪些数据对于事务是可见的。在任何一个时刻,对于事务可见的数据包括:
- 对象存储中所有
CommitTimestamp < txn.SnapshotTimestamp
的数据 - LogTail中所有
CommitTimestamp < txn.SnapshotTimestamp
的数据 - 事务的
Workspace
中所有的Uncommitted
的数据
在我们明确哪些数据对于事务是可见的时候,就需要确定满足条件的数据在读发生的时候,是否完整。
Workspace
中的数据,任何时刻对于事务都是完整的。需要保证的就是对象存储
和LogTail
的数据了。由于LogTail
是整个 MatrixOne 集群最新的数据写入,所以只要保证LogTail的数据完整了,那么对象存储
对应的数据对于事务也就完整了。
现在的问题就是如何保证LogTail
的数据对于事务是完整的。
MatrixOne 的事务在CN节点创建,事务创建后,就会明确一个事务的SnapshotTimestamp
(这个时间戳对于SI
是整个事务生命周期不变的,对于RC
是每个Statement
的生命周期内是不变的)。
LogTail
的数据在TN
节点产生,并且写入LogService
。CN使用订阅的方式来获得最新的LogTail
数据,并且把这些LogTail
中的数据Apply
到CN的内存中。
CN在内存中维护了一个最大的Apply
的CommitTimestamp
,可以根据这个时间戳的水位和事务的SnapshotTimestamp
来确保,LogTail的数据对于事务是完整的。
1.6 事务的写操作
MatrixOne 事务的 Uncommitted
的数据,都是写入 Workspace
,这个 Workspace
在CN的内存中。
一个事务写入的数据越多,这个Workspace
占用的内存越大,知道OOM发生。MatrixOne 为了解决这个问题,对于Workspace
的内存大小有一个阈值(默认是1MB),当发现Workspace
的内存超过这个阈值,就会把Workspace
中的数据写入到对象存储
,在Workspace
的数据会被替换成对象存储上临时文件名
。
事务在没有Commit之前,不会和TN
交互,在Commit
的时候,会把Workspace
的数据发送给TN
节点做Commit
处理。
2. 事务的正确性问题
2.1 什么是正确性问题
上面的章节我们回顾了事务,现在需要说明一下,什么事事务正确性的问题。在 MatrixOne 的研发过程中遇到事务正确性的BUG主要有以下几种:
RC
模式下的Lost Update
悲观事务
锁服务失效Workspace
数据问题
这几个问题都会产生事务正确性问题。这些问题,都会产生事务读了错误的数据,或者提交了错误的数据。
2.2 如何测试
MatrixOne 很多的测试,来帮助我们发现这些事务正确问题,这些测试包括:
- 单元测试
- 集成测试
- PR Merge之前的CI测试
- PR Merge之后的性能基准测试
- 7*24小时执行的稳定性测试
- daily的各种测试
- chaos 测试
这些测试都会帮助我们发现事务正确性问题。
2.3 常规分析问题的手段
对于研发来说,我们常规的分析问题的手段一半是这几种:
- 断点Debug
- 分析日志
- Metrics
- Tracing
对于分析分布式集群的事务问题,其中最有用的就是日志,其余手段几乎没有用。