zoukankan      html  css  js  c++  java
  • Mongo实战之数据空洞的最佳实践

    问题背景: 某天,开发部的同事跑过来反映: mongodb数据文件太大,快把磁盘撑爆了!其中某个db占用最大(运营环境这个db的数据量其实很小)

    分析: 开发环境有大量测试的增/删/改操作,而由于MongoDB顺序写的原因,在我们删除部分无用数据后,它的storageSize并不会变小,这就造成了大量的数据空洞。

    解决办法

    1. 使用MongoDB自带的compact命令:

      db.collectionName.runCommand(“compact”)
     这种方式是collection级别的压缩,只能去除collection内的碎片。但是MongoDB的数据分配是DB级别的,效果有限。
     这个压缩是线上压缩,磁盘IO会比较高,从而影响线上服务。
    

    2.采用复制集的方式滚动瘦身(offline)

    1.检查服务器各节点是否正常运行 (ps -ef |grep mongod)
    2.登入要处理的主节点,做降权处理rs.stepDown(),并通过命令 rs.status()来查看是否降权
    3.切换成功之后,停掉该节点,删除数据文件,比如: rm -fr /mongodb/data/*
    4.重新启动该节点,执行重启命令,比如:如:/mongodb/bin/mongod --config /mongodb/mongodb.conf
    5.通过日志查看进程以及数据同步的进度
    6.数据同步完成后,在修改后的主节点上执行命令 rs.stepDown(),做降权处理。
    
    通过这种方式,可以做到收缩率是100%,数据完全无碎片.当然也会带来运维成本的增加,并且在Replic-Set集群只有2个副本的情况下,
    还会存在一段时间内的单点风险(在下面的实验中就发生了这样的情况)。通过Offline的数据收缩后,收缩前后效果非常明显.
    

    系统环境(实验环境,为了简单只做了1个副本,请勿在生产环境操作!!!)

    主库: 192.168.2.130:27017
    从库: 192.168.2.138:27017
    

    1.安装mongo

    2.配置参数(两台上配置)

    [root@localhost bin]# vi mongodb.conf
    
    dbpath=/u01/mongodb/data
    port=27017
    oplogSize = 2048
    logpath=/u01/mongodb/logs/mongodb.log
    logappend = true
    fork = true
    nojournal = true
    bind_ip=0.0.0.0
    shardsvr=true
    replSet=relp1
    

    3.启动mongo

    [root@localhost bin]# ./mongod --config ./mongodb.conf
    

    4.初始化副本集

    [root@localhost bin]# ./mongo  192.168.2.130:27017
    
    > cfg = {"_id":"repl1","members":[ {"_id":0, "host":"192.168.2.130:27017"}, {"_id":1, "host":"192.168.2.138:27017"}]}; 
    {
    		"_id" : "repl1",
    		"members" : [
    				{
    						"_id" : 0,
    						"host" : "192.168.2.130:27017"
    				},
    				{
    						"_id" : 1,
    						"host" : "192.168.2.138:27017"
    				}
    		]
    }
    >  
    > rs.initiate(cfg)rs.initiate(cfg)
    { "ok" : 1 }
    

    5.插入数据

    #准备工作 安装pip工具 pymongo
    [root@localhost mongodb]# tar zxvf setuptools-0.6c11.tar.gz
    [root@localhost mongodb]# cd setuptools-0.6c11
    [root@localhost mongodb]# python setup.py install
    
    [root@localhost mongodb]# wget "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz#md5=834b2904f92d46aaa333267fb1c922bb" --no-check-certificate
    [root@localhost mongodb]# tar zxvf [root@localhost mongodb]# tar pip-1.5.4.tar.gz
    [root@localhost mongodb]# cd pip-1.5.4
    [root@localhost pip-1.5.4]# python setup.py install
    
    
    [root@localhost mongodb]# pip install pymongo
    
    #插入脚本
    vi insert.py
    #!/usr/bin/python
    import random
    from pymongo import MongoClient
    
    client = MongoClient('192.168.2.137', 27017)
    
    test = client.test
    students = test.students
    students_count = students.count()
    print "student count is ", students_count
    
    for i in xrange(0,5000000):
    	classid = random.randint(1,4)
    	age = random.randint(10, 30)
    	student = {"classid":classid, "age":age,
    "name":"fujun"}
    	students.insert_one(student)
    	print i
    
    students_count = students.count()
    print "student count is ", students_count
    
    #执行插入,可以开多个窗口执行
    [root@localhost mongodb]#python insert.py
    
    #插入完毕 2kw条记录
    repl1:PRIMARY> db.students.find().count() 
    21511778
    
    #查看复制集状态
    repl1:PRIMARY> rs.status()rs.status()
    {
    		"set" : "repl1",
    		"date" : ISODate("2018-03-17T02:42:01.126Z"),
    		"myState" : 1,
    		"term" : NumberLong(3),
    		"heartbeatIntervalMillis" : NumberLong(2000),
    		"members" : [
    				{
    						"_id" : 0,
    						"name" : "192.168.2.130:27017",
    						"health" : 1,
    						"state" : 1,
    						"stateStr" : "PRIMARY",
    						"uptime" : 60089,
    						"optime" : {
    								"ts" : Timestamp(1521231587, 19),
    								"t" : NumberLong(3)
    						},
    						"optimeDate" : ISODate("2018-03-16T20:19:47Z"),
    						"electionTime" : Timestamp(1521213635, 1),
    						"electionDate" : ISODate("2018-03-16T15:20:35Z"),
    						"configVersion" : 1,
    						"self" : true
    				},
    				{
    						"_id" : 1,
    						"name" : "192.168.2.138:27017",
    						"health" : 1,
    						"state" : 2,
    						"stateStr" : "SECONDARY",
    						"uptime" : 40892,
    						"optime" : {
    								"ts" : Timestamp(1521231587, 19),
    								"t" : NumberLong(3)
    						},
    						"optimeDate" : ISODate("2018-03-16T20:19:47Z"),
    						"lastHeartbeat" : ISODate("2018-03-17T02:42:01Z"),
    						"lastHeartbeatRecv" : ISODate("2018-03-17T02:42:00.376Z"),
    						"pingMs" : NumberLong(1),
    						"syncingTo" : "192.168.2.130:27017",
    						"configVersion" : 1
    				}
    		],
    		"ok" : 1
    }
    
    #查看storageSize和fileSize:
    repl1:PRIMARY> db.stats() 
    {
    		"db" : "test",
    		"collections" : 1,
    		"objects" : 21511778,
    		"avgObjSize" : 60,
    		"dataSize" : 1290706680,
    		"storageSize" : 410132480,
    		"numExtents" : 0,
    		"indexes" : 1,
    		"indexSize" : 217350144,
    		"ok" : 1
    }
    
    #storageSize = dataSize+size(删除的文档)(文档删除后,storageSize并不会变小)。
    

    6.制造空洞数据

    #删除3/4数据
    repl1:PRIMARY> db.students.remove({"classid":{"$lt":4}}) 
    
    WriteResult({ "nRemoved" : 9050980 })
    
    #还剩下500w
    repl1:PRIMARY> db.students.find().count()db.students.find().count()
    5376340
    
    
    #storageSize没有变下。
    repl1:PRIMARY>db.stats()
    {
    		"db" : "test",
    		"collections" : 1,
    		"objects" : 5376340,
    		"avgObjSize" : 60,
    		"dataSize" : 322580400,
    		"storageSize" : 425127936,
    		"numExtents" : 0,
    		"indexes" : 1,
    		"indexSize" : 219590656,
    		"ok" : 1
    }
    

    7.primary降权、停止

    repl1:PRIMARY> rs.setrs.sers.stepDown()rs.stepDown()
    2018-03-17T13:46:49.588+0800 E QUERY    [thread1] Error: error doing query: failed: network error while attempting to run command 'replSetStepDown' on host '192.168.2.130:27017'  :
    DB.prototype.runCommand@src/mongo/shell/db.js:135:1
    DB.prototype.adminCommand@src/mongo/shell/db.js:153:16
    rs.stepDown@src/mongo/shell/utils.js:1202:12
    @(shell):1:1
    
    2018-03-17T13:46:49.600+0800 I NETWORK  [thread1] trying reconnect to 192.168.2.130:27017 (192.168.2.130) failed
    2018-03-17T13:46:49.618+0800 I NETWORK  [thread1] reconnect 192.168.2.130:27017 (192.168.2.130) ok
    repl1:SECONDARY> 
    
    #停止192.168.2.130
    [root@localhost mongodb]# mongod --shutdown --config=/u01/mongodb/mongodb.conf
    killing process with pid: 32322
    

    8.删除192.168.2.130 上的数据文件

    [root@localhost data]# rm -rf /u01/mongodb/data/*
    

    9.重启192.168.2.130

    [root@localhost data]# mongod  --config=/u01/mongodb/mongodb.conf
    about to fork child process, waiting until server is ready for connections.
    forked process: 48079
    child process started successfully, parent exiting
    

    10.查看日志,跟踪数据同步过程

    [root@localhost mongodb]# cd /u01/mongodb/logs/
    [root@localhost logs]# tail -50f  mongodb.log
    
    2018-03-17T13:53:31.077+0800 I REPL     [replExecDBWorker-0] Starting replication applier threads
    2018-03-17T13:53:31.077+0800 I REPL     [ReplicationExecutor] 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] ** WARNING: This replica set is running without journaling enabled but the 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] **          writeConcernMajorityJournalDefault option to the replica set config 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] **          is set to true. The writeConcernMajorityJournalDefault 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] **          option to the replica set config must be set to false 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] **          or w:majority write concerns will never complete.
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] 
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] New replica set config in use: { _id: "repl1", version: 1, protocolVersion: 1, members: [ { _id: 0, host: "192.168.2.130:27017", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 }, { _id: 1, host: "192.168.2.138:27017", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 } ], settings: { chainingAllowed: true, heartbeatIntervalMillis: 2000, heartbeatTimeoutSecs: 10, electionTimeoutMillis: 10000, getLastErrorModes: {}, getLastErrorDefaults: { w: 1, wtimeout: 0 }, replicaSetId: ObjectId('5aab9f92276e84b589038188') } }
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] This node is 192.168.2.130:27017 in the config
    2018-03-17T13:53:31.078+0800 I REPL     [ReplicationExecutor] transition to STARTUP2
    2018-03-17T13:53:31.079+0800 I REPL     [rsSync] ******
    2018-03-17T13:53:31.079+0800 I REPL     [rsSync] creating replication oplog of size: 2048MB...
    2018-03-17T13:53:31.298+0800 I REPL     [ReplicationExecutor] Member 192.168.2.138:27017 is now in state SECONDARY
    2018-03-17T13:53:31.915+0800 I STORAGE  [rsSync] Starting WiredTigerRecordStoreThread local.oplog.rs
    2018-03-17T13:53:31.915+0800 I STORAGE  [rsSync] The size storer reports that the oplog contains 0 records totaling to 0 bytes
    2018-03-17T13:53:31.916+0800 I STORAGE  [rsSync] Scanning the oplog to determine where to place markers for truncation
    2018-03-17T13:53:34.635+0800 I REPL     [rsSync] ******
    2018-03-17T13:53:34.635+0800 I REPL     [rsSync] initial sync pending
    2018-03-17T13:53:37.219+0800 I REPL     [ReplicationExecutor] syncing from: 192.168.2.138:27017
    2018-03-17T13:53:39.164+0800 I REPL     [rsSync] initial sync drop all databases
    2018-03-17T13:53:39.165+0800 I STORAGE  [rsSync] dropAllDatabasesExceptLocal 1
    2018-03-17T13:53:39.165+0800 I REPL     [rsSync] initial sync clone all databases
    2018-03-17T13:53:39.281+0800 I REPL     [rsSync] fetching and creating collections for test
    2018-03-17T13:53:47.061+0800 I REPL     [rsSync] initial sync cloning db: test
    2018-03-17T14:19:07.020+0800 I STORAGE  [rsSync] clone test.students 70015
    2018-03-17T14:19:07.021+0800 I STORAGE  [rsSync] 70105 objects cloned so far from collection test.students
    2018-03-17T14:20:34.083+0800 I STORAGE  [rsSync] 139955 objects cloned so far from collection test.students
    2018-03-17T14:20:34.084+0800 I STORAGE  [rsSync] clone test.students 140031
    2018-03-17T14:21:38.094+0800 I STORAGE  [rsSync] 489459 objects cloned so far from collection test.students
    2018-03-17T14:21:38.094+0800 I STORAGE  [rsSync] clone test.students 489471
    2018-03-17T14:22:51.519+0800 I STORAGE  [rsSync] 769113 objects cloned so far from collection test.students
    2018-03-17T14:22:51.519+0800 I STORAGE  [rsSync] clone test.students 769151
    2018-03-17T14:24:07.410+0800 I STORAGE  [rsSync] 978790 objects cloned so far from collection test.students
    2018-03-17T14:24:07.410+0800 I STORAGE  [rsSync] clone test.students 978815
    2018-03-17T14:25:10.198+0800 I STORAGE  [rsSync] 1468121 objects cloned so far from collection test.students
    2018-03-17T14:25:10.198+0800 I STORAGE  [rsSync] clone test.students 1468159
    2018-03-17T14:25:44.018+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:48042 #7 (4 connections now open)
    2018-03-17T14:26:01.100+0800 I NETWORK  [conn5] end connection 127.0.0.1:48032 (3 connections now open)
    2018-03-17T14:26:01.100+0800 I NETWORK  [conn7] end connection 127.0.0.1:48042 (3 connections now open)
    2018-03-17T14:26:16.318+0800 I STORAGE  [rsSync] 1887602 objects cloned so far from collection test.students
    2018-03-17T14:26:16.318+0800 I STORAGE  [rsSync] clone test.students 1887615
    2018-03-17T14:27:19.201+0800 I STORAGE  [rsSync] clone test.students 2307071
    2018-03-17T14:27:19.201+0800 I STORAGE  [rsSync] 2307083 objects cloned so far from collection test.students
    2018-03-17T14:28:22.898+0800 I STORAGE  [rsSync] clone test.students 3145855
    2018-03-17T14:28:22.899+0800 I STORAGE  [rsSync] 3145918 objects cloned so far from collection test.students
    2018-03-17T14:29:25.991+0800 I STORAGE  [rsSync] 3565272 objects cloned so far from collection test.students
    2018-03-17T14:29:25.991+0800 I STORAGE  [rsSync] clone test.students 3565311
    2018-03-17T14:30:28.780+0800 I STORAGE  [rsSync] 3984753 objects cloned so far from collection test.students
    2018-03-17T14:30:28.780+0800 I STORAGE  [rsSync] clone test.students 3984767
    2018-03-17T14:31:28.001+0800 I STORAGE  [rsSync] clone test.students 4667519
    2018-03-17T14:31:29.457+0800 I STORAGE  [rsSync] 4683761 objects cloned so far from collection test.students
    2018-03-17T14:32:34.884+0800 I STORAGE  [rsSync] clone test.students 5103231
    2018-03-17T14:32:34.884+0800 I STORAGE  [rsSync] 5103242 objects cloned so far from collection test.students
    2018-03-17T14:33:46.017+0800 I STORAGE  [rsSync] 5452746 objects cloned so far from collection test.students
    2018-03-17T14:33:46.017+0800 I STORAGE  [rsSync] clone test.students 5452799
    2018-03-17T14:34:47.770+0800 I STORAGE  [rsSync] clone test.students 5872127
    2018-03-17T14:34:47.770+0800 I STORAGE  [rsSync] 5872227 objects cloned so far from collection test.students
    2018-03-17T14:35:52.885+0800 I STORAGE  [rsSync] 6291581 objects cloned so far from collection test.students
    2018-03-17T14:35:52.885+0800 I STORAGE  [rsSync] clone test.students 6291583
    2018-03-17T14:36:57.050+0800 I STORAGE  [rsSync] 6571235 objects cloned so far from collection test.students
    2018-03-17T14:36:57.050+0800 I STORAGE  [rsSync] clone test.students 6571263
    2018-03-17T14:37:59.514+0800 I STORAGE  [rsSync] 8248905 objects cloned so far from collection test.students
    2018-03-17T14:37:59.515+0800 I STORAGE  [rsSync] clone test.students 8248959
    2018-03-17T14:38:37.698+0800 I INDEX    [rsSync] build index on: test.students properties: { v: 1, key: { _id: 1 }, name: "_id_", ns: "test.students" }
    2018-03-17T14:38:37.698+0800 I INDEX    [rsSync]         building index using bulk method; build may temporarily use up to 500 megabytes of RAM
    2018-03-17T14:38:40.000+0800 I -        [rsSync]   Index Build: 1511900/12074974 12%
    2018-03-17T14:38:43.000+0800 I -        [rsSync]   Index Build: 3571300/12074974 29%
    2018-03-17T14:38:46.000+0800 I -        [rsSync]   Index Build: 5640600/12074974 46%
    2018-03-17T14:38:49.001+0800 I -        [rsSync]   Index Build: 7599000/12074974 62%
    2018-03-17T14:38:52.001+0800 I -        [rsSync]   Index Build: 9471000/12074974 78%
    2018-03-17T14:38:55.001+0800 I -        [rsSync]   Index Build: 11341800/12074974 93%
    2018-03-17T14:39:27.000+0800 I -        [rsSync]   Index: (2/3) BTree Bottom Up Progress: 8961500/12074974 74%
    2018-03-17T14:39:30.222+0800 I INDEX    [rsSync]         done building bottom layer, going to commit
    2018-03-17T14:39:31.465+0800 I NETWORK  [initandlisten] connection accepted from 192.168.2.138:50802 #8 (3 connections now open)
    2018-03-17T14:39:31.960+0800 I COMMAND  [conn1] command local.replset.election command: replSetRequestVotes { replSetRequestVotes: 1, setName: "repl1", dryRun: false, term: 212, candidateIndex: 1, configVersion: 1, lastCommittedOp: { ts: Timestamp 1521264812000|7795, t: 193 } } keyUpdates:0 writeConflicts:0 numYields:0 reslen:63 locks:{ Global: { acquireCount: { r: 4, w: 2 } }, Database: { acquireCount: { r: 1, W: 2 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_command 3219ms
    2018-03-17T14:39:31.983+0800 I INDEX    [rsSync] build index done.  scanned 12074974 total records. 54 secs
    2018-03-17T14:39:31.984+0800 I REPL     [rsSync] initial sync data copy, starting syncup
    2018-03-17T14:39:31.984+0800 I REPL     [rsSync] oplog sync 1 of 3
    2018-03-17T14:39:32.797+0800 I REPL     [ReplicationExecutor] syncing from: 192.168.2.138:27017
    2018-03-17T14:39:33.749+0800 I REPL     [ReplicationExecutor] Member 192.168.2.138:27017 is now in state PRIMARY
    2018-03-17T14:46:16.481+0800 I REPL [rsSync] oplog sync 2 of 3
    2018-03-17T14:46:16.708+0800 I REPL [rsSync] initial sync building indexes
    2018-03-17T14:46:16.708+0800 I REPL [rsSync] initial sync cloning indexes for : test
    2018-03-17T14:46:17.236+0800 I STORAGE  [rsSync] copying indexes for: { name: "students", options: {} }
    2018-03-17T14:46:19.079+0800 I REPL [rsSync] oplog sync 3 of 3
    2018-03-17T14:46:19.083+0800 I REPL [rsSync] initial sync finishing up
    2018-03-17T14:46:19.483+0800 I REPL [rsSync] initial sync done
    2018-03-17T14:46:19.491+0800 I REPL [rsSync] initial sync succeeded after 1 attempt(s).
    2018-03-17T14:46:19.491+0800 I REPL [ReplicationExecutor] transition to RECOVERING
    2018-03-17T14:46:19.495+0800 I REPL [ReplicationExecutor] transition to SECONDARY
    

    由日志中可以看到,同步花了很长时间,原因:

    1.192.168.2.130降级前,复制集的同步是没有完成的,这导致了降级后,192.168.2.138并没有升级为primary,这样就造成了单点故障!
    2.192.168.2.130删除数据重启后,192.168.2.138继续做delete同步操作,130的状态为startup2
    3.192.168.2.138删除数据完毕后(由于没有同步完全,130上的数据文件被删除了,导致138上最终的数据不是最新的!),
      然后才成为primary
    
    repl1:PRIMARY> db.students.find().count()
    12074974
    

    通过查询结果,可以看到数据不是最新的,新数据应该至于500w条,也证明了mongo复制集是异步的,降级的时候应该观察副本数据库的状态!!!

    后面又做了一次删除,并跟踪了副本的同步情况,这次切换时间就变得很短了,并且文件大小下降的十分可观!

    11. 再次查看storageSize,下降十分明显

    repl1:PRIMARY> db.stats() 
    {
    		"db" : "test",
    		"collections" : 2,
    		"objects" : 5376341,
    		"avgObjSize" : 60.000029946017186,
    		"dataSize" : 322580621,
    		"storageSize" : 102256640,
    		"numExtents" : 0,
    		"indexes" : 2,
    		"indexSize" : 54321152,
    		"ok" : 1
    }
    

    12. 192.168.2.138降权

    repl1:PRIMARY>rs.stepDown()
    2018-03-17T02:51:29.554-0400 E QUERY    [thread1] Error: error doing query: failed: network error while attempting to run command 'replSetStepDown' on host '127.0.0.1:27017'  :
    DB.prototype.runCommand@src/mongo/shell/db.js:135:1
    DB.prototype.adminCommand@src/mongo/shell/db.js:153:16
    rs.stepDown@src/mongo/shell/utils.js:1202:12
    @(shell):1:1
    
    2018-03-17T02:51:29.652-0400 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
    2018-03-17T02:51:29.791-0400 I NETWORK  [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) ok
    

    13. 重复130的操作收缩138的空间

  • 相关阅读:
    ReactNative--Flexbox布局
    ReactNative--资源,文章,等等
    ReactNative--坑--no bundle URL present
    ReactNative--StyleSheet样式表
    ReactNative--项目创建及结构分析
    ReactNative--ReactNative简介
    10-4路径文字排版 这一节完全不明白
    10-3区域文字排版
    10-2使用字符调板
    10-1使用文字工具
  • 原文地址:https://www.cnblogs.com/chinesern/p/8602239.html
Copyright © 2011-2022 走看看