PostgreSQL学徒

《深入浅出 Greenplum 分布式数据库》读后感

前言

前阵子看到三水在朋友圈推荐了一本新书《深入浅出 Greenplum 分布式数据库》,Greenplum 在 MPP 领域的地位不用多说,常青不凋,现在新书上市,还是一本原理性的书籍,那自然不容错过,果断买入。

Image

最近忙得直抠脑壳,在今晚的出差旅途上才终于得空,能够静下心来细细品味这本书,全书内容量并不多,不到 200 页,小而精,加之笔者也有相关领域的基础,前后大约花费两小时,全文浏览了一遍,收获不少,简单分享一点读后感。

理论介绍

本书前三章介绍了相关数据库理论

1.云原生数据库,并不是将数据库简单地搬到云上就算"云原生",云原生数据库不仅要基于云端硬件资源池化来实现数据库的计算存储弹性伸缩和分布式部署能力,还需要能够利用云基础设施本身的特性,比如跨可用区的部署能力、全栈解耦、结合全密态和防篡改技术等等。2.分布式数据库理论,CAP、BASE,以及一致性算法,2PC/3PC/Paxos 等等。3.并发控制,在并发控制一章中,除了常规的 MVCC 相关介绍,还提到了 Blink-tree,也可以称之为 B* 树 (或者说 nbtree,src/backend/access/nbtree),不同于 BTREE 和 B+ TREE,BLink-Tree 的设计来源于论文 1981 ACM论文 "Efficient Locking for Concurrent Operations on B-Trees",Blink tree 使用双向指针指向节点的左右兄弟节点,并在叶子节点和非叶子节点上引入了 High-key,以此增加了并发能力,相关论文过于晦涩,感兴趣的读者自行查阅。

体系架构

第四章介绍了 Greenplum 的体系架构:

1.master节点主要存储元数据,负责执行计划的生成与查询接入2.segment节点即计算节点,负责存储实际数据的存储以及分布式执行计划的执行3.interconnect network,高速内联网络,主要用于集群间的通信与数据重分布

Image

其中着重介绍了 Interconnect 模块,在之前的案例中也有介绍 (👉🏻从一个案例聊聊DBA掌握网络的重要性),如果是传统的 TCP 方式的话,TCP 是一种点对点的有连接传输协议,一个有 N 个 QE 节点的 Motion 的连接数是 N^2,一个有 k 个 Motion 的查询将产生 k*N^2 个连接,很容易将资源耗尽,因此,Greenplum 在应用层实现了基于 UDP 的带有流量控制、乱序处理、重传等功能的 UDPIFC (with flow control),解决 OLAP 查询在大点的集群中连接数过多的问题。

下图是一个比较典型的图:Slice 和 Gang。

•Slice:为了提高查询执行并行度和效率,Greenplum 把一个完整的分布式执行计划分割成多个Slice,每个 Slice 负责查询计划的一部分。划分 Slice 的边界为 Motion,每遇到一个 Motion 则一刀将 Motion 切成发送方和接收方。同时,每个 Slice 都由一个 QE 进程进行处理•Gang:在不同 Segment 上执行同一个 Slice 的所有 QEs 进程称为 Gang,Gang 用来表示一组进程

Image

分布式事务

第五章中介绍了分布式事务的实现,其中特别提到了 ARIES,即 Algorithms for Recovery and Isolation Exploiting Semantics,设计⽇志系统来保证持久性和原⼦性;其⽇志分为两种 REDO 和 UNDO,但并不是每个数据库系统两个⽇志都有,当崩溃发⽣时,在重启的时候,恢复管理器就会开始⼯作,它会读取事务的状态,将已经提交的数据重新回放,将已经放弃或者中断的事务进⾏回滚,将数据库内不⼀致的数据恢复到⼀致的状态。

在恢复的时候,恢复管理器有⼀套算法逻辑在其中,决定如何进⾏回放,⼤名鼎鼎的 ARIES 就是这⽅⾯的⼀个算法。ARIES 的算法,是 IBM 提出的⼀整套关于⽇志记录和恢复处理的算法,后续的数据库管理系统都多少参考了该算法。

这取决于 BufferManager 的 Steal/Force 策略:

•Force:事务提交的时候,事务修改的数据页面被强制刷回存储;如果不满⾜,则需要 Redo Log;Whether the DBMS requires that all updates made by a txn are reflected on non-volatile storage before the txn is allowed to commit•No Steal:对于未提交的事务,缓存里面被修改的脏页不可以刷回存储;否则需要 Undo Log;Steal policy:Whether the DBMS allows an uncommitted txn to overwrite the most recent committed value of an object in non-volatile storage

Image

在 PostgreSQL 中,同样使用了 steal + no force,运行时效率高,即读写数据的效率高,但是数据恢复的效率低。以 WAL 为例,运行时写入 WAL 日志即可,而写 WAL 是 append 操作而不是随机写操作,速度会更快;但是恢复时需要重放 WAL 日志。推荐阅读下周刊(第16期):图解ARIES论文(下)[1]

Image

得益于 MVCC 实现方式,新老数据放在一起,所以对于 steal 方式,就无须 undo log,坏处自然是膨胀,需要垃圾清理了。

分布式计算

引用一下三水的原话:

MPP 就是把十亿对十亿的不可能的复杂度,按照关联数据,哈希分布到 100 个实例,每个实例按照1000 万跟 1000 万关联,复杂度直接下降几个数量级,把大的计算拆分成若干个小的,降低计算复杂度

说白了,就是人多力量大!这也是分布式数据库的优势,大家齐活一起上,但是切忌,分布式不是银弹。在这一章中,还提到了 ORCA 优化器,以及独特的算子 — ShareInputScan,关于这个算子,我还特意请教了一下做优化器的同事

一种算子,类似一个子查询,结果可以跨 slices 共享

其主要用于跨 Slice 共享数据,物化中间结果,然后通知消费者去读取中间结果文件。这个算子让我想起了 PostgreSQL 里面的类似机制,默认情况下,产生的临时文件会位于 base 的 pgsql_tmp 目录下,但是各位可能还会看到 SharedFileSets 目录,比如 pgsql_tmp.sharedfileset,顾名思义,因为 PostgreSQL 是多进程的,当并行执行的时候,需要通过 sharefileset 来共享数据,比如 parallel hash join。

 * SharedFileSets provide a temporary namespace (think directory) so that * files can be discovered by name, and a shared ownership semantics so that * shared files survive until the last user detaches. * * SharedFileSets can be used by backends when the temporary files need to be * opened/closed multiple times and the underlying files need to survive across * transactions.

文章后面还提到了本地事务和全局事务,和大多数分布式数据库类似,为了提高判断事务可见性的效率,避免每次都去访问全局事务提交日志,Greenplum 同样也引入了本地事务 — 分布式事务提交缓存,通过此缓存,可以快速查找到本地事务所对应的全局事务 distribXid 的信息,避免频繁访问共享内存和磁盘。

外部表存储

这一章节对于 gpfdist 花费了很大笔墨,gpfdist 的核心也是 MPP,每个 segment 各自向 gpfdist 服务端发出请求,服务端按照一定规则进行分发,然后并行地发给各个 segment 实例,最大化地发挥 MPP 的性能,避免单点瓶颈。以下是来自某大佬的原话,一直收藏着。

MPP 下输入导入一般不会直接 insert,每条数据都从 master 走,会占用资源,计算分布到哪个节点也是瓶颈。external table + gpfdist, copy on segments, gpload, gpkafka, gpss 等,背后都是 gpfdist 协议。gpfdist是 开源的,当然你可以写一个接入程序将数据源喂给 gpfidst,通过 insert select from external table 的方法。实际上 GPSS 就是基于此原理将 kafka/rabbitmq/file 等流式数据不断导入GPDB。

足以可见,gpfdist 的强大之处,并且作者还对 gpfdist 进行了增强,开发出了高并发的服务端程序 Lotus[2],使用 zstd 压缩算法对数据进行压缩后传输,速度突破了硬件网卡的极限速度,是裸数据在网卡上传输速度的 3 倍。更多细节各位可以参考三水的 Github,https://github.com/water32/gpfaq/blob/master/2020/gpfdist.md,[3]

Image

Image

HAWQ

后面介绍了一下 HAWQ,简单来说就是在 Hadoop 上运行 Greenplum,把底层存储从磁盘改为了 HDFS。Greenplum 存在一个比较严重的问题,也就是 double failure,HAWQ 的 segment 实例没有角色之分,无状态,HAWQ 的 segment 实例允许宕机,假设 100 个 segment,最后只剩一个,也不会出问题,不过凡事都有利有弊,HAWQ 牺牲了性能而获得了强一致性。

最后一章介绍了 NVM 和容器化、虚拟化相关,关于 NVM (非易失性存储),各位可以多阅读下宗帅的公众号。

后记

一本小而精的优质书籍,建议从事 PostgreSQL 或者 Greenplum 的读者,一定要买上一本,细细品味!

References

[1] 周刊(第16期):图解ARIES论文(下): https://www.codedump.info/post/20220521-weekly-16/
[2] Lotus: https://ginobiliwang.github.io/lotus-doc/
[3]: https://github.com/water32/gpfaq/blob/master/2020/gpfdist.md,