介绍

Shard指对数据的水平切分,每一个切分的部分都可以叫做一个shard,它们拥有相同的schema,但却拥有不同的数据集。对数据库来说,是指对数据库的表按行进行切分(与按列的垂直切分对应),不同的shard可能位于不同的数据库服务器或者物理机器上。它的优势体现在以下几点:

  • 表的大小减少,索引体积减小,提升查询性能(某些方面)
  • 如果数据本身有比较明显的分区(比如国家,地区等),那么做shard很容易并且查询很大程度上都能落在一个shard上。
  • 水平扩展性好,可以通过添加新节点来扩充

劣势有以下几点:

  • 查询需要跨多个shard时会增加latency
  • 因为shard经常只能做到某一位维度。所以在这一维度的查询的性能可能提高,但其他维度的查询的性能则可能会下降。
  • 跨shard的数据一致性和可用性也更加复杂和难以保障

shard本身的问题让他成为一个迫不得已的选择。尽量在没有其他优化方式的情况下选择shard.理想情况下,应该有底层框架来处理shard而让应用层做到对shard无感知,不然还不如不用。

分片策略

如果将数据集进行shard,有很多策略可以选择,常见的有

The Lookup strategy

用shard key做一个映射表,包含不同shard key的请求会转发到相应的shard上。这种情况下,不同shard key的数据可能会落在同一个shard上,但相同shard key的数据则一定在同一个shard上.shard与物理地址的映射也不能是一对一的,可以用类似于consistent hashing里面的那种virtual node的方式,设置一些virtual shard,几个virtual shard可以对应于同样的物理位置(reblancing的时候对上层代码的影响很小)。

The Range strategy

适用于需要获取区间连续数据的场景。与第一种策略类似,用shard key做分区,但shard key是按顺序排列的,每个shard内部的数据也经是有序的.(通常有一个row key用来在内部排序).

The Hash strategy

为了分散数据和请求,也可以用hash函数对数据做分片。上面两种策略避免不了的一个问题是,假如有一些数据是热点数据,那么他们很可能是位于少量的几个shard上,这样就造成了负载的不均衡。而利用hash函数则能尽量将热点数据分散开,必要时还可以加入一些随机元素来提高随机性.

相关技术

BRIN

Block Range Index.是一种作用于数据库索引上的类似于shard的技术。图示;

数据库里的数据在磁盘里存储时也是按block存储,通常也是按key的顺序。那么BRIN相当于对每一个block的一个描述:我拥有的最大值是多少,最小值是多少。对于查询来说,它知道了这个信息之后,发现目标值不在这个block的最小和最大值范围之间,那就可以直接跳过这个block.因为对于每个block只需要存一个tuple的值,内存占用很小,所以所有的BRIN信息都可以放在内存中(相比较而言B-Trees的index信息如果全放置在内存中占用会比较高)

优势

  • 对于读的场景来说,尤其是需要顺序扫描索引,用B-tree结合BRIN能够提高查询速度
  • 索引的一个坏处是会降低写入的速度,因为在写入的时候要一直维护索引。已经有各种优化措施,但是也比较复杂,很多场景也不实用。考虑用BRIN来代替普通索引的话,能够极大地减少维护索引的开销
  • 对于非常大的数据集,B-tree索引可能需要水平切分.创建BRIN的开销相比而言就要小的多,并且速度也更快。

对于随机性比较强的数据集或者有明显热点数据集的场景,BRIN不是很合适。因为它的作用是用来排除区间,上述两种场景并不能有效地排除有效的数据区间。

Ref:

  1. Shard (database architecture)
  2. BRIN wiki
  3. sharding patterns