PolarDB for PostgreSQL架构介绍

分享人:北侠   阿⾥云PolarDB内核


正文:本文从四方面来介绍PolarDB for PostgreSQL的架构。

Ÿ 数据库架构对比

Ÿ . PolarDB 1.0 存储计算分离架构

Ÿ PolarDB 2.0 HTAP架构

Ÿ 参与PolarDB开源社区


一、数据库架构对比


PolarDB for PostgreSQL架构介绍

目前所有数据库可以分成三个架构:

Ÿ 左侧这张图是单机的数据库,也叫存储,存储计算是一体化的PG数据库,它的CPU、内存和磁盘都是在一台机器上的,也就是传统的数据库。

Ÿ 中间的架构是采用PolarDB的方案,基于共享存储的存储计算分离的数据库。我们将数据库的CPU内存放到一台机器上,把存储放到远端的共享存储池里,这样是多个节点共享一份存储,实际上它就是一个存储设备,也有可能在存储设备里又分成了多个副本,为了存储的高可用。存储计算分离的优势是:每个节点都能看到所有的数据,任何一个节点可以通过共享存储来得到所有的数据。在执行事务时,事务跨了多个分区,不像分布式数据库一个一个提交的算法过程,很容易完成在单机上事务的一致性,劣势是说扩展性不像分布式数据库那么好。

Ÿ 右图架构是开源的数据库,采用的方案是分布式的数据库,比如像典型的TIDB,整体的方案是将数据的表进行拆分,分布在不同的存储节点上,存储节点为了做高可用,就对每个表的分片做了多副本,可能会采用分布式的算法。优势是可以将整个集群做的非常大,比如可以做到1000个节点。劣势是在执行跨分区的事务时要做分布式事务的控制。


二、PolarDB 1.0存储计算分离架构


1)传统数据库痛点


PolarDB for PostgreSQL架构介绍

这是PolarDB的架构。阿里云在处理数据库时,它早期是托管传统的标准数据库。那么它有什么问题呢?上图左侧是master的节点配置,右侧是两个Standby节点,数据通过redo日志做复制。传统的数据库储备模式的架构的问题:

Ÿ 扩展性差,当用户在这套架构下做扩容时,比如希望将3个节点扩展到16个节点,16个节点做读写分离来提高堵的能力,这时需要将3份数据复制到16份数据,这个过程是非常漫长的。

Ÿ 可靠性差,由于为了保证性能,主备之间的复制是异步复制,不能保证数据不丢失。

Ÿ 可用性差,当主节点宕机的时候,要通过故障发现再做故障切换,从其他备节点里选出可服务的一个机器,这个过程是很漫长的。

Ÿ 成本高,将3个节点扩展到16个节点的时候,计算和存储量成本是线性增加的。在一个集群里面,为了预防业务的高峰期需要去预占资源。


2)PolarDB云原⽣架构 - 存储计算分离架构


PolarDB for PostgreSQL架构介绍

PolarDB的解决方案是存储计算一体化,在上图最左侧是传统的数据库,最右侧是PolarDB一个整体的架构,底层是共享存储。上面的计算节点,计算节点里面只有CPU和内存,没有本地存储,它的存储是通过RDMI高速网络和后端的存储池做交互,整体上数据只存在于远端的共享存储里,计算节点和存储节点之间是通过用户态的文件系统和后端的存储做交互,在这个过程中用的就是DirectIO。那这样做的话有什么好处呢?

Ÿ 弹性好,当存储计算分离的时候,业务的数据量会变得非常大,将存储池里面拖几个磁盘过来就可以了,在整个过程中3个计算节点是不需要动的,用户的业务是无感知的。如果业务高峰期来了,我的数据量没有变多,但是我的计算量的要求变高了,这时可以将3个节点迅速扩展到16个节点,只需要找到16台机器,把共享存储的路径挂载上去就可以了,这个过程理论上来说是分钟级别的,可以迅速的从3个节点扩展到16个节点。同理,当发现业务高峰期不需要这么多机器的时候,就将16个节点迅速的缩容到3个节点。

Ÿ 成本低,底层的存储是有一份,不管扩展到多个计算节点,存储是不需要再扩容的,整个存储的成本就降低了。

Ÿ 易用性,PolarDB在前端有一个透明代理,它可以做透明的读写分离。在事物里它的写可以路由到它的主节点,事物后续的堵的可以路由到其它的只读节点,可以做一个整体的负载均衡。由于每个节点能看到所有的数据,对于用户来说,相当于是在使用一个单机的数据库,但实际上架构是一个分布式的架构,底层存储是一个分布式的存储方案,单机数据库大家比较熟悉,使用起来用户体验也是比较好的。它是一个单机体验,我们可以做到对社区的100%的一个兼容。

Ÿ 可靠性。底层的共享存储池是PolarDB自研的分布式的共享存储,我们改进成三副本的复制算法。在存储上又做了秒级快照,如果对业务做快照的话,快照的时间是非常短的,底层使用了引用技术。

架构遇到的挑战:一致性的问题。这个架构是1份存储加N份计算,其它的三个架构挑战也可以说是架构的优深度优化,比如像低延时的复制以及快速的恢复和DirectIO的一些优化。


3)PolarDB云原⽣架构 - 存储计算分离原理

PolarDB for PostgreSQL架构介绍

这张图是PolarDB在整个数据库的模块站里面做的事情,从上往下看,

Ÿ 第一层就是最上层也就是事务层,事务层支持了CSN快照,因为原生的数据库在做事物隔离的时候要去拿一个快照,这个快照要到一个大的数组里面去拿快照,拿快照的过程是很漫长的,它需要一个枷锁,这个临界区域是很庞大的,我们就借助社区的CSN快照,只需要做一些整数的原子操作就可以了。

Ÿ 第二层就是日志层,在日志层做了日志的复制优化和 layz的回放,并行回放和Log Index,在缓存层优化的是常驻的buffer pool,把DirectIO实现后,就不需要把内存给buffer了,那内存都可以作为buffer来用了, buffer会变得非常大。

Ÿ buffer大了的好处是缓存命中率会变高,风险点是之前所在buffer里面的所积累的一些页面也就消失。我们进程、主进程和buffer是解耦的,主进程宕机了buffer pool还在。

Ÿ 存储层的话,我们做了DirectIO、数据预读、预扩展和PolarVFS。数据文件系统的抽象不仅能对接到PolarDB的分布式文件系统,还可以对接到其它的自己实现的文件系统。


4)PolarDB存储计算分离架构 - 数据⼀致性

PolarDB for PostgreSQL架构介绍

PolarDB的挑战是数据一致性的问题。见上图下方就是共享存储,共享存储里面有Data,Data里面配置的是200的页面,另一部分是redo日志也叫WAL日志。WAL日志里面有两条WAL日志100和500,往上面左上角看的话,是Master节点,内存页面是200,经过事物的运转后,产生了两条redo日志,日志是100和500,要将这两条日志落盘到共享存储上面。右上角是Replica节点,要做日志的回放,在共享存储下的好处是什么呢?我们发现redo日志不需要通过流复制发送过去,因为redo日志已经存在于共享存储上了。

Replica节点理论上是可以直接从共享存储上读到这个redo日志的,我们就不需要做真正的复制了, WAL Meta信息就是直接告诉redo日志在共享存储的位置就。这个信息可能就几个字节,真正复制是不需要的。这个架构不用复制redo日志的内容,只需要复制redo日志的原信息。


5)PolarDB存储计算分离架构 - 数据⼀致性问题1 - “过去⻚⾯

PolarDB for PostgreSQL架构介绍

第一个问题是过去页面。它的产生是因为备库在内存中回放得到的新页面被丢弃。在这个图里RW节点有页面P1,加上它的日志200,就得到一个新内容叫日志页面,P1内容变成了600,也就在T1时刻所发生的事情,T1时刻在这个整个虚线的左侧主节点里面是500加日志200得到了内容600。在另外的节点上面,其它节点上的数据的内容是比较老旧的,因为它的日志没有复制过去。这个时候它的内容只有页面内容P1是500。横向看的话,T2时刻主节点将日志200发送给RO节点,也只能知道发送日志200是的位置,没有真的去发送。T3时刻在RO节点,页面500加上日志200,也得到一个最新的页面内容是600,日志200也是从共享存储上直接读的,得到页面的内容是600。T4时刻下一时刻P1的内存满了不够用了,他要将600给淘汰掉,淘汰掉之后内存里面就没有了,这时候T5时刻再次去发现又读到了一个P1页面,这个时候因为内存没有了,需要从共享存储上读。共享存储内容是老旧的500,就是因为主库没有将页面600刷新,这时就读到过去页面了。


6)PolarDB存储计算分离架构 - 数据⼀致性问题1 - “过去⻚⾯” 的解法

PolarDB for PostgreSQL架构介绍

这个解决方案是按需回馈的,在每个节点上去记录每个页面应该回报到的地方。比如页面P1上面有日志200,400和800三条日志,将事件记录下来,其它节点需要回放的时候它就知道要读日志,需要用老旧的页面500加上日志200,就得到它所需要的页面。


7)PolarDB存储计算分离架构 -“过去⻚⾯” 的解法 - LogIndex数据结构

PolarDB for PostgreSQL架构介绍

过去页面需要维护这个因素关系,对内存放不下的问题,我们研发了Logo Index的数据结构,专门用来记录每个页面上发生的事件,这是一致性问题。


8)PolarDB存储计算分离架构 - 数据⼀致性问题2 - “未来⻚⾯”

PolarDB for PostgreSQL架构介绍

PolarDB for PostgreSQL架构介绍


今天就不详细讲解未来页面了。


三、PolarDB2.0 HTAP架构


1)PolarDB2.0云原⽣架构 - HTAP架构

PolarDB for PostgreSQL架构介绍

前面讲了PolarDB1.0,是在做存储计算分离时要做的事情。PolarDB2.0就是HTAP的一个架构,存储计算分离后通过读写分离将高并发的事物打散到不同的节点上。它没办法去解决什么问题呢?比如你去电信营业厅办业务,白天处理TB型的业务,像去营业厅办卡或者去办宽带,这时你对于电信就是TB型业务。因为你操作的是自己的账号,给自己账号里面充500块钱。对于后端的数据库来说,你只是操作自己的数据,它按照user ID做了一个索引,就可以快速定位到数据的位置,这是 TB型的业务,也叫做点查和点写,PolarDB1.0是解决这种问题的。这种业务晚上要对账,比如一个杭州市,我要去看每一个营业点的营收。这种查询实际上不是点查点写,不涉及去查某个用户发生的事情,只需要知道整个营业厅下午发生的事情,这是IP的一个应用。在存储、计算分离的架构下,这条SQL不管发给哪条节点,都可以快速的扩容到很多节点。

PolarDB for PostgreSQL架构介绍

如果SQL落到一个节点上,这个节点的硬件资源又是有限的,在TP下面又有一部分IP的需求,那么就叫做TIP,实现了一套基于共享存储的MPP方案。有人就会知道解决方案是将SQL进行优化,经过分布式优化器将SQL产生计划数,拆分成很多个指数,指数分发到不同的计算节点上,这些计算节点做计算,将 结果进行汇总,汇总后再次打散再次汇总那么,这是MPP原理。不同的节点看到的数据是一样的,比如节点一发现表一有1万条数据,由于节点二底层的共享存储也能看到1万条数据,我们将SQL进行拆分,分发给不同的节点去做计算,每个节点都能看到1万条数据,这样的话得到的结果重复了是不对的。

扫描的数据量是原来的那种单机数据量,没有起到加速的效果,MPP共享存储要解决问题是说如何将表进行拆分,比如用户表有1万条数据,希望两个节点做加速,节点一扫5000条数据节点,节点二扫另外5000条数据,节点一和节点二扫的结果再做一个合并,那么得到1万条数据。我发动了两个节点,每个节点只处理1/2的数据,整体的资源和运行效率都提升了。我们做到了共享存储的MPP,有四大好处:

Ÿ 第一个好处是提升 ScaleOut的能力,就是横向扩展的能力。用户需要IP的分析需求时,可以增加节点,选择一部分节点来跑分析型查询,另外一部分节点来跑TP型,也就是点查点写的这种查询。

Ÿ 第二个好处是一体化的解决方案,可以对应到像TIDB,会发现TIDB是的事务型的集群,跟IP型的的集群是分开的。PolarDB的数据底层还是原来的那套数据,只是在内核里面做了两套计算引擎,一个是点查点写,另一个是分布式型的。

Ÿ 第三个好处是Serverless,可以SQL级别的弹性的扩展。存储计算分离之后,比如某个业务的第一条SQL跑在节点一和节点二上,那么第三条SQL可以跑在节点五和金的六上都可以做到。

Ÿ 第四个好处是可以做到TP和AP在物理上是隔离互相不干扰的。


2)PolarDB云原⽣架构 - HTAP架构 - 基于共享存储的MPP

PolarDB for PostgreSQL架构介绍

左侧这个图是个比较有意思的示例,了解oracle就会发现,它可以让某个业务跑在节点一、节点二上,另外一个业务跑在节点三和节点四上。如何做到Serverless这种无状态化呢?那么如果说我们对齐到像社区的方案,就是他在做MPP的时候会将它的所有的信息放到共享存储上,其它的worker是没有状态的,它的状态来自共享存储,它是无状态就可以迅速做扩容。基于共享存储的MPP,把数据清洗的问题给彻底解决了,即使选择很好的分布策略,在业务运行的时候,后续也会造成数据清洗。

即使没有数据清洗,也可能有计算清洗。比如我查询关注某些特征的用户,那这些特征的用户可能集中落到某两台或者某几台机器上,一条SQL下去之后,只有这几台计算节点在做SQL的执行,其他节点实际上是空闲的,整体的资源利用率是比较低的,那么我们怎么样去做这个数据清洗呢?利用了共享存储的特性叫能者多劳,在做数据扫描时,将整个任务切分成了多个小段,就是task切分成了多个小task,每个节点先处理自己的task,先去扫描4M的数据再去做处理,这个处理就走火山模型,处理完4M的时候再处理下一个4M。因为共享存储的数据是共享的。当某些节点处理的比较慢,其它的节点处理比较快的时候,那处理快的节点可以消费更多的数据,整个的计算过程会把慢节点给补偿回来。


四、PolarDB开源社区


PolarDB for PostgreSQL架构介绍

大家可以搜到PolarDB的主页,项目主页里面有整个的架构的详细介绍,有中文版和英文版,我们工程师花了很长时间来编写的,设计的要点都写在了这里面,也欢迎大家去做开源的贡献,流程是先要去folk主仓库,把代码克隆到自己的本地,比如说你们可以去帮忙去从一些简单的事情做起,可以去下载的设计文档,可能里面中文和英文是不对齐的,可以把一些小问题给挑出来,走一下这个流程。

上一篇:Non-FPW开发实战


下一篇:Android Fragment生命周期——多屏幕支持