TiDB集群体系结构

TiDB集群体系结构
作者:周万春
微信:lovemysql3306



1、CAP分布式
CAP 理论是分布式系统的一个基础理论,它描述了任何一个分布式系统最多只能满足以下三个特性中的两个:
    一致性(Consistency)
    可用性(Availability)
    分区容错性(Partition tolerance



2、TiDB整体架构
TiDB 有以下的一些优势:
    纯分布式架构,拥有良好的扩展性,支持弹性的扩缩容
    支持 SQL,对外暴露 MySQL 的网络协议,并兼容大多数 MySQL 的语法,在大多数场景下可以直接替换 MySQL
    默认支持高可用,在少数副本失效的情况下,数据库本身能够自动进行数据修复和故障转移,对业务透明
    支持 ACID 事务,对于一些有强一致需求的场景友好,例如:银行转账
    具有丰富的工具链生态,覆盖数据迁移、同步、备份等多种场景


三大模块:每个模块都是分布式的架构。
    1、计算层(SQL)------------》TiDB
    2、分布式存储(K-V键值对)----》PD
    3、元信息系统、分布式调度-----》TiKV + TiFlash


TiDB
    1、无状态、不存储数据
    2、接受客户端连接
    3、执行 SQL 解析和优化
    4、生成分布式执行计划
    5、数据读取请求转发给底层的存储层 TiKV


TiKV + TiFlash
    TiKV 分布式 KV 存储(默认分布式存储引擎)。
         支持弹性的扩容和缩容。
         默认3个多副本。
         支持高可用和自动故障转移。
    TiFlash 把数据以列式的形式进行存储(是为了分析型的场景加速)。


PD
    整个 TiDB 集群的元信息存储。
    存储每个 TiKV 节点实时的数据分布情况和集群的整体拓扑结构。
    为分布式事务分配事务 ID。
    支持高可用。
    TiKV 节点实时上报的数据分布状态。
    PD 下发数据调度命令给具体的 TiKV 节点。



3、TiKV说存储
本地存储(RocksDB)
    TiKV 的 KV 存储模型和 SQL 中的 Table 无关!
    数据保存在 RocksDB 中,再由 RocksDB 将数据落盘。
    一个TiKV里面有两个 RocksDB,一个用于存储数据,一个用于存储 Raft。


TiKV 利用 Raft 来做数据复制,每个数据变更都会落地为一条 Raft 日志,通过 Raft 的日志复制功能,将数据安全可靠地同步到复制组的每一个节点中。
Raft 是一个一致性协议。
Raft 负责:
    Leader(主副本)选举
    成员变更(如添加副本、删除副本、转移 Leader 等操作)
    日志复制(通过 Raft,将数据复制到其他 TiKV 节点)

数据写入:
    数据的写入是通过 Raft 这一层的接口写入,而不是直接写 RocksDB。
    数据写入 ---》Raft ---》RocksDB ---》磁盘


Region
    对于一个 KV 系统,将数据分散在多台机器上有两种比较典型的方案:
        Hash:按照 Key 做 Hash,根据 Hash 值选择对应的存储节点。
        Range:按照 Key 分 Range,某一段连续的 Key 都保存在一个存储节点上。(TiKV选择此方案)
    连续的 key-value 划分为一个 Region,默认大小 96 M。
    TiKV:
        Region1:
            key1-value1
            key2-value2
            key3-value3
        Region2:
            key4-value4
            key5-value5
            key6-value6
    以 Region 为单位做数据的分散和复制:
        以 Region 为单位,将数据分散在集群中所有节点上,并且保证每个节点上 Region 数量尽可能相同。(此均匀分布是 PD 干的活)
        以 Region 为单位做 Raft 的数据复制和成员管理。
    TiKV 是以 Region 为单位做数据的复制,也就是一个 Region 的数据会保存多个副本,TiKV 将每一个副本叫做一个 Replica。
    Replica 之间是通过 Raft 来保持数据的一致,一个 Region 的多个 Replica 会保存在不同的节点上,构成一个 Raft Group。
    其中一个 Replica 会作为这个 Group 的 Leader,其他的 Replica 作为 Follower。
    所有的读和写都是通过 Leader 进行,读操作在 Leader 上即可完成,而写操作再由 Leader 复制给 Follower。 


TiKV 的 MVCC 实现是通过在 Key 后面添加版本号来实现。
    Key1_Version3 -> Value
    Key1_Version2 -> Value
    Key1_Version1 -> Value
    ......
    Key2_Version4 -> Value
    Key2_Version3 -> Value
    Key2_Version2 -> Value
    Key2_Version1 -> Value
    ......
    KeyN_Version2 -> Value
    KeyN_Version1 -> Value
    ......
    通过 RocksDB 的 SeekPrefix(Key_Version) API,定位到第一个大于等于这个 Key_Version 的位置。


分布式事务ACID
    TiKV 的事务采用的是 Google 在 BigTable 中使用的事务模型:Percolator。
    在 TiKV 层的事务 API 的语义类似下面的伪代码:
        tx = tikv.Begin()
            tx.Set(Key1, Value1)
            tx.Set(Key2, Value2)
            tx.Set(Key3, Value3)
        tx.Commit()



4、TiDB谈计算
表数据与 Key-Value 的映射关系
    TiDB 会为每个表分配一个表 ID,用 TableID 表示。表 ID 是一个整数,在整个集群内唯一。
    TiDB 会为表中每行数据分配一个行 ID,用 RowID 表示。行 ID 也是一个整数,在表内唯一。
        如果某个表有整数型的主键,TiDB 会使用主键的值当做这一行数据的行 ID。
    每行数据构成的 (Key, Value) 键值对:
        Key:   tablePrefix{TableID}_recordPrefixSep{RowID}
        Value: [col1, col2, col3, col4]


索引数据和 Key-Value 的映射关系
    TiDB 为表中每个索引分配了一个索引 ID,用 IndexID 表示。
    对于主键和唯一索引,我们需要根据键值快速定位到对应的 RowID,因此,按照如下规则编码成 (Key, Value) 键值对:
        Key:   tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
        Value: RowID
    对于不需要满足唯一性约束的普通二级索引,一个键值可能对应多行,我们需要根据键值范围查询对应的 RowID。 因此,按照如下规则编码成 (Key, Value) 键值对:
        Key:   tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue_{RowID}
        Value: null
    一个表内所有的行都有相同的 Key 前缀,一个索引的所有数据也都有相同的前缀。


元信息管理
    元信息也是以 Key-value 存储在了 TiKV 中。
    每个 Database/Table 都被分配了一个唯一的 ID。这个 ID 会编码到 Key 中,再加上 m_ 前缀。这样可以构造出一个 Key,Value 中存储的是序列化后的元信息。
    当前所有表结构信息的最新版本号,也会构成 Key-value 键值对,存储在 pd-server 内置的 etcd 中。
    其Key 为"/tidb/ddl/global_schema_version",Value 是类型为 int64 的版本号值。
    有一个后台线程在不断的检查 etcd 中存储的表结构信息的版本号是否发生变化,并且保证在一定时间内一定能够获取版本的变化。


TiDB 的 SQL层,即 tidb-server
    负责将 SQL 翻译成 Key-Value 操作,将其转发给共用的分布式 Key-Value 存储层 TiKV,然后组装 TiKV 返回的结果,最终将查询结果返回给客户端。
    将 SQL 查询映射为对 KV 的查询,再通过 KV 接口获取对应的数据,最后执行各种计算。
    这一层的节点都是无状态的,节点本身并不存储数据,节点之间完全对等。



5、PD讲调度
作为一个分布式高可用存储系统,必须满足的需求,包括四种:
    副本数量不能多也不能少
    副本需要分布在不同的机器上
    新加节点后,可以将其他节点上的副本迁移过来
    节点下线后,需要将该节点的数据迁移走


作为一个良好的分布式系统,需要优化的地方,包括:
    维持整个集群的 Leader 分布均匀
    维持每个节点的储存容量均匀
    维持访问热点分布均匀
    控制 Balance 的速度,避免影响在线服务
    管理节点状态,包括手动上线/下线节点,以及自动下线失效节点


信息收集
    调度依赖于整个集群信息的收集,简单来说,我们需要知道每个 TiKV 节点的状态以及每个 Region 的状态。TiKV 集群会向 PD 汇报两类消息:
    每个 TiKV 节点会定期向 PD 汇报节点的整体信息。
    TiKV 节点(Store)与 PD 之间存在心跳包,一方面 PD 通过心跳包检测每个 Store 是否存活,以及是否有新加入的 Store;另一方面,心跳包中也会携带这个 Store 的状态信息:
        总磁盘容量
        可用磁盘容量
        承载的 Region 数量
        数据写入速度
        发送/接受的 Snapshot 数量(Replica 之间可能会通过 Snapshot 同步数据)
        是否过载
        标签信息(标签是具备层级关系的一系列 Tag)
    每个 Raft Group 的 Leader 会定期向 PD 汇报信息。
    每个 Raft Group 的 Leader 和 PD 之间存在心跳包,用于汇报这个 Region 的状态,主要包括下面几点信息:
        Leader 的位置
        Followers 的位置
        掉线 Replica 的个数
        数据写入/读取的速度

PD 不断的通过这两类心跳消息收集整个集群的信息,再以这些信息作为决策的依据。
默认是 30 分钟,如果一直没有心跳包,就认为是 Store 已经下线。
再决定需要将这个 Store 上面的 Region 都调度走。但是有的时候,是运维人员主动将某台机器下线,这个时候,可以通过 PD 的管理接口通知 PD 该 Store 不可用,PD 就可以马上判断需要将这个 Store 上面的 Region 都调度走。

调度的策略
    一个 Region 的 Replica 数量正确
        当 PD 通过某个 Region Leader 的心跳包发现这个 Region 的 Replica 数量不满足要求时,需要通过 Add/Remove Replica 操作调整 Replica 数量。出现这种情况的可能原因是:
        某个节点掉线,上面的数据全部丢失,导致一些 Region 的 Replica 数量不足
        某个掉线节点又恢复服务,自动接入集群,这样之前已经补足了 Replica 的 Region 的 Replica 数量多过,需要删除某个 Replica
        管理员调整了副本策略,修改了 max-replicas 的配置

    一个 Raft Group 中的多个 Replica 不在同一个位置
    副本在 Store 之间的分布均匀分配
    访问热点数量在 Store 之间均匀分配
    各个 Store 的存储空间占用大致相等
    控制调度速度,避免影响在线服务
        如果希望加快调度(比如已经停服务升级,增加新节点,希望尽快调度),那么可以通过 pd-ctl 手动加快调度速度。
    支持手动下线节点
        当通过 pd-ctl 手动下线节点后,PD 会在一定的速率控制下,将节点上的数据调度走。当调度完成后,就会将这个节点置为下线状态。


调度的实现
    PD 不断的通过 Store 或者 Leader 的心跳包收集信息,获得整个集群的详细数据,并且根据这些信息以及调度策略生成调度操作序列,
    每次收到 Region Leader 发来的心跳包时,PD 都会检查是否有对这个 Region 待进行的操作,通过心跳包的回复消息,
    将需要进行的操作返回给 Region Leader,并在后面的心跳包中监测执行结果。
    注意这里的操作只是给 Region Leader 的建议,并不保证一定能得到执行,
    具体是否会执行以及什么时候执行,由 Region Leader 自己根据当前自身状态来定。

 

posted @ 2020-12-03 11:06  捧花大王  阅读(504)  评论(0编辑  收藏  举报