• CockroachDB架构-分布式层


    本文知识点来源于官网地址https://www.cockroachlabs.com/docs/v22.1/architecture/distribution-layer.html

    概览

    CockroachDB(以下简称CRDB)将数据存储在key-value对组成的巨大的有序map结构。这个map里面描述了集群中的所有数据,以及数据的位置。数据及数据的位置信息(我们称之为meta数据)均以range为单位存储。所有的key都能在某一个range中找到具体的数据。

    通过这个巨大的有序的map,可以实现:

    1. 简单查找:由于我们确定哪些节点负责存储哪些数据,查询可以快速定位到要查找的数据。
    2. 高效扫描:由于数据是顺序存放,很容易在扫描过程中找到特定的数据。

    这个巨大的有序的map主要包括两部分内容:

    1. meta数据:描述集群中数据位置的元数据
    2. 用户数据:存储表的数据

    Meta数据

    集群中所有range的位置都存储在key空间开头的一个两级索引中,称为meta range。meta range中包含一级meta(meta1)及二级meta(meta2),meta1指向meta2,meta2指向集群中的数据。
    可以用以下树型结构来理解两级索引和用户数据的关系:
    在这里插入图片描述
    当数据量不是特别大的时候,此时meta1和meta2存放在一个range当中,meta1只有一条元数据,指向meta2,meta2中每个元数据对应每个用户数据所在的每个range的信息。
    每个range的最大容量是512MB。每个range的元数据信息大约占用256Byte空间,因此一个meta range可以容纳1PB左右的用户数据。
    如果集群的实际数据确实比较大,如超过1PB,这时候meta range的512MB无法存放所有的range元数据,而meta range又是不可分割的,此时会用新的range来存储新产生的meta2数据。
    meta range可以像普通range一样被处理,像集群中KV数据一样被访问和复制。
    另外,每个节点都会缓存相关的meta数据,以提升对数据访问的效率。如果缓存中没有相关的meta数据,就通过常规读取来更新缓存数据。

    用户数据

    meta range后面的key空间就是集群中KV数据,也是以range为单位进行存储。
    每个表及二级索引最开始映射到一个range,range中的每个key-value表示表中的一行数据。当一个range大小达到512MB时,它就分裂为两个range。当数据量持续增大时,后续会继续分裂。数据以range为单位进行复制(通过复制层),并将每个副本的地址存储在meta range中。

    使用巨大的有序的map

    当一个节点接收到请求时,它以自底向上的方式查询包含请求的key的range位置。其工作原理如下:

    1. 对于每个key,节点首先从本地缓存中查找包含指定key的range的位置。如果在缓存中找到range的位置,则立即返回它。
    2. 如果在本地缓存中没有找到以上数据,则需要进一步从缓存中去查找meta2所在的range的位置。如果在缓存中找到meta2所在的range的位置,节点向meta2的range发送一个RPC,以获取包含指定key的range的位置。
    3. 如果在本地缓存中没有找到meta2的range位置,节点将再进一步从缓存中查找meta1所在的range的位置。由于在实际情况下meta1的range位置一定是通过Gossip协议分布在集群各节点的缓存中,因此正常情况下都可以在缓存中找到此数据。关于Gossip协议,可以参考另外一篇文章介绍分布式一致性协议之Gossip
    4. 在从缓存中找到了meta1的range位置后,通过meta1找到指向的meta2的位置,最后找到要包含指定key的range的位置。

    上面描述的过程是递归的,每次递归查找时,要么从缓存中获取一个位置,要么对树上“上一层”的值执行另一个查找。因为meta range是缓存的,通常情况下可以执行查找,而不需要向另一个节点发送RPC。

    range描述符

    CRDB每个range都有元数据,称为“range描述符”。range描述符由以下内容组成:

    1. 一个连续的RangeID。
    2. range包含的key集合,通常是表数据KV的第一个和最后一个索引列值。这个就是meta2 range的key。
    3. range及副本的地址。这个就是meta2 range的value。

    由于range描述符包含meta2 range的key-value数据,所以每个节点的meta2缓存也缓存了range描述符。

    range描述符会在以下几种情况下进行更新:

    1. range Raft组成员变更(具体见复制层)
    2. range分割
    3. range合并

    所有range描述符的更新都在range所在节点的本地发生,然后传播到meta2 range。

    Range拆分

    默认情况下,CRDB尝试保持范围/副本为默认范围大小(当前为512 MiB)。一旦一个范围达到了这个限制,我们就把它分成两个更小的范围(由连续的键空间组成)。
    在分割范围期间,节点创建一个新的Raft组,其中包含与分割范围相同的所有成员。现在有两个范围这一事实也意味着存在一个事务,它使用新的键空间边界更新meta2,以及使用范围描述符的节点地址。

    基于负载的拆分

    为了优化集群的性能,CRDB可以将频繁访问的键分割为更小的范围。与基于负载的再平衡一起,基于负载的拆分在集群中平均分配负载。

    启动/禁用基于负载的拆分
    可以通过以下参数设置来打开/关闭基于负载的拆分功能,默认为打开。

    SET CLUSTER SETTING kv.range_split.by_load_enabled = false;
    
    • 1

    另外,可以通过以下参数来控制什么时候对range进行拆分,默认为2500。

    SET CLUSTER SETTING kv.range_split.load_qps_threshold = 2000;
    
    • 1

    基于负载的拆分如何工作
    当一个范围超出了设置的kv.range_split.load_qps_threshold,该范围适合基于负载的拆分。
    在这一点上,开始收集每个关键指标,以确定拆分是否会基于以下启发式来提高集群的性能:

    • 平衡因素:如果您执行拆分,拆分的两边会有负载平衡吗?例如,如果99%的流量用于单个键,那么将其与范围内的其他键分离不会对性能产生实质性影响。但是,如果60%的查询是针对单个键的,那么将键移动到它自己的范围可能会使集群受益。
    • 分割交叉:如果执行分割,有多少查询需要跨越这个新的范围边界?因为在查询中涉及多个范围会比单个范围产生更大的开销,因此分割范围实际上会降低性能。例如,如果范围涉及多个SELECT COUNT(*)…如果将范围一分为二,可能会对性能产生负面影响。

    Range合并

    默认情况下,CRDB自动将小范围的数据合并到一起,形成更少、更大的范围(直到默认的范围大小)。这可以提高查询延迟和集群生存能力。

    Range合并如何工作

    CRDB将您的集群数据划分为许多范围。例如,您的集群可能有一个id在[1000,2000)之间的客户的范围。如果该范围超过默认的范围大小,则该范围将被分割为两个更小的范围。
    但是,当您从集群中删除数据时,范围包含的数据可能远远小于默认范围大小。在集群的生命周期中,这可能导致许多小范围。
    为了减少小范围的数量,您的集群可以有任何低于一定大小阈值的范围,尝试与它的“右邻居”合并,即从当前范围结束的地方开始的范围。使用上面的例子,这个范围的右邻居可能是id在[2000,3000)之间的客户的范围。
    如果小范围和它的邻居的组合大小小于最大范围大小,范围合并为一个单一的范围。在我们的示例中,这将创建一个新的键范围[1000,3000)。

    在CRDB中的查询必须联系查询中涉及的每个范围的副本。这对于有很多小范围的集群会产生以下问题:

    • 查询对于它们必须协调的每个范围的处理时间会产生固定的开销。
    • 拥有许多小范围可以增加您的查询必须与之协调的机器数量。这将使您的查询更有可能遇到网络延迟或节点过载等问题。

    通过合并小范围,CRDB可以大大减少查询中涉及的范围的数量,从而减少查询延迟。

    每当节点联机或脱机时,CRDB自动重新平衡集群中的范围分布。

    • 在重新平衡过程中,最好在节点间复制几个较大的范围,而不是许多较小的范围。复制更大的范围需要更少的协调,通常完成得更快。
    • 通过合并较小的范围,集群需要重新平衡的总范围更少。这最终会提高集群的性能,特别是在面对节点中断等可用性事件时。
  • 相关阅读:
    基于遗传算法的红绿灯间隔时间优化(代码完整,数据齐全)
    vue3+te项目正式开发
    语言的数据结构:树与二叉树(二叉树篇)
    12数据结构与算法刷题之【贪心】篇
    使用图形化界面Navicat连接mysql关于密码出现的各种报错问题
    java初探之代理模式
    【Linux系统化学习】开发工具——gdb(调试器)
    【C++】递归,搜索与回溯算法入门介绍和专题一讲解
    Mysql高级——Mysql8一主一从,多主多从搭建
    TypeScrip
  • 原文地址:https://blog.csdn.net/Post_Yuan/article/details/126976194