加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

资深架构师技术分享:一文详解分布式系统的分区

发布时间:2019-08-27 16:52:32 所属栏目:建站 来源:IT技术分享
导读:数据的复制是冗余的过程,冗余会增加可用性,并且可以有效均衡读取负载。而数据的分区是一个整体转换为局部的过程,这种拆解就像你拥有大量图书,但你的书架放不下,所以需要再加几个书架存储是一个道理。 将整体拆分,局部存储在多个较小空间内。这种思想映射到
副标题[/!--empirenews.page--]

数据的复制是冗余的过程,冗余会增加可用性,并且可以有效均衡读取负载。而数据的分区是一个整体转换为局部的过程,这种拆解就像你拥有大量图书,但你的书架放不下,所以需要再加几个书架存储是一个道理。

资深架构师技术分享:一文详解分布式系统的分区

将整体拆分,局部存储在多个较小空间内。这种思想映射到计算机上也是一样的,当数据量过大,单个存储节点不足与存储这些数据(更大容量的磁盘没有或者太贵)时,人们想要继续存储就需要将数据集拆解并规整。这就是数据分区的意义,它是用来提高数据系统的可扩展性而引入的技术方法。

资深架构师技术分享:一文详解分布式系统的分区

如何分区?

分区的关键在于采用一种统一的规则,这种规则可以计算出将数据放在哪个节点,并且在读取时也能计算出去哪个节点读取数据。

要做到这几点目前有三种分区方式:

  1. 按key的范围进行分区 当要存储数据时,我们取数据中的某一个字段作为分区key,按这个字段的范围进行分区例如自增的id值,0-10000存储在A节点上,10001-20000存储在B节点上,那么基于这样的规则我们可以高效的存取分区中的数据,并且自然的支持按区间查找(key的存储是有序的),只要区间的范围仅在一个分区时,那么区间查找就只会访问一个分区,除非查找范围跨越多个分区。但是问题在于当数据的写入在某段时间内存在热点时,例如0-100000的key被大量的写入,而10001-20000的key很少的时候,就会造成 数据倾斜 (数据分区大小不均衡)
  2. 按key的散列进行分区 对于数据倾斜,很自然的方式想到一个高效的散列函数来将数据存放在不同的分区,只要散列函数一致,相同的key一定会被映射到同一个分区。所以也是能够解决分区的关键问题,但是由于散列的问题,自然的进行区间范围查找会非常的困难,有些数据库会将区间查找的请求发送给所有分区,并行处理后,再全部聚合返回结果,但无疑会频繁的产生大量的请求,虽然可以有效的解决数据倾斜问题,但是这种热点数据是没有办法完全避免的,比如一个大V用户总有非常多的粉丝,每天要产生非常多的数据,通过key散列这些数据还是会存储在相同的分区内,造成数据倾斜的同时,还会导致热点数据的频繁访问,读与写负载都会分布不均匀。
  3. range+hash 模式 上述两种分区的优缺点恰好是互补的,那么可以考虑将二者结合例如用数据记录的两个关键字段作为key,比如是id与时间戳,先用id 散列存储在不同的分区上,然后在使用时间戳按范围进行分区,这样做在一定程度上弥补了二者的优缺点。 但依旧没有完全解决热点数据问题,这时热点数据问题可以考虑其他方面来解决,比如建立热点数据的缓存架构。

分区方法看似完美的对数据的存储进行了扩展,但也引入了另外的复杂度,那就是在查询数据的时候,如果数据恰巧不在同一个分区内,就需要访问多次不同的分区这样就会加大请求的延迟,或者当我们需要对关系模型中的数据进行join操作时,由于数据在不同的分区中的不同表内,进行join的难度就会非常大,增加了多表查询的复杂程度,一种折中的解决方案是,从业务上来看,将会被join或者同时读取的数据尽量放在同一个分区上,来减少跨分区调用的性能损耗,这就相当于降低磁盘寻址寻道的次数是一样的道理,都是在降低最耗时操作的发生次数。

二级索引的分区如何设计?

上述的三种分区方案,仅仅是对主键的分区,也就是一条记录的唯一标识进行分区,但从数据库功能的角度来看,我们还需要可以根据一条记录的任意字段建立索引,以便灵活高效的查询.这样的索引,就称之为二级索引。那么二级索引在分区数据库的设计上应该如何实现呢?通常有两种设计,本地索引与全局索引。

本地索引

当写入与读取二级索引时都在本分区上进行时,我们就说这样的二级索引为本地索引,也就是说每个分区上的二级索引文件仅存储本分区上的索引数据。这样做的好处是,在写入数据时更新一条记录的二级索引会很方便,因为关于本记录的所有二级索引都在这个节点上.但是以二级索引读取某条记录时,我们没办法知道记录在哪个分区,因此我们需要进行并行查询然后将查询结果进行合并,这样做无疑放大了读取的延迟。

全局索引

与之相对的是全局索引,即对于某个二级索引,其全部的字段都在同一个分区之中(不同的全局索引在不同的分区上),当我们查询某个二级索引时,我们可以只去唯一的一个节点上进行读取数据即可,不需要并行查询,这样读取的效率会很高,但是在写入数据的时候,由于一条记录涉及的二级索引可能在多个分区上,所以需要操作多个分区这就涉及到分布式的事务一致性等问题,复杂度大大增加并影响性能。全局索引在读取数据时,如何找到索引所在分区呢?答案是,对于全局的二级索引我们可以对其采用相同的分区策略,范围分区,散列分区或者散列范围分区等. 不同的分区策略同样会影响其对区间查询的效率。

分区再平衡

多个节点上拥有多个分区,当随着数据负载的增加,每个分区的大小就会不断的增加,这样就造成了隐患,一旦一个节点失效,其上分区都将失效,占比很大的一部分数据都将失效,再比如现在向集群中加入或剔除一个新的节点,那么数据需要可以被均匀的转移到新的节点上(新节点不转移数据,而是接受新的写请求是否可行?这样做会使在一段时间内,写入请求不能均衡的请求不同的节点,大量的请求新节点会使其负载不平衡),上述问题都概括起来就是引入分区再平衡特性的原因,即为了可用性与扩展性,分区再平衡都是必不可少的特性。

固定数量的分区

分区数与节点数应当不同,这样做是为了方便其扩展。理由是:假设分区数与节点数相同,那么通过对节点数取模来决定数据被分配到哪个分区上,这种取模会造成隐患.当我们添加或者删除一个节点时,取模的数发生变化,之前的数据不能被路由到正确的分区,所以必须进行再平衡对,所有数据重新分区(类似,hashmap 的再哈希),这会导致所有数据都处于迁移的状态,整个集群将不可用。

因此,我们必须将节点数与分区数进行解耦合,在一个节点上分配固定数量的分区数,例如在集群初始化时指定一个有1024个分区,现在有三个节点,那么每个节点应该拥有341个分区,最后一个节点可能拥有342个分区,这时添加一个节点,集群拥有4个节点后,我们需要对其进行分区再平衡,仅需要将原来的三个节点上的分区各取一半即可,这样就仅仅有一半的数据在迁移的过程中(比例经过复杂的算法可以动态调整),就可以降低分区再平衡过程中的复杂度了。节点删除也是同样的道理,将该节点上的分区平均的分散在其他节点上即可,固定数量的分区方案解决了节点数与分区数的耦合,我们对分区数进行取模即可很快的确定数据所在分区,并且在迁移前后相对分区保持不变,redis的集群模式就是采用这种方式进行的分区再平衡。

动态数量分区

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读