分区之再平衡

346 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

本系列主要是《数据密集型应用系统设计》阅读笔记,本文记录分区主题的笔记心得。

随着时间的推移,数据库总会发生某些变化:

  • 查询压力增加,因此需要更多的CPU来处理负载
  • 数据规模增加,因此需要更多的磁盘和内存来存储
  • 节点可能出现故障,因此需要其他机器来接管失效的节点

这样的变化需要将数据和请求从一个节点转移到另一个节点。这样一个负载迁移的过程称为再平衡。 迁移之后,至少满足:

  • 负载、数据、请求等更均匀的分布
  • 再平衡的过程中,数据库应该可以继续提供读写服务
  • 避免不必要的负载迁移,以加快动态再平衡,尽量减少网络和磁盘I/O影响。

那么应该怎么再平衡呢?有几种如下的策略。

再平衡策略

再平衡的时候需要减少数据迁移。哈希分区的分区则可能不适合再平衡了。

固定数量的分区

  • 创建远超节点数的分区数
  • 每个节点分配多个分区,比如10个节点,逻辑分区为100个,这样大约每个节点承担100个分区
  • 如果添加了一个新节点,则可以匀走几个分区。
  • 如果删除节点,则是相反的均衡措施 选中的整个分区在节点之间迁移,分区的总数量维持不变也不改变关键字到分区的映射关系。唯一调整的是分区和节点的对应。

目前ElasticSearch等支持这种动态平衡的方法。 分区的数量在创建数据库的时候就确定了,初始化需考虑将来扩容增长的需求,设置一个足够大的分区。而每个分区也有额外的管理开销,选择太大也有可能有副作用

动态分区

对于采用关键字区间分区的数据库,如果边界设置有问题,可能会出现所有数据都挤在一个分区而其他分区基本为空的情况。手动重新分配比较繁琐,像HBase等采用了动态创建分区

  • 当分区的数据增长超过一个阈值(比如10G),则拆分为两个分区,每个承担一半的数据。
  • 如果大量数据被删除,缩小到某个阈值,则将其与相邻的分区合并 动态分区的优点是分区数可以自动适配数据总量,如果只有少量的数据,少量的分区就足够了,这样系统开销很小;如果有大量的数据,每个分区大小则被限制。

Hbase和MongoDb会在一个空的数据库创建一组初始分区

按节点比例分区

Cassandra等采用了按节点比例分区,每个节点拥有固定数量的分区。 像一致性哈希分区适合这种再平衡的方式。

自动还是手动执行?

再平衡说应该自动执行还是手动执行呢? 再平衡是个昂贵的操作,需要重新路由请求并将大量数据从一个节点迁移到另一个节点。全自动平衡对时机和风险的评估不够,所以由系统生成一个分区分配的方案,再由管理员确认生效更好一些。

请求路由

当客户需要发送请求的时候,如何知道应该连接哪个节点呢? 尤其是发生了再平衡之后。

概括来讲,有如下几种不同的处理策略:

  • 客户端连接任意的节点。如果节点刚好拥有所处理的分区们则处理;否则转发到下一个合适的节点,接收答复并将答复转发给客户端。
  • 客户端将请求发送到路由层,后者转发到对应分区的节点,接收答复并将答复转发给客户端。
  • 客户端感知分区和节点分配到关系

如下图:

image.png

许多分布式数据库依靠独立的协调服务(ZooKeeper)跟踪集群范围内的元数据。每个节点都向ZooKeeper注册自己,ZooKeeper维护了分区到节点的最终映射关系。其他参与者(路由层或感知分区的客户端)可以向ZooKeeper订阅此信息。像Hbase、kafka和MongoDB都是使用ZooKeeper来跟踪分区分配情况的。