暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

He3DB云原生数据库设计思考

原创 努力学习中 2023-11-02
240

我们知道He3DB是基于PostgreSQL开发的云原生数据库,那么它是如何实现的,相比PostgreSQL做了哪些改动?我们将思考云原生数据库He3DB的相关设计

云原生数据库的由来

最早的数据库都是部署在物理机上,比如PostgreSQL、MySQL。后来,随着云计算的发展,应用上云,有了在云上部署数据库的需要,诞生了云数据库。但是云数据库有其不足之处,为了解决云数据库的不足,云原生数据库Aurora诞生了,提出了Log is database的概念,采用存算分离共享存储的架构。

存算分离

云原生数据库须采用存算分离的架构,否则无法发挥其云计算相比物理机的最大优势——弹性。在存算分离的架构下,原有数据库刷页落盘持久化,WAL只作为Redo日志作为故障恢复使用,其中后台进程不断的刷页落盘将不再可行,因为存储节点与计算节点是分离的,不再是处在同一个单机实例中,刷页落盘需要通过网络进行,而网络是非常慢的,采用这种方式其相比单机PostgreSQL数据库,其还有性能劣势,明显,这种方案是不可行的,即计算节点与存储节点之间不能采用原有的刷页落盘持久化的方式。那怎么办呢?除了缓存中的页,WAL日志存储了数据库的所有修改,可将其发送到存储节点,存储节点不断的重放WAL日志,代替刷页,其相比页空间要小很多。

所以,相比PostgreSQL,He3DB计算节点要将WAL日志发送到存储节点,不再将WAL放到pg_wal本地盘中。

日志服务

PostgreSQL中高可用是通过主备方式实现的,即,主节点通过流复制将WAL日志发送到备节点,备节点重放WAL日志。而在He3DB中,高可用是通过存储节点集群实现的,即将WAL存储在分布式KV存储中,在分布式存储中,WAL会保存多副本,通过Raft协议保证副本一致性。这样即使1个存储节点挂了,也不会造成数据丢失。

所以,He3DB计算节点,需要将生成的WAL日志发送到Tikv中存储,将WAL元数据信息通过Wal sender进程发送到推进节点的wal receiver进程中,不在需要将完整WAL日志发送到只读节点。

当然,不同的云原生数据库,其设计是不同的,也有数据库自己写了一个日志服务,自己实现raft, 这里只分析He3DB的逻辑,其实,大的方向都是想通的。都可以参考Aurora的设计。

多版本页 + 数据一致性

多版本页的问题,不同于PostgreSQL,在PostgreSQL中,页要么在内存中,内存中的页一定是最新页,要么因为Buffer Pool满了被淘汰掉刷盘存储在磁盘中,此时磁盘中的页也一定是最新页,因为是内存中含有的最新的页刷盘刷下来的,肯定是最新的。而当需要更新某个页时,也是将页从磁盘读到Buffer中,在内存中更新页,将页标记为脏页,这时候,最新页在内存中,不存在多版本页的问题。而在He3DB中,则存在多版本页的问题,最直接的原因就是此时的最新页并不是通过从内存中刷盘刷下来的,因为计算节点仅仅将WAL日志发送给了推进节点,并没有将页发送到推进节点,推进节点是通过旧的一个版本的页加上WAL日志回放到最新页,而回放到那个位置是有限制的,因为只读节点的一致性的限制,往往推进节点不能推进到最新页,推进的位置(也就是推进到那个LSN)要满足不能超过当前只读节点的最新LSN,因为一旦超过了,那么只读节点从推进节点获取页+WAL日志的时候,就会得到“未来页”,引发不一致。可以认为页有很多版本,通过<Page+LSN>的方式,标识每个版本。

未来页的问题,直接原因就是推进节点的刷脏速度,大于备库的回放速度引起的,所以,主节点的推进节点要控制推进的速度,不能推进的太快,这里还会引发一个工程问题,要是回放的速度很慢,那么就可能会造成推进节点积累了大量的页以及WAL,可能会有内存无限膨胀的问题。具体的实现中,对应的数据结构是LogIndex,即,LogIndex内存不够用了怎么办?又不能随意扔了,唯一的办法就是内存不够时存储到磁盘中,释放部分内存,按需从磁盘读取到内存中,其思路于操作系统的swap机制是一样的。

故障恢复

故障恢复的不同,PostgreSQL故障恢复的逻辑是宕机重启后,从最近的一个检查点开始恢复,读取检查点之后的所有Redo日志并进行回放,出于性能的考虑,往往不会选择进行频繁的checkpoint,会通过配置,降低checkpoint触发的频率,也就是说,这个回放的过程可能会很长。而在He3DB中,计算节点不断地将WAL日志发送给推进节点,由推进节点进行回放日志,这个过程是不间断的一直在进行的,因为他不会影响到计算节点,所以,在进行故障恢复时,可以很快的进行,因为这个故障回放操作其实一直在进行。

WAL日志机制

he3db中的wal日志机制与pg是不同的,pg中的wal是存在日志文件中的,默认日志段大小为16M。 而在He3db中,日志是存储在tikv中的,并不是按照日志文件进行存储的,所以目前在he3db中并没有pg_wal目录下的日志文件,也没有日志段切换,所以wal_recycle=off。所以目前归档也是无效的,也就是说目前He3DB并没有实现完整日志归档功能。也不能说没有实现,有一个工具,可以将tikv中的日志归档到s3中,需要手动进行归档。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论