DDIA 读书笔记(5)数据分区方案
面对海量的数据以及超高的查询压力,普通的数据复制扛不住,需要将数据拆成很多块,每个节点储存一定量的数据,每一块数据称之为分区,或分片。
每个分区都会存储特定的数据,可以将一个分区视为一个小型的独立数据库。采取这样的方法可以有效降低每个节点的数据存储量以及查询压力,提高系统的拓展性。
kv 数据分区方案
分区的理想目标是将数据和负载均匀地分散在每个节点上,理论上10个节点就能承担10倍于单个节点的负载。现实情况是分区不可能完全均衡,甚至可能会有数据热点的存在,我们需要改善分区方法来尽量地打散数据
最简单的是基于关键字的特性按照区间划分,比如按照字典数据库按照单词首字母排序,A-C 一个区,D-Z 一个区。客户端可以根据查询关键词直接连接对应的节点。坏处是可能会有热点问题,微博的业务模型是最经典的例子。如果能够提前预测哪些关键字是热点,可以对热点进行特定处理,比如加上其他相关前缀让热点数据更加分散等。
更主流的方案是哈希分区,根据关键词的哈希值划分到不同的范围,好的哈希函数可以让数据很均匀的分布,这样做坏处是区间查询不好做,硬要做就得给所有节点发请求,所以大部分数据库如果启用了哈希分片,就不会提供区间查询功能。
二级索引
由于数据分散,建立可用的二级索引也变得十分复杂,有些基于 kv 的数据库甚至不提供相关功能。设计二级索引主要难点在于它不能规整地映射到分区当中,目前主要有两种方法,基于文档的分区和基于词条的分区。
基于文档分区的做法是将二级索引建立在本地,每个分区独立维护自己的二级索引,而不关心其他分区的情况。需要注意的是如果要通过二级索引查询,就必须请求所有的节点。虽然代价高昂,但用的还是很多。
还有一种正经方法就是维护一个全局索引,为了避免单点,索引数据也需要进行分区,不过可以独立选择合适的分区方式,不必与原始数据一致。这种分区方案被称为词条分区,优点是读取数据十分高效,客户端只需要向特定分区发送读请求,缺点是写入速度慢且复杂,单个文档更新可能会涉及多个二级索引,多个分区,写放大逃不掉。因此用这种方法更新二级索引只能是异步的。
分区再平衡
随着时间发展,原本平衡的数据通常都会倾斜,数据量增大需要引入新节点,或者旧的节点故障需要替代,这些场景都需要将数据搬家,转移节点,这个过程称为再平衡。我们需要选取合适的再平衡策略来尽量减少迁移的数据
有一个相当简单的解决方案,就是将数据分为足够多的分区,一个节点可以存储很多个分区,这样如果集群中添加的新节点,只需要匀走几个分区就可以达成新的平衡。由于分区是固定的,分区与数据的映射不会变,只需要改变分区和节点的映射即可。使用这个策略需要设计之初就把分区数确定好,要考虑未来的增长需求,毕竟分区过多还是会带来一些额外的开销。
有些业务场景关键词数据量不定,边界也不好划分,人工维护会非常困难,就需要系统动态地创建合并分区。相比于手动分区会灵活很多,系统可以根据数据量动态地设置分区大小,不必担心有额外的开销。但是自动平衡并不是完全的自动,可能会引入额外的风险,因为再平衡本身就是一个非常昂贵的操作,可能会导致节点负载过重,影响性能,甚至会误判节点的故障,导致级联失效,因此适当的人工介入是非常有必要的。
请求路由
分区和节点的映射,甚至分区和数据的映射可能都是动态的,因此请求究竟该落在哪个节点上需要一个有效的动态路由方案。这是一类典型的服务发现问题,大概有三种不同的策略:
客户端请求任意节点,收到的请求的节点进行二次转发。
客户端访问统一的路由层,进行转发。
客户端自行感知节点的分配情况,直接访问目标
每种方案都会有各自的优劣,需要根据具体的场景选择。
版权声明: 本文为 InfoQ 作者【莫黎】的原创文章。
原文链接:【http://xie.infoq.cn/article/3a9a76e7c18f000dec5b8aff0】。文章转载请联系作者。
评论