Global Distributed Database日志的逻辑解析—视图
一、概述
本文意在说明GDD如何依据日志进行逻辑解析,由于篇幅有限,仅以比较具有代表性的视图相关DDL为例。
1.1 GDD回顾
GDD是一套高可用、高并发的互主多活容灾架构,通过实现Raft协议保证数据一致性。
GDD各节点的变更数据捕获(CDC)依赖对HaloDB的WAL日志进行逻辑解析。
1.2 视图和规则系统
HaloDB中视图是通过规则系统来实现的。
create view halo_view as select * from halo_table;上面创建视图的语句与下面两个命令的执行结果是相同的:
create table halo_view (same column list as halo_table);create rule "_RETURN" as on select to halo_view DO INSTEAD SELECT * FROM halo_table;
所以视图的本质上就是定义层面上只有列概念的、数据层面上无数据的特殊表及表上的特定规则。
1.3 前置条件
支持视图相关的DDL解析,需要依赖以下几项内容:
1)支持解析replica级别日志下的系统表变更。
2)支持解码Heap、Heap2、Transaction类型的日志消息。
3)支持分析表相关的DDL。
1.4 日志级别
从日志信息量的丰富程度、日志解析的难易程度、解析DDL的实现顺序对日志级别进行划分,共有三个阶段:
1)支持logical级别日志的用户表变更,这是初级的阶段。
在此基础上,支持FPI(全页写)的解析、存储、维护,进入中级阶段。
2)支持replica级别日志的用户表变更,这是中级阶段。
在此基础上,支持本地数据字典的构造、维护,进入高级阶段。
3)支持replica级别日志的系统表变更,这是高级阶段。
1.5 日志消息类型
WAL日志中出现的日志消息类型有很多种,其中与视图DDL关联性较大的有:Heap、Heap2、Transaction三种类型的消息。Heap类型消息对应大部分系统表的增删改操作,Heap2类型消息对应pg_attribute系统表的批量插入操作,Xact类型消息对应事务的控制操作。三个消息类型中相对重要的动作如下:
Heap:insert/update/delete动作。
Heap2:multinsert动作。
Xaxt:commit/abort动作。
二、视图的物理存储—系统表中的存储格式和内容
HaloDB数据库的物理存储载体是操作系统中的文件。数据库对象的定义以行的形式存储在对应各系统表中。一个数据库对象的定义往往涉及到多张系统表,下文将主要介绍两张核心系统表。
2.1 核心系统表pg_class的解读
系统目录pg_class中的视图信息与表的信息表现形式是相似的。所以对于解析器来说,表和视图之间没有区别。它们是同样的事物:关系。
2.2 核心系统表pg_rewrite的解读
视图最核心的部分:规则的定义,存储在pg_rewrite.ev_action中。
三、从SQL到日志—产生WAL日志的顺序和内容
该章节描述了执行一条SQL时,数据库内部在日志内容、系统表数据上产生的影响。
3.1 CREATE TABLE
由图可见创建一个简单表在日志中产生的日志如上图:
无论何时创建表,还会自动创建一个与表同名的复合类型来表示表的行类型。所以一次create table产生的WAL日志中有两条对pg_type(1247)的操作。
pg_depend(2608)记录数据库对象间的关系,可忽略。
pg_class(1259)记录数据库对象的信息,对应halo_table。
pg_attribute(1249)记录列的信息,第一条对应id,第二条对应cmax等六条隐藏列。
3.2 CREATE VIEW
由图可见创建一个简单视图在日志中产生的日志如上图:
前半部分与建表大致相同,区别是不产生约束、索引、隐藏列等数据库对象。
后半部分多产生了两条记录。
pg_rewrite(2618):记录重写规则,对应视图定义。
pg_class(1259):更新halo_view条目信息,创建视图的整个流程完毕。
3.3 REPLACE VIEW
视图的取代分两种情况:视图定义的变化和视图属性的变化。
进行视图取代操作时,无论视图属性是否发生实质变化,都认为发生了取代操作。
视图定义变化时必须产生和现有视图查询相同的列,也可以在目标列表的末尾加上额外的列,并对应产生加列的日志。
3.4 DROP VIEW
删除视图即创建视图的反序相反操作。
3.5 ALTER VIEW
修改视图属性同修改表属性产生的记录相同,pg_class中对应条目的相应项对应变化。
四、从日志到SQL—逻辑解析得到SQL的类型和内容
视图相关DDL中较为复杂的行为有创建、取代、修改视图,下图展示了各DDL的语法树并标明了各组成部分的数据来源,即结合特征判断、由对应系统表的对应字段拼接得出SQL。
4.1 数据库对象的相关信息
源自pg_class和pg_rewrite中视图对应条目各项的值,通过pg_rewrite.ev_class=pg_class.oid建立两张系统表之间的关联。
4.2 视图属性的相关信息
源自pg_class中视图对应条目各项的值,当涉及到属性变更时,旧值来自上文中提到的本地数据字典。
4.3 视图定义的相关信息
源自pg_class中ev_action项的值。
4.4 视图中列的相关信息
源自pg_attribute和pg_attrdef中对应条目各项的值。
五、围绕视图进行的其他设计
视图相关DDL解析这一功能在实际应用中往往会遇到复杂场景,以下是一些常见复杂场景的解决方式。
5.1 显式事务/级联删除
当一个事务中包含多条SQL时,包括DML与DDL交叉出现、DDL与DDL交叉出现等各种情况,此时不能仅以事务的提交或xid的变化做为对日志分割的依据,要准确判断DDL的开始和结束,依此做为分割条件。需要考虑生产上可能发生的各种场景,对其产生的日志内容组合进行预设,从而达到准确拆分的目的。
5.2 临时视图
分析视图相关DDL时,对其模式进行判断。需要对以pg_temp_开头为模式名的视图进行处理(过滤临时视图)。
5.3 长定义视图
视图定义过长时(默认超过2K),视图定义会以toast的形式进行存储在pg_toast.pg_toast_2618表中,需要解析该表的toast数据变更。