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,一经查实,立即删除!

相关文章

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 …

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…

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

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

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…

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 …

Sumsets POJ - 2229(计数dp)

题意&#xff1a; 给一个数&#xff0c;是集合的总数和&#xff0c;集合元素只能为2的次幂数&#xff0c;问这样的集合有多少&#xff1f; 题目&#xff1a; Farmer John commanded his cows to search for different sets of numbers that sum to a given number. The cows…

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

上一篇文章&#xff0c;把这个架构的起因&#xff0c;和操作系统的选择进行了详细说明。原文地址&#xff1a;15分钟从零开始搭建支持10w用户的生产环境(一)二、数据库的选择对于一个10W用户的系统&#xff0c;数据库选择很重要。一般来说&#xff0c;这个用户量&#xff0c;根…

[Java基础]Stream流的常见中间操作方法

代码如下: package StreamTest;import java.util.ArrayList;public class StreamDemo02 {public static void main(String[] args){ArrayList<String> list new ArrayList<String>();list.add("Tom");list.add("Bom");list.add("jack&q…

云原生初探

文章目录什么是云原生&#xff1f;第二讲 容器的基本概念什么是容器&#xff1f;容器运行时的生命周期容器项目的架构容器和VM的差异第三讲 Kubernetes核心概念什么是KubernetesKubernetes架构Kubernetes核心概念和API第四讲 理解Pod和容器设计模式为什么Pod必须是原子调度单位…

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

上一篇文章介绍了这个架构中&#xff0c;选择MongoDB做为数据库的原因&#xff0c;及相关的安装操作。原文地址&#xff1a;15分钟从零开始搭建支持10w用户的生产环境(二)三、WebServer在SOA和gRPC大行其道的今天&#xff0c;WebServer在系统中属于重中之重&#xff0c;是一个系…

[Java基础]Stream流终结操作之forEachcount

代码如下: package StreamTest;import java.util.ArrayList;public class StreamDemo06 {public static void main(String[] args) {ArrayList<String> list new ArrayList<String>();list.add("Jack");list.add("Tom");list.add("张敏…

实现.Net程序中OpenTracing采样和上报配置的自动更新

前言OpenTracing是一个链路跟踪的开放协议&#xff0c;已经有开源的.net实现&#xff1a;opentracing-csharp&#xff0c;同时支持.net framework和.net core&#xff0c;Github地址&#xff1a;https://github.com/opentracing/opentracing-csharp。这个库支持多种链路跟踪模式…