【分享】使用组合索引做shard key可以大幅度提高集群性能


  • 註冊用戶

    “固定值+增量值” 两字段做组合索引可以有效的实现分布式集群中的分散多热点写入、读取。以下为读书笔记: 在单个MongoDB实例上,最高效的写入是顺序写入,而MongoDB集群则要求写入能随机,以便平均分散到多个MongoDB实例。所以最高效的写入是有多个局部热点:在多个MongoDB实例之间是分散写入,在实例内部是顺序写入。 要实现这一点,我们采用组合索引。 例如:shardkey的第一部分是很粗糙的,可选集很少的字段,索引的第二部分是递增字段,当数据增加到一定程度时,会出现很多第一部分相同第二部分不同的chunk,数据只会在最后一个chunk里写入数据,当第一部分不同的chunk分散在多个shard上,就实现了多热点的写入。如果在一个shard上,不止一个chunk可以写入数据,那也就是说不止一个热点,当热点非常多的时候,也就等同于无热点的随机写入。当一个chunk分裂之后,只能有一个成为热点,另一个不能再被写入,否则就会产生两个热点,不再写入的chunk也就是死掉了,后续只会对它有读操作。

    最典型的应用是具有日期属性的日志处理,shard key选择“日期+用户ID”组合,保证了数据写入时的局部热点(一个shard上只有少数几个chunk被写入,避免随机IO)和全局分散(所有的shard上都有写入数据,充分利用磁盘IO)。 我在实践中除了书中讲到的组合键方式外,还加上了预分片策略,避免了早期数据增长过程中的分片和数据迁移。另外还尽可能的制造能利用局部性原理的数据写入,例如在数据写入之前先对数据排序,有大约30%左右的update性能提升。

    预分片是这样子做的:根据组合shardkey信息先分裂好chunk,把这些空chunk移动到各个shard上,避免了后续自动分裂引起的数据迁移。

    good case:

    环境:一台机器、7分片、MongoDB2.6版本、shard key选择“日期+用户ID组合”,

    数据:写入使用批量插入,对10亿条日志级分片集群的写入,写入1000W条日志只需要35分钟,每条日志约0.11K。

    bad case:

    环境:3台机器、18分片、MongoDB2.6版本、shard key选择 _id的hashid

    数据:写入采用批量插入,对3亿条日志级分片集群的写入,写入300W条日志耗时35分钟,每条日志约0.11K。

    从对比可以看到,在数据量比较大的情况下选择组合索引做shard key性能明显优于选择hashid。

    我在实际应用中还遇到选择hashid的更极端情况:对3条机器&18分片&3亿条日志集群每天写入300W条日志,耗时170分钟,每条日志约4K。每次写入数据时,所有分片磁盘IO使用率都达到100%。

    附创建组合索引和使用组合索引做shard key 的 mongo shell代码:

    xx> db.cswuyg.ensureIndex({'code':1, 'insert_time':1})

    xx> use admin

    admin> db.runCommand({"enablesharding":"xx"})

    admin> db.runCommand({"shardcollection":"xx.cswuyg","key":{'code':1, 'insert_time':1}})

     

    参考:《MongoDB——The Definitive Guide 2nd Edition》 page268


登录后回复
 

与 萌阔论坛 的连接断开,我们正在尝试重连,请耐心等待