我一直在传统关系型数据库混迹,时间久了,也渐渐发现数据库的发展离不开生态,而已形成的生态很难去打破,总结现在最流行、最先进的关系型数据库,可划分为三种生态Oracle、PostgreSQL、MySQL。国内以Oracle、MySQL应用最为广泛,而近几年随着PGXC分布式架构的兴起,PostgreSQL也开始加快了在国内的应用,有代表性的如华为的GaussDB。各云厂商只要提供数据库服务,一定会有For PostgreSQL版。
最近有时间就看了PostgreSQL圣经《The Internals of PostgreSQL》,如果真的想好好研究PostgreSQL,可以好好看看这个书,有中文版叫《PostgreSQL指南内幕探索》。在看WAL日志一章节时,来了兴致,早年间研究过Oracle redo,之后研究过MySQL binlog,现在在看PostgreSQL WAL,这之间究竟差别有多大呢?各自设计的优缺点时什么?带着很多疑问,我耐心的去看起了资料。
WAL(Write Ahead Log),中文翻译过来叫”预写日志“,这种日志其实是关系型数据库通用的叫法,只不过Oracle和MySQL变换了一个叫法。它是关系型数据库必不可少的模块,可用于数据库恢复、高可用复制使用。
下面单独的说一说这三种数据库WAL日志:
1. Oracle
Oracle 预写日志叫REDO,中文称”重做日志“,一般会设置几组,当一组写完后,会写下一组,当几组都写完了后,会再循环写第一组,就这样轮询往复的不断写,为了让日志能够不断延续保留,又出现了一种日志”归档日志“,归档日志完全和redo是一样的日志,只不过redo是不断轮询,而归档是redo的过期数据,毕竟redo还要支持在线事务和crash safe。
那么redo是怎么记录的呢?
其日志是不可读日志,日志是由块组成的,而Oracle的redo写入是按照change vector的方式,数据记录,也就是数据行,是由若干个change vector组成的。因此数据的变更,实际上是通过change vector引起的块变更,因此我们称Oracle的redo日志是物理日志,而非逻辑日志(逻辑日志通常采用记录SQL语句的方式)。
2. MySQL
MySQL预写日志在5.6之前的版本只有BINLOG,后来有了innodb存储引擎,且慢慢的将innodb作为默认存储引擎后,就不止BINLOG了,还有REDO日志。
BINLOG日志现在主要作用仅是作为高可用复制使用了,REDO日志是用来解决数据一致性的及crash safe。
BINLOG和REDO其实没有什么太大的关系,REDO是innodb存储引擎带的功能,BINLOG是MySQL本身具备的预写日志的功能,二者日志的格式完全不一样,因此也不存在谁是谁的延续的问题。当然二者在写日志上要保持一致性的,过程还挺复杂,通过两阶段提交来保证。当然在这里只说BINLOG。
BINLOG是MySQL的预写日志,日志从名字上来看叫二进制日志,确实也是不可直接读的,但通过自带的mysqlbinlog是可以解析出的,解析出的内容并不是像Oracle一样,是通过change vector来改变块,而是通过一个叫event的事件来进行描述数据的变化,event是binlog的最小单元,如果细致的去看event,发现其实就是一些解释性语言来标记数据的变化,实际上仍然是SQL语句。如果要进行主从复制binlog_format是一定要设置row格式的,在event中就不在只是简单的SQL语句,还包含了行记录的变化,当然这仍然是解释性标记的,仍然可以当作SQL语句。
啰嗦这么多,其实也就是想说明MySQL的BINLOG并非是物理日志,而是逻辑日志,在从库回放时时通过SQL apply进程回放,看名字是不是更容易理解了。
3.PostgreSQL
PostgreSQL预写日志叫WAL,比较原生,在PostgreSQL中也称xlog record,PG中最小物理存储单元叫页(Page),PostgreSQL表数据在每个页面第一次变更时,会将这个页面及相应首部作为一条XLOG 记录写入,而这条记录也称为备份区块(backup block),那么再次对页面进行变更时,xlog记录就不再是备份块了,而是有两个结构体和一个数据对象组成。实际上就是定位实际变更位置,也可称之为”向量“或者”指针“。
这明显可以看出,PostgreSQL的WAL日志中和Oracle有着类似的change vector,还含了数据的备份区块。因此我们也成PostgreSQL的WAL日志为物理日志。
总结
三种数据库的预写日志分析完后,可见Oracle、PostgreSQL都是物理的预写日志,而MySQL则是逻辑的预写日志。
逻辑日志和物理日志的本质区别
预写日志的是实现时间点恢复和高可用复制的基础,在现代IT基础设施建设中高可用的能力直接体现了其可抗拒风险的能力,而数据库的预写日志方式,也决定了其所能承载的业务场景。
逻辑日志
逻辑日志实际上就是SQL语句的记录日志或可转化的SQL语句日志,在实现主从复制上,从库的重放仍然是和主库一样的语句执行过程,这在使用上是受到一些制约的,如一些触发器、存储过程、函数的使用,主库执行了,并触发了修改数据,那么到从库中如果应用不当,很容易引起数据的不一致。另外如果主库运行了较复杂的SQL语句,形成了长事务,那么这样的过程仍然要在从库走一遍,因此也更容易引起主从延迟。从MySQL的主从复制设计上,为什么会只有半同步,而没有全同步,这也是重要的因素。因此如果有企业说自己基于MySQL改造实现了全同步,如果没有对预写日志彻底改变,那么最好还是要好好考虑一下。
物理日志
物理日志从Oracle和PostgreSQL上看到,实际就是基于块的变更,那么在复制技术上,其也是基于块的形式,PostgreSQL stream复制,Oracle Dataguard均如此,刚才说的逻辑日志存在的两个缺点,在这里是不存在的,因此在基于物理日志的主从复制设计上,在从库日志落地以及日志应用,都会给主库发送ACK信号,以达到全同步的能力,即使做到同步设计,对主库的影响也不会很大。这也是Oracle Dataguard为什么敢实现最大保护模式,PostgreSQL stream可实现同步复制的原因了。
那么在基于逻辑日志和物理日志的WAL日志,我们知道了其优缺点,很容易定位该种数据库在企业中的使用场景了。
如果是企业要核心业务去Oracle,而采用开源或者国产数据库,了解预写日志是很有必要的,但这并不代表全部,还要看其工程实践完善程度和案例成熟度等多种表现。