MongoDB 哈希分片为什么数据大小不均匀?

今天接到一个用户反馈的问题,sharding集群,使用wiredtiger引擎,某个DB下集合全部用的hash分片,show dbs 发现其中一个shard里该DB的大小,跟其他的集合差别很大,其他基本在60G左右,而这个shard在200G左右?

由于这个DB下有大量的集合及索引,一眼也看不出问题,写了个脚本分析了一下,得到如下结论

  1. somedb 下所有集合都是hash分片,并且chunk的分布是比较均匀的
  2. show dbs 反应的是集合及索引对应的物理文件大小
  3. 集合的数据在各个shard上逻辑总大小是接近的,只有shard0占用的物理空间比其他大很多

从shard0上能找到大量 moveChunk 的记录,猜测应该是集合的数据在没有开启分片的情况下写到shard0了,然后开启分片后,从shard0迁移到其他shard了,跟用户确认的确有一批集合是最开始没有分片。

所以这个问题就转换成了,为什么复制集里集合的逻辑空间与物理空间不一致?即collection stat 里 sizestorageSize 的区别。

mymongo:PRIMARY> db.coll.stats()
{
    "ns" : "test.coll",
    "size" : 30526664,
    "count" : 500808,
    "avgObjSize" : 33,
    "storageSize" : 19521536,
    "capped" : false,
    ....
}

逻辑存储空间与物理存储空间有差距的主要原因

  1. 存储引擎存储时,需要记录一些额外的元数据信息,这会导致物理空间总和比逻辑空间略大
  2. 存储引擎可能支持数据压缩,逻辑的数据块存储到磁盘时,经过压缩可能比逻辑数据小很多了(具体要看数据的特性,极端情况下压缩后数据变大也是有可能的)
  3. 引擎对删除空间的处理,很多存储引擎在删除数据时,考虑到效率,都不会立即去挪动数据回收删除的存储空间,这样可能导致删除很多文档后,逻辑空间变小,但物理空间并没有变小。如下图所示,灰色的文档删除表示被删除。删除的空间产生很多存储碎片,这些碎片空间不会立即被回收,但有新文档写入时,可以立即被复用。

而上述case里,集合数据先分到一个shard,然后启用分片后,迁移一部分到其他shard,就是一个典型的产生大量存储碎片的例子。存储碎片对服务通常影响不大,但如果因为空间不够用了需要回收,如何去强制的回收这些碎片空间?

  • 数据清理掉重新加入复制集同步数据,或者直接执行resync命令 (确保有还有其他的数据备份)
  • 对集合调用 compact 命令


2017-08-03 15:42:04 update

关于 compact操作,有同学问道,问题链接

mongdb中由于删除了大量的数据,但是没有释放磁盘空间给系统,想通过compact命令来释放磁盘空间;但是对compact命令有几个疑问
1. compact命令在WiredTiger引擎上是库级别锁还是collection级别锁?
2. 执行compact命令需要多大的空余磁盘空间呢

  • compact 加的是DB级别的互斥写锁,同一个DB上的读写都会被阻塞
  • compact基本不需要额外的空间,wiredtiger compact的原理是将数据不断往前面的空洞挪动,并不需要把数据存储到临时的位置(额外的存储空间)。

参考资料

时间: 2024-12-09 00:01:45

MongoDB 哈希分片为什么数据大小不均匀?的相关文章

Mongodb 删除添加分片与非分片表维护_MongoDB

MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 一.如何移除分片 1.确认balancer已经开启 mongos> sh.getBalancerState() true 2.移除分片 注:在admin db下执行命令. mongos> use admin switched to db admin mon

PHP实现格式化文件数据大小显示的方法

 这篇文章主要介绍了PHP实现格式化文件数据大小显示的方法,通过一个自定义函数实现针对文件大小的精确格式化,具有一定的参考借鉴价值,需要的朋友可以参考下     本文实例讲述了PHP实现格式化文件数据大小显示的方法.分享给大家供大家参考.具体分析如下: 有时候我们需要在网页上显示某个文件的大小,或者是其它数据的大小数字. 这个数字往往从跨度很大,如果以B为单位的话可能是个位,如果1G则长达1073741824的数字,这个时候我们就需要根据大小来格式化,比如小于1K则以B为单位显示,小于1M则以K

分片 副本-分布式存储中的数据分片和数据主副本的作用

问题描述 分布式存储中的数据分片和数据主副本的作用 分布式存储中需要对数据进行分片,假设一个数据到来后,分成 A, B, C三片,分别存放在不同的节点上,并且每个分片都有三个副本. 问题1:分片的作用是什么?是不是提升数据的读写速度?如果一个数据本来就很小,比如每个节点都是一个KV数据库,存放的KV键值对都不大于1KB,那还需要分片的必要吗? 当然主副本就是防止放生故障时能够继续为客户服务的. 问题2:分片和副本之间存放的节点有什么必要的关系吗?是不是一个分片的副本和其他的分片存放在同一个节点上

mysql查询数据,比较数据大小

问题描述 mysql查询数据,比较数据大小 我现在碰到的问题: 在一个列的信息中查处2013年6月8日前的信息(该列值是一个varchar2类型,而且值中的第2位为年,第3位为月,第4位为日信息).而2013使用N表示(2000年开始用字母A,B.C...表示),月份超过10的用字母A,B...表示,日期超过10的也用A,B...表示 我要怎么使用MYSQL语句直接查出数据呢(是mysql,不是oracle),数据可能有一百多万笔... 如:NN68KKKKKKKK这个值表示是2013年6月8号

php 将文件里面的数据大小限制为1M,超过1M则显示最近1M的数据

问题描述 php 将文件里面的数据大小限制为1M,超过1M则显示最近1M的数据 php file_put_contents生成一个文件,将文件里面的数据大小限制为1M,超过1M则显示最近1M的数据 解决方案 获取文件长度,如果超过1M,从文件长度-1M处读取

用java来操作mongoDB,备份mongDB中的数据

问题描述 用java来操作mongoDB,备份mongDB中的数据 come on 大神 如题 现在想每个月把数据库中的数据导出来做备份 , 怎么用java语言来实现呢 ? 谢啦!!! 解决方案 omg 我在顶顶吧 解决方案二: 写一个quartz的定时任务管理, 然后创建一个机遇每月月初几点几分执行的任务... 然后就是执行你需要的业务逻辑,如果比较复杂的话,就使用异步来实现. 最后记得生成一份日志或者报表用于查看数据备份后的一些结果输出信息... 大致的思路是这样的

web前端-怎么用js来获取网页元素,请求响应事件和返回数据大小

问题描述 怎么用js来获取网页元素,请求响应事件和返回数据大小 如图那样..不要使用后台,直接用jq来抓取,可不可行??领导说不能用后台语言来实现..本来用C#做好了的,现在又要重新做过 解决方案 js不是有函数什么的,利用js语法应该可以的

mongodb移除分片

MongoDB的Shard集群来说,添加一个分片很简单,AddShard就可以了. 但是缩减集群(删除分片)这种一般很少用到.由于曙光的某服务器又挂了,所以我们送修之前必须把它上面的数据自动迁移到其他Shard上.  1.执行RemoveShard命令 1 db.runCommand( { removeshard: "your_shard_name" } ) 2 3 { msg : "draining started successfully" , state: &

CentOS6配置安装MongoDB及主从同步与数据备份与恢复

=== 安装.配置 ===  代码如下 复制代码 #下载源码包 cd /usr/local/src/mongodb wget -c http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.2.7.tgz #解压.把bin文件夹拷贝到指定目录 /usr/local/mongodb tar -xzvf ./mongodb-linux-x86_64-2.2.7.tgz cd ./mongodb-linux-x86_64-2.2.7 mkdir /u