zoukankan      html  css  js  c++  java
  • MongoDB 数据分发

    在MongoDB(版本 3.2.9)中,数据的分发是指将collection的数据拆分成块(chunk),分布到不同的分片(shard)上,数据分发主要有2种方式:基于数据块(chunk)数量的均衡分发和基于片键范围(range)的定向分发。MongoDB内置均衡器(balancer),用于拆分块和移动块,自动实现数据块在不同shard上的均匀分布。balancer只保证每个shard上的chunk数量大致相同,不保证每个shard上的doc数量大致相同。

    一,数据按照chunk数量进行均衡分发

    均衡分发是MongoDB自动实现的,使数据库架构对Application透明,简化系统的管理,使得向分片集群中增减分片变得容易。均衡分发是由MongoDB内置均衡器(balancer)来实现的,Balancer按照collection的索引字段来进行数据分发,该字段叫做片键(sharded key)。片键一般有三种类型:升序片键,随机片键和基于分组的片键。

    块(chunk)是由多个doc组成的一个分组,在某个索引字段(片键)上是连续的,每个chunk的片键是有一定范围的。块的默认大小是64MB。有些chunk会非常大,包含的doc数量非常多,但是,在MongoDB看来,仍然是一个chunk,和没有任何doc的空chunk没有区别。均衡分发保证每个shard的chunk数量是大致相同的。因此,片键的选择直接影响分片的好坏。

    例如:一个MongoDB分片集群有3个shard,分别是shard1,shar2,shard3。片键的最小值是:$MinKey,最大值是:$MaxKey。包含端值$MinKey的chunk是最小块,包含端值$MaxKey的chunk是最大块。

    1,升序片键

    升序片键类似date字段或者_id字段,是一种随着时间稳定增长的字段。假如分片的字段是_id字段,集合foo中存在10个doc,每个shard中存在一个数据块,分别是:chunk1:$MinKey-3,chunk2:4-8,chunk3:9-$MaxKey。

    使用升序片键的劣势是:每次插入一个新的doc,都会插入到最大块中,这会导致所有的写请求都会被路由到同一个分片,导致最大块不断增长,不断被拆分,然后不断被移动到其他分片中,导致数据的写入不均衡,块移动会额外增加Disk的写数量。使用升序片键的优势是:按照片键进行范围读时,性能高。

    2,随机片键

    随机片键是指片键的值不是固定增长,而是一些没有规律的键值。由于写入数据是随机分发的,各分片增长的速度大致相同,减少了chunk 迁移的次数。使用随机分片的弊端是:写入的位置是随机的,如果使用Hash Index来产生随机值,那么范围查询的速度会很慢。

    3,基于分组的片键

    基于分组的片键是两字段的复合片键,第一个字段用于分组,该字段的势最好是比较低的,势是在同一字段中不同值(distinct value)的数量或所占的比例;第二个字段用于自增,该字段最好是自增字段。这种片键策略是最好的,能够实现多热点数据的读写。

    单个mongod 在处理升序写请求时是最有效的,数据只需要写入到集合的末尾。基于分组的片键,将数量不多的分组分布在分片集群中,每个shard只有少量的chunk,这样能够将数据的写操作分布在分片集群中的每个shard上,在单个shard上,以升序方式读写数据。一个shard上的分组太多,写请求就相当于随机写了,反而不好。

    二,按照片键范围进行定向分发

    如果希望特定范围的chunk被分发到特定的分片中,可以为分片添加tag,然后为tag指定相应的片键范围,这样,如果一个doc属于tag的片键范围,就会被定向到特定的shard中。

    1,为shard指定tag

    sh.addShardTag("shar1","shard_tag1");
    sh.addShardTag("shar2","shard_tag2");
    sh.addShardTag("shar3","shard_tag2");

    2,为tag指定片键范围

    sh.addTagRange(
        "db_name.collection_name",
        {field:"min_value"},
        {field:"max_value"}, 
        "shard_tag"
    )

    每个shard的tag可以使用任意数量的tag,MongoDB的均衡器在移动块时,会将特定片键范围的chunk移动到特定的shard上。
    三,手动进行数据的分发

    MongoDB内置均衡器(balancer),自动实现数据块的拆分和移动,有时,可以关闭balancer,使用moveChunk命令手动移动数据块。

    1,关闭balancer

    连接到一个mongos,更新config.setting命名空间

    use config
    db.setting.update({"_id":"balancer"},{"enabled":false},true)

    --or
    sh.setBalancerState(false);

    2,拆分块
    拆分块是指新增一个边界点,将一个chunk在边界点处拆分成两个chunk。在MongoDB中,将片键从小到大排序,边界值属于右边的chunk。

    sh.splitAt("db_name.collection_name",{sharded_filed:"new_boundary_value"})

    3,移动块
    MongoDB将包含指定文档的chunk移动到指定的shard上,必须使用片键来查找所要一定的chunk。

    sh.moveChunk("db_name.collection_name",{sharded_filed:"value_in_chunk"},"new_shard_name")

    4,启用balancer

    sh.setBalancerState(true)

    5,刷新mongos的缓存

    在Application layer 和数据存储之间,存在一个Query Router,即mongos,mongos会在第一次启动或分片的元数据被更新之后,从config server 同步配置数据,并缓存在mongos中。有时,mongos无法从config server上及时同步最新的配置信息,导致无法路由到相应的chunk,不能返回正确的数据,可以使用flushRouterConfig 命令手动刷新mongos的缓存

    db.adminCommand({"flushRouterConfig":1})

    参考文档:

    Sharding

  • 相关阅读:
    揭秘淘宝286亿海量图片存储与处理架构
    从能做的事做起,做越来越多的事
    用表驱动代替switchcase
    文件过滤驱动中的重入处理
    谈谈对APC的一点理解
    StartIo例程的作用
    C++各大名库的介绍
    IRQL
    FastIO
    一道面试题,看这段代码最后抛出什么异常
  • 原文地址:https://www.cnblogs.com/ljhdo/p/5016193.html
Copyright © 2011-2022 走看看