乐趣区

CynosDB技术详解——存储集群管理

本文由腾讯云数据库发表
前言
CynosDB 是架构在 CynosFS 之上的分布式关系数据库系统,为最大化利用存储资源,平衡资源之间的竞争,检查资源使用情况,需要一套高效稳定的分布式集群管理系统(SCM: Storage Cluster Manager),SCM 使用 Etcd 作为存储,利用 Etcd Raft 算法完成 SCM Leader 的选举,对外提供 HTTP API 查询 CynosFS 状态,负责 CynosFS 调度,其包含两类调度:
lPool 调度:对 SCM 中所有 Pool 进行调度,每个 Pool 的调度将根据其状态,产生相关调度操作,包括 Pool 的初始化,Pool 自动扩缩容,以及 Pool 的销毁等。
lSegment Group 调度:每个 Pool 内有一个 SG 调度器,负责该 Pool 内所有 SG 的调度,根据每个 SG 的状态,产生相关的调度操作,包括增减副本,Leader 切换,副本迁移,副本离线等。

相关组件和名词解释如下:
lDBEngine:数据库引擎,支持一主多从。
lDB Cluster Manager(DCM):数据库集群管理,其负责一主多从 DB 集群的 HA 管理。
lStorage Service 或 Storage Node(SN):Storage Service 是个逻辑概念,泛指实际提供服务的 Storage Node。SN 则是 1 个具体的服务进程,负责日志的处理、BLOCK 数据的异步回放、读请求的多版本支持等,同时还负责将 WALLOG 备份到 Cold Backup Storage。
lSegment(Seg):Storage Service 管理数据块 BLOCK 和日志的最小单元(大小为 10GB),也是数据复制的实体。通过一致性协议(Raft)进行同步,形成 Segment Group(SG)。
lPool:多个 SG 从逻辑上构成一个连续的存储数据 BLOCK 的块设备,供上层的 Distributed File System 分配使用。Pool 和 Seg Group 是一对多的关系。
lStorage Cluster Manager(SCM):负责管理 Storage Service,维护 Pool 和 SG 的对应关系,以及 Segment Group 内部成员的调度。
数据模型
SCM 数据模型包含 4 类信息:API 信息,系统信息,调度信息,存储服务信息
lAPI 信息(API Info):SCM 对外提供服务的接口,包括 SCM 自身运行情况,Pool 信息,以及 Storage Service 信息等,提供 RESTFul 风格的接口(管理类接口)和 GRPC 接口(数据交互类)。
l 系统信息(System Info):SCM 自身运行的全局配置信息,以及多个 SCM 主从 Member 信息,此外还包括外部系统访问的地址 ClientUrls 和 Member 之间的访问地址 PeerUrls 等信息。
l 调度信息(Schedule Info):SCM 内部调度的作业信息和状态信息,包括 Pool 和 SG 的调度信息,以及相关调度产生的任务,这些任务将会通过心跳下发给 Storage Service。
l 存储服务(Store Info):SCM 保存的 Storage Service 信息、调度的状态信息、Storage Service 上报的统计信息以及内部作业定期计算产生的统计信息等,主要包括 Pool 信息,Storage Service 元数据及 Storage Service 运行时统计信息,以及 SG 相关信息。

I/ O 模型
SCM Master 主要与如下模块进行交互:
lStorage Service:进行资源调度,接收心跳,下发命令等交互
lDistributed File System:为其提供对应 Pool 和 pool 下所属 SG 的信息,以帮助其完成读写请求的正确路由
lDCM:为其提供包括创建 Pool,查看 Pool 信息,以及 SG 调度情况等接口。
lSCM Slave:通过 Etcd 同步 SCM 的数据,包括调度信息和资源信息等,维护高可用性的心跳信息。

对上图的详细说明:
1.SN 注册到 SCM,SN 的物理布局信息通过标签组 labels(每个标签 label 采用 key-value 键值对表示) 进行定义,标签名依次是 Region->Zone->Rack->Host,标签值是具体部署的物理信息,如北京 -> 北京一区 ->rack_01->host_01。一个 SN 负责处理一个 SSD 设备上的数据读写。
2.DCM 开始创建 Pool,SCM 接收到创建操作后,保存该 Pool 的元数据信息到 Etcd 上,然后把该 Pool 加入到内部调度队列。
3.Pool 调度器:定期从调度队列上获取各个 Pool 来调度,调度包括 Pool 的初始化 (分配第一个 SG),根据 Pool 状态及使用情况进行扩缩容,以及 Pool 的销毁。
4.SG 调度器:每个 Pool 下对应一个 SG 调度器,负责该 Pool 内所有 SG 的调度,包括 SG 的初始化,增减副本,SG 内 leader 切换,迁移等,通过装箱算法选择最佳 Storage Node 作为该 SG 的成员以及整个存储资源的调度。
5.Distributed File System 会定期同步 SG 的使用情况,Pool 信息到 SCM,并从 SCM 获取该 Pool 的所有 SG 信息以及 SG 的变更情况(如 SG 内 leader 切换)。
调度原理
通过 SCM 发送心跳信息来驱动的,包括 Store Node(SN)心跳和 Segment Group(SG)心跳,心跳消息采用 Protobuf V3 定义,GRPC 进行交互,由 SN 发起,SCM 负责接收,接收到心跳信息后,将根据 SN 运行情况产生相关的调度命令,并通过心跳响应信息下发给 SN,SN 接收命令,并执行命令,然后更新相应的状态信息,通过下一次心跳发送给 SCM。
Pool 调度
Pool 调度将对 SCM 所有 Pool 进行调度,每隔 5 秒轮询一次所有的 Pool,检查是否有新的 Pool 加入,检测每个 Pool 的状态,根据 Pool 状态进行调度,如初始化,扩缩容和销毁等。

Pool 状态包括:UNINITIALIZE,NORMAL,DISABLE,DELETE, 其调度状态包括:INITIATING,EXPANDING,EXPANDED,IDLE。Pool 调度状态变更如下:

扩容过程如下:
1. 当前 Pool 存在 SG0,新增 SG1 并对 SG1 进行初始化。
2. 当 Pool 调度器检查到 Pool 需扩容时,更新其状态为 EXPANDING,并持久化该 Pool 信息,然后添加一个 SG 的元数据到 Pool 的 SG 内部调度队列中,并持久化到 Etcd 中,SG 的 ID 从 0 开始编号,依次递增,保持连续性,避免产生空洞,采用一次扩展一个 SG 的方式,完成后更新其状态为 EXPANDED。
3. 该 Pool 的 SG 调度器进行调度,检测到有新 SG,对该 SG 进行初始化,补充副本。
4. 当 Pool 调度器检查到该 Pool 的状态为 EXPANDED,判断该新的 SG 是否创建完成(补充完所有副本),如创建完成则更新 Pool 的调度状态为 IDLE,否则忽略本次调度。

调度状态需进行持久化,当 SCM 发生主从切换时,能恢复到崩溃时的调度状态。
Pool 缩容是扩容的逆过程,从 id 最大的 SG 开始往 0 方向收缩,以免产生空洞,具体的操作由 SG 调度器执行每个 SG 回收。
Pool 释放是对该 Pool 的所有 SG 进行释放,回收将从从 id 最大的 SG 开始回收,回收过程将通过心跳信息下发指令给 SN,具体的操作由 SG 调度器执行每个 SG 的回收。
SG 调度
CynosDB 每个 Pool 都对应一个 SG 调度器,每个调度器按 1 秒轮询一次该 Pool 内的所有 SG,每个 Segment Group 之间是相互隔离的,其调度不受影响,调度主要通过 SN 的心跳和 SG 心跳完成的,调度包括 segment 的添加,删除,切主等。

SG 状态包括:UNINITIALIZE,NORMAL,DISABLE。
Segment 调度状态包括:UNINITIALIZE,INITIATING,ALLOCATING,ALLOCATED,BOOTSTRAPPING,ADDING,ADDED,REMOVING,RELEASING,调度状态如下:

SN 心跳:SCM 接收 store 的统计信息,然后下发 Segment 操作(分配和销毁 Segment)和 SG 操作(启动和销毁 Segment Group)给 Store,然后 Store 执行操作,而 Store 操作的结果通过 GRPC API 汇报给元数据。如分配一个 Segment 给某个 Pool 的 SG 过程:
1. 保存 Segment 的元数据信息到 KV 系统中。
2. 接收到 Store 的心跳信息。
3. 下发分配 Segment 信息。
4. 接收到分配 Segment 信息,进行本地操作,操作完成后直接通过 grpc 汇报分配结果给元数据。

SG 心跳:SCM 获取 SG 的心跳信息,更新 SG 的元数据信息,然后根据 SG 的状态,产生相应操作(如添加,删除副本)或空操作,通过心跳的响应信息反馈给 SN,如有下发操作,SCM 通过下一次心跳信息来检查本次操作是否成功,如往某个 SG 中添加一个副本的过程:
1.SCM 接收到 SG 上报的心跳信息,更新该 SG 的信息到 KV 系统。
2.SCM 通过响应下发添加 Segment 请求给 SG。
3.SG 接收到请求后,向该 SG 加入新的 Segment,添加后,更新 SG 信息,下一次心跳周期发送更新后的 SG 信息.
4.SCM 接收到 SG 的心跳信息,检查添加 Segment 操作是否成功。

装箱算法
假设 SCM 中存在 Region1, 该 Region1 存在 Zone1,Zone2 两个区域,Zone1 有三个机架 Rack1,Rack2,Rack3, 存在三个主机 Host1,Host2,Host3, 每个主机有 4 个 SN,每个 SN 保存已分配的 Segment,选择一个 Store 作为 SG 副本分四个步骤:筛选,过滤,打分,比较。

1. 筛选:根据 Pool 注册的标签信息 (为一组 Key-Value 数组),如 [{REGION:Region1},{ZONE:Zone1}],选择出可用的 PoolStores1 集合,如{S1,S2,S3,S4,S5…,S12}。

2. 过滤:从 PoolStores1 集合中过滤不符合规则的 store 信息,如根据其状态(在线,离线),工作负载(空闲,忙碌),使用率(CPU,内存,磁盘,网络等),以及该 Store 已在该 SG 中等进行过滤,得到 PoolStores2 集合{S1,S2,S4,S7,S8,S9,S10,S12}。

3. 打分:假设 SG0 的 segment 所在的 store 的集合为 {S5,S3},其中 S5 为 leader 所在的 store, 对 PoolStores2 中的 store 进行打分,遍历 PoolStores,针对每个 pStore,遍历 SGStores,比较 pStore 和 sgStore 的位置,计算 pStore 的分值 pScore, 遍历完 SGStores 后,得到该 pStore 在该 SG 上的分值 pScore 的总分值,即 {100,100,100,100,100,200,200,200}。

4. 比较:如选择的 Stores 的分数相同,则按 Store 上 Segment 数量进一步比较,数量少的为选择的 Store,如选择出 Store10 作为为 SG0{S5,S3}的另一个副本。

此文已由作者授权腾讯云 + 社区发布
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复 1024 送你一份技术课程大礼包!

退出移动版