DDIA笔记—第六章 数据分区

第六章 数据分区

数据分区与数据复制

分区通常与复制结合使用,即每个分区在多个节点都存在副本,这就意味着某条记录属于特定的分区,而同样的内容会保存在不同的节点上以提高系统的容错性。

每个节点同时充当某些分区的主副本和其他分区的从副本:

在这里插入图片描述

如何进行分区?

如何决定哪些记录放在哪些节点上?分区的主要目的是将数据和查询负载均匀的分布在所有节点上。如果分区不均匀,则会出现某些分区节点比其他分区承担更多的数据量和查询负载,称之为倾斜。更为严重的情况是,所有的负载都集中在一个分区节点上,这种负载严重不成比例的分区称为系统热点。避免系统热点最简单的方式就是将记录随机分配给所有节点,但这有带来了另一个问题:如何读取数据?(简单的键-值数据模型,可以通过关键字来访问记录)

键-值数据的分区

基于关键字区间分区

为每个分区分配一段连续的关键字或者关键值区间范围。为了更均匀的分布数据,分区边界理应适配数据本身的分布特征。

在这里插入图片描述

但是基于关键字的区间分区的缺点是某些访问模式可能会导致热点,例如:采用时间戳作为关键字,则分区对应于一个时间范围,如果将每天作为一个分区,同一天内所有写入都集中在同一个分区,而其他的分区始终处于空闲状态。

基于关键字哈希值分区

一个好的哈希函数可以处理数据倾斜并使其均匀分布。一旦找到了合适的关键字哈希函数,就可以为每个分区分配一个哈希范围,关键字根据其哈希值的范围划分到不同的分区中。

这种方式看似非常完美,但是在做范围查询时,往往会变的非常麻烦:即使关键字相邻,但经过哈希函数之后可能会被分散到不同的分区中。在MongoDB中,如果启用了基于哈希的分片模式,则区间查询会发送到所有分区上。

综上,基于哈希的分区方法可以减轻热点,但无法做到完全避免。

分区与二级索引

二级索引带来的主要挑战是它们不能规整的映射到分区中。有两种主要的方法来支持对二级索引进行分区:

基于文档分区的二级索引

如图,每条记录都有唯一的ID,首先用此ID对数据库进行分区(例如:0 <= ID < 500属于分区0,500 <= ID < 1000属于分区1)。现在用户需要搜索汽车,可以支持按汽车颜色和厂商进行过滤,所以需要在颜色和制造商上设定二级索引。声明这些索引之后,数据库会自动创建索引。

在这里插入图片描述

在这种索引方法中,每个分区完全独立,各自维护自己的二级索引,因此文档分区索引也被称为本地索引。

读取时需要注意:如果是要查询所有红色汽车(假设没有对ID做特殊处理),则查询请求需要发送到所有的分区,然后再合并结果。所以导致了查询代价高昂、读延迟加大。

基于词条的二级索引分区

另一种方法,我们可以对所有的数据构建全局索引,同时,为了避免瓶颈,不能将全局索引存储在一个节点上,否则就破坏了设计分区均衡的目标。所以,全局索引也必须分区,且可以与数据关键字采用不同的分区策略。

如图,所有颜色为红色的汽车的ID收录在索引color:red中,而索引本身也是分区的,例如从a~r开始的颜色索引放在分区0中。我们将这种索引方案称为词条分区。和前面讨论的方法一样,可以直接通过关键字来全局划分索引,或者对其取哈希值,各自的优点在前面也都提到了。

在这里插入图片描述

这种全局的词条索引相比于文档分区索引的主要优点是:它的读取更为高效,即不需要向所有分区都查询一遍。但是缺点也非常明显:由于需要维护索引,导致它的写入速度非常慢。理想情况下,索引应该时刻保持最新,但是,对于词条分区来说,这需要一个跨多个相关分区的分布式事务支持(这也是现有数据库不支持同步更新二级索引的原因)。

分区再平衡

随着时间的推移,数据库可能总会出现,某些变化:

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

所有这些变化都要求数据和请求能从一个节点转移到另一个节点,这样一个过程就称为再平衡(动态平衡)。无论对于哪种分区方案,分区再平衡通常只少要满足:

  • 平衡之后,负载、数据存储、读写请求等应该在集群范围更均匀的分布;
  • 再平衡执行过程中,数据库应该可以继续正常提供读写服务;
  • 避免不必要的负载迁移,并尽量减少网络和磁盘I/O影响;

动态再平衡策略

为什么不采用模运算?

如果节点数发生变化,将会导致大量的关键字需要从现有节点迁移到另一个节点,频繁的迁移大大增加再平衡的成本。

固定数量的分区

如图,如果集群中添加了一个新节点,该新节点可以从每个现有的节点上匀走几个分区,直到分区再次达到全局平衡(当然,如果增加的节点性能更加强大,则可以给它分配更过的分区,从而分担更多的负载)。删除的话,就是一个逆向的操作。这种方式不会改变关键字到分区的映射关系,唯一要调整的是分区与节点的对应关系。

在这里插入图片描述

在这种方式中,为了使得相关操作变得非常简单,分区的数量往往中数据库创建时就已经确定好(原则上可以拆分和合并,但是为了简单,许多数据库决定不支持分区拆分和合并),所以,在初始化时,就会设置一个足够大的分区数(每个分区都会有额外的管理开销)。如果数据集的规模不确定,此时如何选择合适的分区数以及分区大小就会有些困难。

动态分区

简单的理解就是,当分区的数据增长超过一个参数阈值(HBase默认值为10GB)时,它就拆分为两个分区(可以将其中一部分转移到其他节点),每个分区承担一半的数据量。相反,如果数据被大量删除,并且缩小到某个阈值以下,则将其与相邻分区进行合并。

动态分区的一个优点是:分区数量可以自动适配数据总量

但对于一个空的数据库,初始时可能会从一个分区开始,这样在达到第一个分裂点之前,所有写入请求都由单个节点来处理,而其他节点处于空闲状态。为了缓解这种问题,HBase和MongoDB允许采用预分裂(配置一组初始分区),同时,预分裂要求知道一些关键字的分布情况。

按节点比例分区

动态分区中分区的数量与数据集的大小成正比,固定数量分区中分区大小也与数据集反大小成正比,这两种方式都与节点数无关。

一些数据库系统(Cassandra、Ketama)采用了第三种方式,使分区数与集群节点数成正比。也就是说,每个节点具有固定数量的分区。当一个新节点加入集群时,它随机选择固定数量的现有分区进行分裂,然后拿走这些分区的一半数据。

自动与手动再平衡操作

再平衡总体上讲是一个昂贵的操作,它需要重新路由请求,并将大量数据从一个节点迁移到另一个节点。

全自动再平衡虽然方便,但有可能在再平衡过程中出现难以预测的情况。例如:假设某个节点负载过重,对请求对响应暂时受到影响,其他的节点可能会得到结论:该节点失效;接着触发自动平衡来转移负载,这无疑会加重该节点、其他节点以及网络的负载。

所以,你怎么选择,自动 or 手动?

请求路由

客户端如何知道要连接哪个节点?

这个问题有以下几种处理策略:

  • 允许客户端链接任意节点。如果某节点恰好拥有所请求的分区,则直接处理该请求;否则,将请求转发给下一个节点,接收答复,并将答复返回给客户端;
  • 所有客户端的请求发给路由层,由路由层将请求转发给对应的分区节点;
  • 客户端自己感知分区和节点的分配关系;

在这里插入图片描述

所以,这里的核心问题就变成了:作出路由决策的组件(某个节点、路由层、客户端)是如何知道分区与节点的对应关系以及变化情况的呢?很多分布式数据系统依靠独立的协调服务(如ZooKeeper)跟踪集群范围内的元数据。类似的还有:MongoDB依赖于自己的配置服务器和mongos守护进程来充当路由层等。

每个节点都向Zookeeper中注册自己,ZooKeeper维护了分区到节点的最终映射关系。其他参与者可以向ZooKeeper订阅此信息。一旦分区发生了改变,或者删除、添加节点,ZooKeeper都会通知参与者。

并行查询执行

大规模并行计算(massively parallel processing,MPP)中查询类型方面要复杂的多,典型的操作会包含多个联合、过滤、分组、聚合等操作。MPP查询优化器会将复杂的查询分解成许多执行阶段和分区,以便在不同节点上并行执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Piggy-Bank POJ - 1384(完全背包+背包放满)

题意&#xff1a; 给出一个存钱罐的重量和没存钱之前存钱罐的重量&#xff0c;然后给出几种硬币的重量和币值&#xff0c;计算存钱罐里至少有多少钱。 题目&#xff1a; Before ACM can do anything, a budget must be prepared and the necessary financial support obtain…

Magicodes.IE 2.2发布

Magicodes.IE 2.2发布导入导出通用库&#xff0c;支持DTO导入导出以及动态导出&#xff0c;支持Excel、Word、PDF、CSV和HTML。已加入ncc开源组织.Magicodes.IE2.0发布Magicodes.IE2.1发布如何做好一个开源项目(一)GitHub&#xff1a;https://github.com/dotnetcore/Magicodes.…

C++ 基类,子对象,派生类构造函数调用顺序

#include <iostream> using namespace std;class A {public:A( ) {cout << "A Constructor………" << endl;}~A( ) {cout << "A Destructor………" << endl;} };class B: public A {public:B( ) {cout << "B …

牛客网 第十七届中国计量大学程序设计竞赛(同步赛)(重现赛)B题 Broken Pad 暴力+思维

题意&#xff1a; 给你两个01串&#xff0c;经过两种操作&#xff0c;1.直接让第一串经过操作变成目标串&#xff1b;2.可以点击空白处&#xff0c;即0的地方&#xff0c;使得操作串全部清空为0串&#xff0c;再变为目标串&#xff1b;最终比较两种方式&#xff0c;哪种需更少…

C++ 虚析构函数

代码如下: #include <iostream> using namespace std;class Base {public:Base() {cout << "Base" << endl;}~Base() {cout << "Base destructor" << endl;} };class Derived : public Base {public:Derived() {cout <&…

I - Interesting Permutation Gym - 102394I(排列组合)

题意&#xff1a; 纯数题 1≤i≤n, fimax{a1,a2,…,ai}; 1≤i≤n, gimin{a1,a2,…,ai}; 1≤i≤n, hifi−gi. 数列a是一个排列&#xff0c;问多少种排列方式满足h数列。 题目&#xff1a; DreamGrid has an interesting permutation of 1,2,…,n denoted by a1,a2,…,an. He …

Magicodes.SwaggerUI 已支持.NET Core 3.1

Magicodes.SwaggerUI 通过配置文件简单配置即可快速完成SwaggerUI的配置&#xff0c;包括&#xff1a;SwaggerUI的文档信息API分组API隐藏API JSON生成&#xff08;枚举、API架构Id&#xff09;验证自定义页面支持.NET Core 2.2和3.1。版本日志和使用教程见下文。注意&#xff…

PTA天梯赛L1-006 连续因子 (20分)

题目&#xff1a; 一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3567&#xff0c;其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N&#xff0c;要求编写程序求出最长连续因子的个数&#xff0c;并输出最小的连续因子序列。 输入格式&#xff1a; …

C++ 多态实现的三个条件

多态实现的三个条件&#xff1a; 1.必须是公有继承 2.必须是通过基类的指针或引用 指向派生类对象 访问派生类方法 3.基类的方法必须是虚函数&#xff0c;且完成了虚函数的重写

[推荐]大量 Blazor 学习资源(二)

继上一篇《[推荐]大量 Blazor 学习资源&#xff08;一&#xff09;》之后&#xff0c;社区反应不错&#xff0c;但因个人原因导致这篇文章姗姗来迟&#xff0c;不过最终还是来了&#xff01;这篇文章主要收集一些常用组件、书籍和电子书。资料来源&#xff1a;https://github.c…

Golang实现最大堆/最小堆

Golang实现最大堆/最小堆 参考&#xff1a; https://yangjiahao106.github.io/2019/01/15/golang-%E6%9C%80%E5%A4%A7%E5%A0%86%E5%92%8C%E6%9C%80%E5%B0%8F%E5%A0%86/ https://studygolang.com/articles/24288 方法一 此方法就是比较传统、常见的方法&#xff0c;下面来构建一…

团体程序设计天梯赛-练习集L1-011 A-B (20分)getline输入

little tips&#xff1a;关于天梯赛不能用gets 题目&#xff1a; 本题要求你计算A−B。不过麻烦的是&#xff0c;A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉&#xff0c;剩下的字符组成的就是字符串A−B。 输入格式&#xff1a; 输入在2行中先后给出字…

Sql Server之旅——第八站 看公司这些DBA们设计的这些复合索引

这一篇再说下索引的最后一个主题&#xff0c;索引覆盖&#xff0c;当然学习比较好的捷径是看看那些大师们设计的索引&#xff0c;看从中能提取些什么营养的东西&#xff0c;下面我们看看数据库中一个核心的Orders表。一&#xff1a;查看表的架构1. 先查看这个表的大概架构信息-…

C++ setprecision()用法

io 流控制头文件, 主要是一些操纵用法如setw(int n),setprecision(int n) #include < iomanip > setw(n)用法&#xff1a; 通俗地讲就是预设宽度 #include<iostream> #include <iomanip> using namespace std;int main() {cout << setw(5) <<…

备战ccpc分站赛:秦皇岛和威海站(数论模块和dp模块)

挑战程序设计竞赛&#xff08;第2版&#xff09;练习题 tips&#xff1a;难度&#xff08;个人主观判断&#xff09;&#xff1a; 简单* 简单但卡思维 ** 中 *** 中稍加思考 **** 难 ***** 1 . 记录结果再利用的“动态规划” &#xff08;1&#xff09;基础的动态规划算法&am…

Go 排序方式

参考&#xff1a; https://segmentfault.com/a/1190000016514382 &#xff08;值得一看&#xff09; Go 常见排序方式 整数、浮点数、字符串切片排序 sort包提供了一下几种排序函数&#xff1a; sort.Ints(x []int)sort.Float64s(x []float64)sort.Strings(x []string) 使用…

15分钟从零开始搭建支持10w+用户的生产环境(四)

上一篇文章&#xff0c;介绍了这个架构中&#xff0c;WebServer的选择&#xff0c;以及整个架构中扩展时的思路。原文地址&#xff1a;15分钟从零开始搭建支持10w用户的生产环境(三)五、架构实践前边用了三篇文章&#xff0c;详细介绍了这个架构的各个部分的选择以及安装。这篇…

[Java基础]体验Stream流

代码如下: package StreamTest;import java.lang.reflect.Array; import java.util.ArrayList;public class StreamDemo {public static void main(String[] args){ArrayList<String> list new ArrayList<String>();list.add("Tom");list.add("ja…

Cow Bowling POJ - 3176(基础的动态规划算法)

题意&#xff1a; 杨辉三角&#xff0c;让从顶部开始走到底部&#xff0c;所经过的每一层的点数相加&#xff0c;使得实现最高和。 题目&#xff1a; The cows don’t use actual bowling balls when they go bowling. They each take a number (in the range 0…99), thoug…

[Java基础]Stream流的常见生成方式

1.Collection体系的集合可以使用默认方法stream()生成流 default Stream< E > stream() 代码如下: package StreamTest;import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Stream;public …