写点什么

一文读懂 GaussDB(for Mongo) 的计算存储分离架构

  • 2020-08-17
  • 本文字数:2722 字

    阅读完需:约 9 分钟

一文读懂GaussDB(for Mongo)的计算存储分离架构

1.摘要

GaussDB(for Mongo)是华为云自主研发兼容 MongoDB4.0 接口的文档数据库。基于共享存储的存算分离架构,对于传统 MongoDB 社区版有如下优势:


  • 秒级添加 Secondary 节点(相比社区版 Mongo 小时级添加 Secondary 节点)

  • 基于 WAL 复制, Secondary 节点无写 IO,从根本上解决社区版 Seconary 节点 Oplog 脱节问题

  • Primary/Seconary 无任何 IO 交互,Secondary 节点个数理论无上限, 支持百万 OPS 的读事务能力

  • LSMTree Compaction 计算/IO 卸载到 Compaction 统一调度池,集中管理,不浪费用户读写 IO

  • 基于共享存储,Chunk 分裂/迁移动作不引起真实 IO,只更新路由元数据,秒级分裂/均衡

2.GaussDB(for Mongo)技术架构

1)容忍更多 Shard 宕机


与社区版 MongoDB 的Share-Nothing模式不同的是,GaussDB(for Mongo)采用Share-Storage架构,计算存储分离。集群模式下,N 个 Shard 节点,可以容忍 N-1 个 Shard 宕机。



某个 Shard 节点宕机后,其负责的数据由于存在于共享的存储池中,因此不需要物理拷贝数据,只需要修改元数据路由信息,即可被其他分片节点接管。


2)更快的分裂与均衡能力


此外,由于 Chunk 数据在存储池中,Chunk 的分裂与均衡不涉及到数据拷贝,可以做到分钟级分裂与扩容,分裂与扩容对用户的影响也远比社区版 MongoDB 小。



3)百万级读 OPS 能力


GaussDB(for Mongo)副本集模式下,Primary/Secondary 节点之间共享同一份数据库文件。Secondary 节点只复制 Primary 节点的 WriteAheadLog 以及 LSMTree 的结构变更信息,并应用到内存中。Secondary 节点没有 LSMTree 的 Compaction 和 Flush 任务,因此对用户的读业务影响很小。



此外,由于Share-Storage的架构优势,添加 Secondary 节点并不需要拷贝数据,添加 Secondary 节点的动作可以秒级完成。而 Primary/Secondary 之间只传递元数据变更,不传递 WriteAheadLog,因此 Secondary 节点的个数即使变多,也不影响 Primary 节点的写性能。Secondary 节点可以水平扩展,支撑百万级的读 OPS。


4)主节点 IO 卸载


LSMTree 的写压力来源于三部分:


  • 用户的业务写入导致的 Memtable Flush

  • 后台 SST 文件 Compaction

  • WAL 的持续写入


根据线上业务的实际测算,三者的 IO 资源消耗占比为: 1:10:1。后台的 SST 文件 Compaction 占了绝大部分 IO 带宽,通过将 Compaction 任务集中化管理,从计算池卸载到存储池,进一步减少了用户计算节点的 CPU 和 IO 资源消耗。



5)GaussDB(for Mongo) 只读节点设计


  • 传统社区版 MongoDB 副本集基于 Oplog 做数据复制,只读节点需要镜像主节点的所有写 IO 操作。GaussDB(for Mongo) 的只读节点和主节点共享同一份底层数据库文件(LSMTree 的 SST 文件),只读节点并不自己生成 SST 文件。

  • 随着业务数据的写入,Compaction 的不断执行,LSMTree 的当前版本(包含哪些 SST 文件)不断更新,LSMTree 的元数据更新(增删 SST 文件的记录)被同步到只读节点执行。

  • RocksDB 中,数据的变更被持久化到 WAL 里,元数据的变更(增删文件的操作, 叫做 VersionEdit)被持久化到 Mainifest 里。RocksDB 的数据和元数据是分开的,WAL 流和 VersionEdit 流是并行的,没有严格的先后顺序。为了保证只读节点和主节点完全一致的事件回放顺序,WAL 和 VersionEdit 流必须要合并成一个流,在双流合并后,通过 LSN 就可以为每个事件(WAL 的写操作/VersionEdit)定序。



  • 基于 WAL+VersionEdit 复制,而不基于 Oplog 复制

  • 共享文件(sst/wal)的生命周期管理由主节点负责 sst 文件和 wal 的文件的生命周期由主节点负责。RocksDB 中,SST 文件通过层级的引用计数来维持不被删除。如下图,RocksDB 的每个游标会维持 SuperVersion,如下图中的 S0,S1,S2。每个 SuperVersion 会引用一个 Version,一个 Version 代表 LSMTree 在不断变形(通过增删 SST 文件变形)的过程中,某个时间点的形状,最新的 Version 就代表 LSMTree 当前的形状。



  • 在 GaussDB(for Mongo)中,主节点会记录所有只读节点在使用的 Version,并为这些 Version 增加引用计数从而维持 SST 文件的生命周期。对于 WAL,主节点会记录所有只读节点中最老的 LSN(oldestLsn),最老的 LSN 来自于复制最慢的只读节点。并删除比 oldestLsn 还旧的 WAL 文件。

  • 元数据变更通知,无论是 oldestLsn 还是只读节点的当前在用的活跃的 Version,都需要及时推进,这些元数据的变更是通过主从节点的定期心跳上报到主节点上的。主节点利用心跳数据对垃圾版本与 WAL 做清理。如下图所示,在经历一次心跳后,主节点发现 Secondary0 的 Version0 和 Secondary1 的 Version0 不再使用。删除这两个 Version 后,SST0 的引用计数为 0,表示 SST0 可以被删除。OldestLsn 也从 100 推进到了 250,可以清理掉 250 之前的 WAL。



  • 只读节点的 memtable 的释放:主节点的 Memtable 不会实时 Flush 为 SST 文件。如果只读节点不处理主节点的 Memtable 的话,只读节点的数据就不是实时的,且存在数据一致性问题。只读节点通过回放 WAL 到内存的 Memtable 中,来覆盖 SST 文件与主节点的 Memtable 的 Gap。上文介绍了只读节点是不往共享存储写入数据的, 所以只读节点上的 Memtable 最后的结局一定是被丢弃掉。但什么时候丢弃这个 Memtable 就是一个问题。过早的丢弃,会造成 SST 文件与 Memtable 之间的数据不连续,存在 Gap,过晚的丢弃会造成内存的浪费。只有当只读节点识别到 SST 的数据已经完全能够 Cover 某个 Memtable 时,这个 Memtable 才可以被丢弃。

  • GaussDB(for Mongo)的只读节点在每次应用 VersionEdit 后,检查所有 SST 中的最大的 LSN 与 Memtable 的最小的 LSN 的关系,来决定是否要丢弃某个 Memtable。

  • 内存元数据的反向更新:传统的复制,数据流从 Oplog 来,走一遍完整的数据库 Server 层 CRUD 接口,再落到引擎层。这种逻辑和主节点上业务的写入逻辑是一致的,因此 Server 层的一些内存元数据结构,在这个过程中就自然而然的得到更新了。但是当采用基于 WAL 的复制后,整个 WritePath 并不经过只读节点的 Server 层。因此 Server 层的内存元数据更新,就是一个很大的挑战。在这里,只读节点对每一条 WAL 做分析,如果 WAL 的内容会影响 Mongo 内存元数据,就会 reload 对应的元数据模块。


3. 总结

GaussDB(for Mongo) 基于 Share-Storage 架构,实现秒级 Chunk 分裂与均衡,对业务影响更小,水平扩展速度更快,能容忍更多节点宕机。只读节点功能,实现了一份数据多计算节点共用的功能。极大的提升了存储的利用效率,提高了计算节点的读取数据能力。为了让副本节点具有持续的读扩展能力,整个只读方案采用元数据的同步模式,在不降低主节点负载的情况下,极大的提升了整个系统的读数据的处理能力。为 3 节点,5 节点,乃至于 15 节点以上的副本集的工作提供了可能。


2020-08-17 10:142426

评论 2 条评论

发布
用户头像
rocksdb 的WAL应该是逻辑日志,不像mysql 的redo log这种物理日志,就无法做到在存储节点层直接进行recovery 吧
2021-02-01 17:21
回复
用户头像
但是在图3里有4条从计算节点到存储节点的path,oplog, wal, data都下沉? 这还是 log is database 吗?

基于 WAL+VersionEdit 复制,而不基于 Oplog 复制

2021-02-01 17:18
回复
没有更多了
发现更多内容

聊聊销售背后的策略

吴晨曦

创业 销售管理

现在Php、Java、Python横行霸道的市场,C++程序员们都在干什么呢?

ShenDu_Linux

c++ 程序员 编程语言 C语言 软件工程师

根治可扩展、高可用、高性能“神器”:SpringCloud+Nginx高并发编程手册

Java架构追梦

Java nginx 架构 面试 微服务

Spock单元测试框架实战指南四 - 异常测试

Java老k

单元测试 spock

《华为数据之道》读书笔记:第 6 章 面向“自助消费”的数据服务建设

方志

数据中台 数据仓库 数字化转型 数据治理

阿里内部“高并发通关秘籍”曝光,看完带给你独一无二的认知!

比伯

Java 编程 架构 面试 计算机

使用 Go 实现 Async/Await 模式

Roc

channel goroutines Async Go 语言

5分钟学会6个阿里内部编程的方法

Java架构师迁哥

三万字无坑搭建基于Docker+K8S+GitLab/SVN+Jenkins+Harbor持续集成交付环境!!

冰河

Docker 云原生 k8s

区块链开发落地,联盟链系统平台搭建

t13823115967

区块链 区块链开发落地 联盟链系统平台搭建

Spring 源码学习 02:关于 Spring IoC 和 Bean 的概念

程序员小航

spring 源码 源码分析 ioc

今年最火的 Golang 云原生开源项目,可能就是它了!

孙健波

Kubernetes k8s OAM KubeVela CloudNative

我是如何使计算提速>150倍的

白日梦想家

Python 代码优化 Numpy

磁盘到底是怎样工作的?一文理解硬盘结构

Guanngxu

操作系统

JVM调优不知道怎么回答,阿里总结四大模块,学不会就背过来

小Q

Java 学习 架构 面试 JVM

监控之美——监控系统选型分析及误区探讨

华章IT

运维 云原生 监控 Prometheus

Nginx的反向代理与负载均衡--配置Nginx

Linux服务器开发

nginx 负载均衡 反向代理 后端 Linux服务器

甲方日常 59

句子

工作 随笔杂谈 日常

《华为数据之道》读书笔记:第 7章 打造“数字孪生”的数据全量感知能力

方志

数据中台 数字化转型

微博和B站屏蔽马保国相关信息:自媒体蹭热度要适可而止

石头IT视角

一枚程序猿的MacBook M1详细体验报告

Zhendong

架构师训练营第 1 期 - 第 10 周 - 学习总结

wgl

极客大学架构师训练营

CPU飙高问题排查

程序猿玄微子

【薪火计划】06 - 你推崇的领导方式是怎么样的?

码字与律动

管理

二分发代码模板

小兵

前嗅教你大数据:常见几种编码介绍

前嗅大数据

大数据 编码 编码指南

苹果开始告别英特尔

罗燕珊

macOS Big Sur 芯片 苹果 MacBook 英特尔

免费下载O’Reilly出版社全新之作《建立机器学习流水线》

计算机与AI

学习

面试无忧:源码+实践,讲到MySQL调优的底层算法实现

小Q

Java 数据库 学习 面试 算法

区块链政务系统开发解决方案

t13823115967

区块链+ 区块链开发落地 政务系统开发解决方案

《华为数据之道》读书笔记:第 8 章 打造“清洁数据”的质量综合管理能力

方志

数字化转型 数据质量管理

一文读懂GaussDB(for Mongo)的计算存储分离架构_数据库_华为云与计算_InfoQ精选文章