3 月 16 日在北京举行的腾讯云自研数据库 CynosDB 交流会圆满落下帷幕. 现将技术团队分享的内容整理如下.
我们先看一下整体的软件架构, 上面是 TXSQL; 左边是 Space manager, 负责空间分配映射; 底下是一个 DBStore 的模块, 负责处理 redo 和 page 相关逻辑; 再下面是 Atlas node, 这个大家可能不太熟悉, 它是腾讯云后端的存储平台, 现在支撑的服务有块存储, 数据库, 文件, 后面再做介绍.
接下来是介绍客户端的一些读写流程, 因为 page 的读写, 它跟 Redo 的处理逻辑比较相似, 这里只给出一个 Redo 的处理流程来做说明. 假设 TXSQL 发了一个 log 流(100~104), 到达客户端之后, 进行地址映射, 将空间映射到下面的 T1~T4(T1-T4 是指分布式存储的复制单元). 这样就能把一个 log 流引入到下面多个流, 分发到下面的分布式节点去处理. 日志流在存储节点返回成功后, 进行到右边的第三步. 假设那 100 和 103 先返回了, 这时候就会推进 VDL 到 100, 告诉 DB 说存储系统已经持久化到这个点了. 如果后续 101 返回了, 则可以直接推进到 103 的位置了. 普通的 page 读写操作流程, 处理方式和 redo 类似.
接下来看一下 DB recovery, 它的流程会变成什么样? 首先 TXStore-client 会获取表空间映射, 获得分布到存储空间哪些存储单元 (T1~T4) 相关信息. 然后向这些存储单元获取 lsn. 这里会有一些优化, 会根据一些持久化的点进行获取 lsn, 以此来减少返回的 lsn 量. 获取到 lsn 后进行排序, 如图所示 lsn 会推进到 103,recovery point 就到这里. 当然这个例子中忽略了一些因素, 为了简化流程说明, 没有考虑 mtr 相关因素. 实际处理中有可能 103 不是 mtr,recovery point 可能还需要向左边返回一些.
接下来介绍一下 DBStore 模块, 它负责所有 Redo 的相关逻辑处理以及 page 的读写操作. 首先是客户端发送 redo 到 DBStore,DBStore 对这个 log 进行一个简单的排序, 它要判断排序中的 log 和 persist queue 中的 log 是否连续. 如果连续, 则紧接着进行持久化, 并且把这些 log 向副本进行复制. 等到日志持久化和副本返回成功后, 整个 redo 流程处理就完成了. Redo log 在单个节点内一次写入就可以完成.
这里介绍下刚才提到 Atlas 分布式存储平台. 它对上支持的用户业务包括一些腾讯的业务和外部业务(比如拼多多, 摩拜之类的业务). 中间这一层是它支撑的云服务, 包括块服务, 文件服务, DB 服务等. 接下来是 Atlas 平台提供的功能罗列, 借助平台的能力可以快速构建 DB 上的能力, 比如说一些扩容, 流控, 快照等.
下面介绍一下 Atlas 的软件架构, 它是一个典型两层分布式存储架构. 先看客户端, 它支持丰富的接口和一些高级功能(比如快照, 卷迁移). 左边是控制节点, 负责分布式集群的状态控制, 包括节点故障恢复以及负债均衡等功能. 右下角是三副本跨交换机分布的存储节点, 它提供了高性能的存储引擎, 数据同步恢复功能, 强一致性复制协议, 故障容忍 F+1 等.
接下来看下数据路由方式. 在支持块存储的时候路由方式比较简单, 经过哈希函数得到一个虚拟节点, 之后通过右边的路由关系找到一个存储节点, 然后进行读写. 在 DB 里面发生一些变化, 如果也按照块存储的方式去 hash 路由的话, 这个拆分太散了, 会导致 redo 很分散, 达不到聚合的作用. 所以我们分配的时候会使用 MDS 分配的方式, 直接将 DB 的某一段空间直接映射到哈希上的某一段, 映射到分布式存储的一个复制单元.
接下来我们介绍一下 Atlas 系统的 IO 协议栈. 首先从 IO 路径上看是一个两层架构, 不需要中心节点介入, 一方面缩短路径提高了性能, 因为少了接入节点也降低了成本. 最上面的接入层, 支持丰富的协议, 比如 iscsi,file,db 等; 接下来是网络模块, 支持普通网络和 RoCE 网络; 再往下是复制模块, 支持并行高效复制; 接下来是存储引擎层, 基于 Append only 方式的元数据管理和基于裸盘的空间管理, 有效降低了写放大, 提高性能; 接下来是 cache 模块, 支持一些低成本方案. 比如可以通过配置一些较慢的介质做主存, 较快的介质来做 cache 来达到成本和性能的均衡. DB 场景下为了追求极致性能, 目前没有选择混存配置方式; layout 层这里不做介绍了; 接下来是磁盘管理模块, 负责 IO 提交, 会进行合并, 批提交等优化处理.
接下来介绍这个系统的高可用能力, Atlas 无法回避分布式节点里面故障节点, 在分布式系统中故障是常有的. 故障处理分为故障临时故障和永久故障. 上图是临时故障的过程, 假设左边 A 节点故障了, 当它再次恢复的时候它会向主节点 B 发起增量数据恢复; 下图是全量同步的过程, 当一个节点永久故障时候, 需要其它所有节点参与重建. 临时故障只需要同步少量的增量数据, 全量同步可以让系统很多的节点共同参与, 因此同步都是快速的, 系统能快速回归到稳态.
这里是一个高可用的补充, 通常分布式系统中会依赖一些心跳去探测节点的好坏. 但是假设遇到网络丢包或者慢盘等亚健康状态, 就不那么生效了. 我们是对 IO 进行随路探测, 更及时的发现这些故障, 上报到我们的 Master 节点进行仲裁把它隔离掉, 减少对业务的影响.
接下来介绍一下存储平台的特性. 比如快照, 基于这些快照, 我们可以快速实现 DB 的一些物理备份; 卷迁移, 因为云上有很多的仓储, 可能会涉及到迁移调度, 或者后续有一些性能体验更好的仓库, 通过在线迁移可以提升用户体验; 预读的能力, 这是一个分布式预读, 可能一些应用或者数据库本身也有预读的 cache, 但它的特点因为是单机的, 空间是很有限的. 在分布式系统中, 分布式节点有很多, 所以把读 cache 做到下面之后跟上面的 DB 服务, 块存储服务形成配合. 取数据还需要跨网络, 但是可以省去访存储介质的时间而且支持多点访问; 多介质支持, 支持一些存储介质的组合, 比如 SSD,HDD,SSD 和 HDD 混存; 还有支持流控, 共享磁盘等功能, 后续还有更多的功能在迭代开发中.
Q: 您好, 我提问两个问题, 你刚才说到我们在读写的时候, 底层有一个大的 cache
, 我的问题是比如某个节点堵了 cache, 你缓存的机制是什么? 能介绍一下吗? 比如通常说有大的计算或者需要大量的数据出报表, 或者出各种计算的时候, 可能需要大量的数据, 我们这个缓存的机制是什么?
A: 关于预读, 预读的逻辑更多的是靠前端的模块配合的. 预读请求发送之后也不需要应答, 告知存储层把数据准备好就可以了.
Q: 通常我们是这样, 比如他去分析数据, 哪些日志是常用的东西, 他可能会做一个缓存计划, 这样来了备份直接去用 IO 读, 我们一般会有这样的一个分析的逻辑. 所以说您说的还不太理解.
A: 也就是说比如 DB 的逻辑, 可能后面会用到哪几个块, 会提前读到 buffer pool 里面来, 但因为 buffer pool 还是有限的; 有了存储预读功能后, 不需要将数据读到 buffer pool, 只需要告诉存储, 等真正用的时候不用到介质上去读.
Q: 关键是怎么知道想读哪些?
A: 这个是要靠应用自己去逻辑分析, 比如块里面一些简单的顺序模型, 会很容易的推测出来后续可能要用这些块. MySQL 中本身也有一些预读逻辑, 可以将 MySQL 的预读逻辑和后端存储平台打通.
Q: 这一页 SSD 和 HDD 混合的存储, 你的数据如何分布的? 存储的策略, 这一块你们是怎么设计的? 还是说在规划中?
A: 不是规划中, 这个是 Atlas 平台的能力, 这个算法有很多的配置, 典型的是两级 LRU 的配置, 就是根据数据访问的频度, 然后决定数据是在 SSD 上还是淘汰到 HDD 上.
Q: 这个调度的算法是你在存储层做的?
A: 存储层做的.
Q: 这主要是根据存储层读页面的程度来访问它的吗?
A: 对, 统计它的冷热程度.
TXStore in CynosDB for MySQL CN - 樊伟. PDF
来源: https://www.qcloud.com/developer/article/1405284