硬件DMA和物理复制实现的数据库多副本
大家都知道关系型数据库的重要特性归纳起来是“ACID”,其中A是原子性,C是约束,I是隔离性,D是持久性。
POLARDB将从两个维度出发,从根本上改进多副本复制。一个是保证数据库ACID中的D(Durable),把网络、存储硬件提供的DMA能力串起,用硬件通道高性能的把主库的日志数据持久化到三个存储节点的磁盘中;另一个是实现了高效的只读节点,在主库和只读节点之间通过物理复制同步数据,直接更新到只读节点的内存里。如何实现?
POLARDB实现日志数据持久化到三个存储节点的磁盘中。主库通过RDMA将日志数据发送到存储节点的内存中,存储节点之间再通过RDMA互相复制,每个存储节点用SPDK将数据写入NVMe接口的存储介质里,整个过程CPU不用访问被同步的数据块(Payload),实现数据零拷贝。
同时由RDMA网卡和NVMe控制器完成数据传输和持久化,CPU仅做状态机的维护,在一致性协议的协调下,把网卡和存储卡两块硬件串起来,存储节点之间数据同步采用并发Raft(ParallelRaft)协议,和Raft协议一样,决议在leader节点上是串行生成和提交的,但并发Raft协议可以允许主从之间乱序同步,简单的说,允许follower节点在漏掉若干条日志的情况先commit并apply后面过来的日志,并异步的去补之前漏掉的日志,数据同步的性能和稳定性都显著优于Raft协议。
POLARDB在主库和只读实例之间的数据流上,放弃了基于binlog的逻辑复制,而是基于innodb的redolog实现了物理复制,从逻辑复制到物理复制对主库和从库性能带来的提升都非常明显。
在主库上,原本引擎需要和binlog做XA事务,事务要等到binlog和redolog同时写盘后才能返回,去掉binlog后,XA事务可以去掉,事务的执行路径更短,IO开销也更小。在从库上,redolog由于是物理复制,仅需比对页面的LSN就可以决定是否回放,天然可以多线程执行,数据的正确性也更有保证,此外,POLARDB的从库收到redolog后只需要更新缓存里的页面,并不需要写盘和IO操作,开销远低于传统多副本复制里的从库。
针对数据库加速的Smart Storage
POLARDB的存储节点针对数据库的IO workload进行了一些针对性的优化。
IO优先级优化:POLARDB在文件系统和存储节点两层都开了绿色通道,对redolog文件的更新进行优待处理,减少排队,提高IO的优先级。redolog也从512对齐调整为4k对齐,对SSD性能更加友好。
double write优化:POLARDB存储节点原生支持1MB的原子写,因此可以安全关闭doublewrite,从而节省了近一倍的IO开销。
group commit优化:POLARDB里一次group commit可以产生写入几百KB的单个大IO。对于单个SSD,延迟和IO的大小是呈线性的,而POLARDB从文件系统到存储节点都进行一系列优化来保证这种类型的IO能尽快刷下去,针对redolog文件进行条带化,将一个上百KB的大IO切割为一批16KB的较小IO,分发到多个存储节点和不同的磁盘上去执行,进一步的降低关键IO路径的延迟。
2. POLARDB的计算引擎性能优化
使用共享存储物理复制
由于POLARDB使用共享存储和物理复制,实例的备份恢复也做到完全依赖redolog,因此去掉了binlog。使得单个事务对io的消耗减少,有效减少语句响应时间,提升吞吐量。同时避免了引擎需要与binlog做的XA事务逻辑,事务语句的执行路径更短。
锁优化
POLARDB针对高并发场景,对引擎内部锁做了大量优化,比如把latch分解成粒度更小的锁,或者把latch改成引用计数的方式从而避免锁竞争,例如Undo segment mutex, log system mutex等等。PolarDB还把部分热点的数据结构改成了Lock Free的结构,例如Server层的MDL锁。
日志提交优化
Redolog的顺序写性能对数据库性能的影响很大,为了减少Redolog切换时对性能的影响,我们后台采用类似Fallocate的方式预先分配日志文件,此外,现代的SSD硬盘很多都是4K对齐,而MySQL代码还是按照早期磁盘512字节对齐的方式刷日志的,这样会导致磁盘做很多不必要的读操作,不能发挥出SSD盘的性能,我们在这方面也做了优化。我们对日志提交时Group Commit进行优化,同时采用Double RedoLog Buffer提升并行度。