mongoDB深入理解

来源:互联网 发布:梦幻手游 mac os 编辑:程序博客网 时间:2024/05/16 19:39

1.分片的过程

这里写图片描述

首先,在分片之前,集合是一个[minKey, maxKey] 的数据块(chunk),如图1,
然后,当写入的数据超过一定量时,就会触发 chunk 的分裂,分裂成多个数据块,如图2。
chunkSize 为默认64MB时,chunk的数量和分裂的阀值:

集合chunk数量 分裂阀值 1 1024 B [1,3) 0.5 MB [3,10) 16 MB [10,20) 32 MB [20,Max) 64 MB

chunk 分裂后,当出现各个 shard 上 chunk 分布不均衡时,就会触发 chunk 迁移。均衡器(balancer)会根据shard tag、集合的 chunk 数量、shard 间 chunk 数量差值 来决定是否需要迁移。
最后,chunk被均匀的分布在各个分片上,如图3。
针对所有启用分片的集合,如果 拥有最多数量 chunk 的 shard 与 拥有最少数量 chunk 的 shard 的差值超过某个阈值,就会触发 chunk 迁移; 有了这个机制,当用户调用 addShard 添加新的 shard,或者各个 shard 上数据写入不均衡时,balancer 就会自动来均衡数据。
chunk数量和分裂的阀值:

集合chunk数量 迁移阀值 [1,20) 2 [20,80) 4 [80,Max) 8

MongoDB 默认的 chunkSize 为64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk 分裂、迁移的行为。

2.chunkSize 对分裂及迁移的影响

  1. chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk分裂及迁移会更少,但可能导致数据分布不均。
  2. chunkSize 太小,容易出现 jumbo chunk(即shardKey 的某个取值出现频率很高,这些文档只能放到一个 chunk里,无法再分裂)而无法迁移;chunkSize 越大,则可能出现 chunk 内文档数太多(chunk 内文档数不能超过 250000)而无法迁移。
  3. chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将 chunk 分裂到指定的大小。
  4. chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但 chunk大小会随着写入不断增长,直到达到目标大小。

3.数据分片的方式

数据的分发是指将集合的数据拆分成块(chunk),分布到不同的分片(shard)上,数据分发主要有2种方式:基于数据块(chunk)数量的均衡分发和基于片键范围(range)的定向分发。2.1 基于chunk数量进行均衡分发    升序片键    升序片键类似date字段或者_id字段,是一种随着时间稳定增长的字段。假如分片的字段是_id字段,那么集合会根据_id范围被拆分为多个块,
chunks: $minKey–>Object(“……5”) Object(“……6”)–>Object(“……10”) Object(“……6”)–>Object(“……10”) Object(“……16”)–>$maxKey

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

2.2随机片键随机分发是指片键的值不是固定增长,而是一些没有规律的键值。可以是用户名、邮件地址、udid(唯一设备标识符)、md5散列值或者是数据集中其他一些没有规律的键,随着数据的不断插入,新插入的数据会比较均衡的分布在不同的块中,由于写入数据是随机分发的,各个分片增长的速度应该大致相同,这就减少了需要进行迁移的次数。随机分发片键的唯一弊端在于:mongodb在随机访问超出ram大小的数据时效率不高.如果拥有足够多的ram或者不介意系统性能的话使用随机片键在集群上分配负载时非常好的。2.3散列片键如果追求的是数据加载速度的极致,那么散列片键是最佳选择,散列片键可使其他任何键随机分发.因此打算在大量查询中使用升序键但同时又希望写入数据随机分发的话,散列片键会是非常好的选择。弊端:是无法使用散列片键做指定目标的范围查询。创建一个散列片键首先要创建散列索引 db.users,ensureIndex({"username":"hashed"}) 然后对集合分片 sh.shardConllection("app.users",{"username":"hashed"})

使用散列片键存在着一定的局限性。首先不能使用unique选项.其次,与其他片键一样,不能使用数组字段。最后注意,浮点型的值会先被取整,然后才会进行散列,所以1和1.999会得到相同的散列值。

2.4使用ShardTag,可以是用户的ip经纬度或者地址位置片键。这里不做赘述了。

3.副本集原理

副本集中数据同步过程:Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败,则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作执行多次,与执行一次的效果是一样的。简单的说就是:

当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:
1:检查自己local库的oplog.rs集合找出最近的时间戳。
2:检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
3:将找到的记录插入到自己的oplog.rs集合中,并执行这些操作。

副本集的同步和主从同步一样,都是异步同步的过程,不同的是副本集有个自动故障转移的功能。其原理是:slave端从primary端获取日志,然后在自己身上完全顺序的执行日志所记录的各种操作(该日志是不记录查询操作的),这个日志就是local数据 库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参数中设 定:–oplogSize 1000,单位是M。

  注意:在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务。

本文结合众多资料整合

原创粉丝点击