带着问题学习分布式系统之数据分片
但是,一致性hash方式在增加节点的时候,只能分摊一个已存在节点的压力;同样,在其中一个节点挂掉的时候,该节点的压力也会被全部转移到下一个节点。我们希望的是“一方有难,八方支援”,因此需要在增删节点的时候,已存在的所有节点都能参与响应,达到新的均衡状态。 因此,在实际工程中,一般会引入虚拟节点(virtual node)的概念。即不是将物理节点映射在hash换上,而是将虚拟节点映射到hash环上。虚拟节点的数目远大于物理节点,因此一个物理节点需要负责多个虚拟节点的真实存储。操作数据的时候,先通过hash环找到对应的虚拟节点,再通过虚拟节点与物理节点的映射关系找到对应的物理节点。 引入虚拟节点后的一致性hash需要维护的元数据也会增加:第一,虚拟节点在hash环上的问题,且虚拟节点的数目又比较多;第二,虚拟节点与物理节点的映射关系。但带来的好处是明显的,当一个物理节点失效是,hash环上多个虚拟节点失效,对应的压力也就会发散到多个其余的虚拟节点,事实上也就是多个其余的物理节点。在增加物理节点的时候同样如此。 工程中,Dynamo、Cassandra都使用了一致性hash算法,且在比较高的版本中都使用了虚拟节点的概念。在这些系统中,需要考虑综合考虑数据分布方式和数据副本,当引入数据副本之后,一致性hash方式也需要做相应的调整, 可以参加cassandra的相关文档。 range based 简单来说,就是按照关键值划分成不同的区间,每个物理节点负责一个或者多个区间。其实这种方式跟一致性hash有点像,可以理解为物理节点在hash环上的位置是动态变化的。 还是以上面的数据举例,三个节点的数据区间分别是N0(0, 200], N1(200, 500], N2(500, 1000]。那么数据分布如下: ![]() 注意,区间的大小不是固定的,每个数据区间的数据量与区间的大小也是没有关系的。比如说,一部分数据非常集中,那么区间大小应该是比较小的,即以数据量的大小为片段标准。在实际工程中,一个节点往往负责多个区间,每个区间成为一个块(chunk、block),每个块有一个阈值,当达到这个阈值之后就会分裂成两个块。这样做的目的在于当有节点加入的时候,可以快速达到均衡的目的。 不知道读者有没有发现,如果一个节点负责的数据只有一个区间,range based与没有虚拟节点概念的一致性hash很类似;如果一个节点负责多个区间,range based与有虚拟节点概念的一致性hash很类似。 range based的元数据管理相对复杂一些,需要记录每个节点的数据区间范围,特别单个节点对于多个区间的情况。而且,在数据可修改的情况下,如果块进行分裂,那么元数据中的区间信息也需要同步修改。 range based这种数据分片方式应用非常广泛,比如MongoDB, PostgreSQL, HDFS 小结: 在这里对三种分片方式(应该是四种,有没有virtual node的一致性hash算两种)进行简单总结,主要是针对提出的几个问题: 上面的数据动态均衡,值得是上述问题的第4点,即如果某节点数据量变大,能否以及如何将部分数据迁移到其他负载较小的节点 分片特征值的选择 上面的三种方式都提到了对数据的分片是基于关键值、特征值的。这个特征值在不同的系统中有不同的叫法,比如MongoDB中的sharding key, Oracle中的Partition Key,不管怎么样,这个特征值的选择都是非常非常重要的。 那么。怎么选择这个特征值呢?《Distributed systems for fun and profit》给出了言简意赅的标准:
大概翻译为:基于最常用的访问模式。访问时包括对数据的增删改查的。比如上面的列子,我们选择“id”作为分片的依据,那么就是默认对的数据增删改查都是通过“id”字段来进行的。 如果在应用中,大量的数据操作都是通过这个特征值进行,那么数据分片就能提供两个额外的好处:
如果大量操作并没有使用到特征值,那么就很麻烦了。比如在本文的例子中,如果用name去查询,而元数据记录的是如何根据按照id映射数据位置,那就尴尬了,需要到多有分片都去查一下,然后再做一个聚合! 另外一个问题,如果以单个字段为特征值(如id),那么不管按照什么分布方式,在多条数据拥有相同的特征值(如id)的情况下,这些数据一定都会分布到同一个节点上。在这种情况下有两个问题,一是不能达到节点间数据的均衡,二是如果数据超过了单个节点的存储能力怎么办?关键在于,即使按照分布式系统解决问题的常规办法 -- 增加节点 --也是于事无补的。 在这个时候,单个字段做特征值就不行了,可能得再增加一个字段作为“联合特征值”,类似数据库中的联合索引。比如,数据是用户的操作日志,可以使用id和时间戳一起作为hash函数的输入,然后算出特征值;但在这种情况下,如果还想以id为查询关键字来查询,那就得遍历所有节点了。 所以说没有最优的设计,只有最符合应用需求的设计。 下面以MongoDB中的sharding key为例,解释特征值选择的重要性以及对数据操作的影响。如果有数据库操作基础,即使没有使用过MongoDB,阅读下面的内容应该也没有问题。 以MongoDB sharding key为例 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |