> 数据库 > MongoDB >

MongoDB实战 : 操作性很强的入门手记

./mongo --port 27017
show dbs ----已有数据库列表
show collections ---- 已有集合列表
show users ----已有用户列表
use dbname ---- 切换数据库,系统会自动延迟创建该数据库
db.account.save({'name':'test','addr':'china'}) -- 创建集合
db.account.find() -- 查看集合数据
db.dropDatabase() -- 删除数据库
数据库组件:mongod、mongos、mongo  
数据库工具:
mongodump -h dbhost -d dbname -o dbdirectory -- 数据库备份
mongorestore -h dbhost -d dbname --directoryperdb dbdirectory -- 数据库恢复
./bsondump dump/bbs/account.bson -- 查看bson对象
./mongoexport -d bbs -c account -q {} -f name,addr --csv > account.csv   -- 数据导出工具,导出为csv格式
./mongoexport -d bbs -c account -q {} -f name,addr  > account.json 导出为json格式
./mongoexport -d bbs -c account -q '{"name":"test2"}' -f name,addr --csv > account.csv 带查询条件导出
./mongoimport -d bbs -c account --type csv --headerline  --drop < account.csv  -- 数据导入工具,导入csv文件
./mongoimport -d bbs -c account --type json  --drop < account.json--导入json文件
===================文档插入=======================
单个文档插入:db.account.insert({"userName" : "bbs10000001", "passwd" : "ddddddd", "acctAttr" : null })
===============文档删除=============
删除文档中所有数据:db.account.remove(),不删除索引
条件删除:db.account.remove({"userName":"bbs1100"})
删除整个集合:db.account.drop()。数据、索引一起删除,性能好
=============文档更新=====================
更新命令:db.account.update({"userName":"bbs10"},{ "_id" : "3e1fd26f4b0f8351760fcc54", "userName" : "bbs10", "passwd" : "fff", "acctAttr" : null })
$set用法,使用修改器进行局部更改:db.account.update({"_id" : "3e1fd26f4b0f8351760fcc54"},{ "$set":{"passwd":"d"}})
去掉一个键:db.account.update({"userName":"bbs10"},{ "$unset":{"passwd":1}})
$inc用法,db.account.update({"userName":"bbs10"},{ "$inc":{"age":30}})
加1:db.account.update({"userName":"bbs10"},{ "$inc":{"age":1}})
减1:db.account.update({"userName":"bbs10"},{ "$inc":{"age":-1}})
$inc的键值必须为数值。
数组修改器$push。db.account.update({"userName":"bbs10"},{$push:{"email":"1@163.com"}})
$addToSet避免重复加入:db.account.update({"userName":"bbs10"}},{$addToSet:{"email":"4@163.com"}})
pop修改器:db.account.update({"userName":"bbs10"},{$pop:{"email":1}})  从数组尾删除一个元素
从数组头删除一个元素:db.account.update({"userName":"bbs10"},{$pop:{"email":-1}}) 
指定位置删除删除元素:db.account.update({"userName":"bbs10"},{$pull:{"email":"2@163.com"}})
多文档更新:db.account.update({"userName":"bbs10"},{$set:{"passwd":"a"}},false,true)
看执行结果,有多少文档被更新:db.runCommand({getLastError:1})
执行getLastError时,驱动程序会等待数据库返回结果
=====================查询========基础查询find命令==================
查询集合所有文档:db.account.find()
简单条件查询:db.account.find({"userName":"bbs10"})
多值匹配条件查询,类似"条件1 and 条件2":
db.account.find({"userName":"bbs10","passwd":"ddd"})
指定返回某些键:db.account.find({},{"userName":1,"passwd":1})
db.account.find({},{"passwd":0})
db.account.find({},{"userName":1,"_id":0})
=====================查询========复合条件查询==================
比较操作符lt、lte、gt、gte、ne分别对应<、<=、>、>=、!=
db.account.insert({"userName":"bbs2000000","age":30,"createTime":new Date()})
db.account.find({"createTime":{"$gt":start}})
db.account.find({"age":{"$gt":30,"$lt":40}})
db.account.find({"age":{"$ne":30}})
$in查询:db.account.find({"age":{"$in":[30,32]}})
db.account.find({"age":{"$nin":[30,32]}})
$or 或查询,可多键值或查询:db.account.find({"$or":[{"userName":"bbs2000000"},{"age":32}]})
组合查询db.account.find({"$or":[{"userName":"bbs2000000"},{"age":{"$in":[30,32]}}]})
$not运算符,可运用于任何条件之上,表示取非:db.account.find({"age":{"$not":{"$nin":[30,32]}}})
$mod模运算:db.account.find({"age":{"$mod":[5,0]}})
=====================查询========高级查询规则-null=================
null不仅匹配自身,还匹配不存在db.account.find({"createTime":null})
要结合$exist才能准确查出属性为null的文档:
db.account.find({"createTime":{"$in":[null],"$exists":true}})
====================查询=======正则表达式==================
正则表达式规则遵循javascript正则表达式规则db.account.find({"userName":/bbs200000/i})
带前缀正则表达式查询性能最好:db.account.find({"userName":/^bbs200000/i})
=====================查询========查询数组==================
db.food.insert({"_id":1,"fruit":["apple","banana","peach"]})
db.food.insert({"_id":2,"fruit":["apple","watermelon","orange"]})
db.food.insert({"_id":3,"fruit":["cherry","banana","apple"]})
单元素匹配任何一个就行:db.food.find({"fruit":"apple"})
多元素匹配要用$all,既有apple又有banana的文档:
db.food.find({"fruit":{$all:["apple","banana"]}})
数组下标从0开始,用数组下标指定位置查询:
db.food.find({"fruit.2":"apple"})
$size,查询指定数组长度的数组:db.food.find({"fruit":{"$size":3}})
=====================查询========查询内嵌文档==================
db.account.insert({"userName":{"first":"joe","last":"schmoe"},"age":35})
完全匹配查询:db.account.find({"userName":{"first":"joe","last":"schmoe"}})
改变文档数据模式db.account.update({},{"$set":{"userName.passwd":"ddd"}})
点表示法查询(不受文档数据模式改变影响):db.account.find({"userName.first":"joe","userName.last":"schmoe"})
再次改变文档数据模式,增加数组元素db.account.update({},{"$push":{"comments":{"author":"joe","score":3,"comment":"test"}}})


db.account.update({},{"$push":{"comments":{"author":"tom","score":5,"comment":"test"}}})
查询作者为joe并且得分超过5分的文档:db.account.find({"comments.author":"joe","comments.score":{"$gte":5}})
正确做法,采用$elemMatch对内嵌文档多键匹配:db.account.find({"comments":{"$elemMatch":{"author":"joe","score":{"$gte":5}}}})
=====================查询========where查询==================
db.food.insert({"apple":1,"banana":6,"peach":3})
db.food.insert({"apple":8,"spinach":4,"watermelon":4})
db.food.find({"$where":function(){ for(var current in this){ for(var other in this){ if(current !=other && this[current]==this[other]){ return true; } } } return false; }});
不是逼急了不要用where 查询,能用键/值对尽量用键/值对查询方式
where查询无法使用索引,并且文档要从bson转成javascript对象,查询速度非常慢
=====================查询========游标操作==================
for(i=0;i<100;i++){ db.c.insert({x:i}); }
定义游标,不会立即执行查询:var cursor=db.c.find()
游标迭代器:while(cursor.hasNext()){ obj=cursor.next() }
执行cursor.hasNext()时,查询发往服务器,执行真正查询,shell会获取前100个结果或者4M数据(两者较小者)返回。
限制结果数据:db.c.find().limit(5);
跳过匹配文档:db.c.find().skip(5);
排序:sort用一个对象为参数,键、值对表示,键对应文档键名,值表示排序方向。1-升序,-1 - 降序。
db.c.find().sort({x:-1}) db.c.find().sort({x:1})
多键复合排序:db.account.find().sort({userName:1,age:-1})
=====================查询========游标分页==================
for(i=0;i<100;i++){ db.c.insert({x:i,y:"post"}); }
按条件查询每页20条纪录db.c.find({"y":"post"}).limit(20).sort({"x":1})
db.c.find({"y":"post"}).limit(20).sort({"x":-1})  
分页参数就是skip的参数db.c.find({"y":"post"}).limit(20).skip(20).sort({"x":1})
注意,用skip跳过少量文档是可行的,数量太多就会变慢
另一种不用skip进行分页的方法
=====================查询========游标内幕==================
服务器端,游标消耗内存和其它资源,要尽快合理释放
游标遍历完或客户端发消息终止,释放游标
游标在客户端不在作用域,驱动会向服务器发消息销毁游标
超时销毁机制,游标即使是在客户端作用域内,但10分钟不用,也会自动被销毁
若关闭游标超时销毁机制(驱动immortal函数),游标使用完,一定要显式将其关闭,否则其会一直消耗服务器资源。
====================索引创建==================
for(i=0;i<10000;i++){ db.account.insert({userName:"bbs"+i,age:i%60,createTime:new Date()}); }
单键索引:db.account.ensureIndex({"userName":1})
1--表示升序,-1 -- 表示降序
复合索引:db.account.ensureIndex({"userName":1,"age":-1})
db.account.ensureIndex({"userName":1,"age":1,"createTime":1})
只有索引前部的查询会得到优化
索引优化查询的同时,会对增删改带来额外开销
索引创建原则
应用程序会做什么查询,哪些键需要索引
每个键的索引方向是怎样的
如何应对扩展?如何通过不同键的排列使数据尽可能多的保存在内存中,增加命中率
数据量大时为排序创建索引
=====================唯一索引=================
db.account.ensureIndex({"userName":1},{"unique":true})
默认插入数据时不检查数据唯一性
安全插入时才会检查数据唯一性
_id键索引就是唯一索引,并且不能删除
也可创建唯一复合索引,单键可重复,组合后不相同即可
=====================查询分析工具==================
explain可分析查询使用索引的情况,耗时、及扫描文档数的统计
db.account.find({"userName":"bbs22"}).explain()
db.account.find({"age":30}).sort({"userName":1}).explain()
db.account.find({"age":{$gt:20,$lt:30}}).explain()索引前后比较
=====================强制指定索引使用==================
hint可以强制mongodb使用某一个索引
db.account.find({"age":{$gt:20,$lt:30}}).hint({"userName":1,"age":1,"createTime":1}).explain()
通常mongodb会智能选择最优索引使用
=====================聚合统计==================
count
统计集合总数: db.account.count()
条件统计:db.account.count({"age":30})
增加查询条件统计通常用于分页查询,但增加查询条件统计会使统计变慢
distinct
用于找出指定键的不同值 
db.runCommand({"distinct":"account","key":"age"})
必须指定集合名,键名
计算distinct后的count总数:
db.runCommand({"distinct":"account","key":"age"}).values.length
db.runCommand({"distinct":"account","key":"age","query":{"age":{"$gt":30}}}).values.length
group
db.account.group({ key:{"age":true}, initial:{number:0}, reduce:function(doc,prev){prev.number+=1 },cond:{"age":{"$gt":30}}})
key关键字标识我们想要汇总的数据(类似于SQL中GROUP BY子句的参数)
initial关键字标识我们记录的关键字的关键值的初始值
reduce关键字定义了一个方法,每次遇一个文档要做的事情
cond关键字定义条件
========================高级指南==================命令的工作原理================
db.account.drop()
db.runCommand({"drop":"account"})
命令响应结果是一个文档,ok键值为true表示执行成功,为false表示执行失败。
errmsg键值表示失败原因。
MongoDB中的命令其实是作为一种特殊类型的查询来执行的。这些查询针对$cmd集合来执行,runCommand仅仅命令文档,执行等价查询。
db.$cmd.findOne({"drop":"c"})
支持的命令浏览
db.listCommands()
访问web console也可获取
版本命令:db.runCommand({"buildInfo":1}) 
集合统计信息 :db.runCommand({"collStats":"account"}) 
修复数据库:{"repairDatabase":1} 比较耗时
删除集合:{"drop":collection}
查看对本集合最后一次操作的错误信息:db.runCommand({ "getlasterror" : 1 , "w" : 1 , "wtimeout" : 0})
删除当前数据库:{"dropDatabase":1}
删除索引:{"dropIndexes":collection,"index":name}
检查本服务器是主服务器还是从服务器:{"isMaster":1}
列出服务器上所有数据库(管理专用):{"listDatabases":1}
重命令集合:{"renameCollection":a,"to":b} a、b均必须为完整的命令空间(管理专用)
服务器管理统计信息:{"serverStatus":1}
========================高级指南==================固定集合================
固定集合:事先创建,大小固定
类似环状队列,空间不足队列头文件被替换
不能手工删除文档,只能自动替换
特点;插入性能好,不需额外分配空间,直接插入队列尾.按插入顺利查询速度极快
创建固定大小100k的固定集合:db.createCollection("fixed",{capped:true,size:100000})
插入测试数据:for(i=0;i<10000;i++){ db.fixed.insert({userName:"bbs"+i,age:i%60,createTime:new Date()}); }
创建固定大小100K且文档数最大100的固定集合: db.createCollection("fixed",{capped:true,size:100000,max:100})
容量未满时按文档数限制,容量满时按容量限制
转换语法:db.runCommand({convertToCapped:"account",size:10000})
========================高级指南==================GridFS================
GridFS是MongoDB中存储大二进制文件的机制。
使用GridFS后不需要再使用单独的文件存储架构
可直接利用MongoDB的复制分片机制,使文件存储也具有水平扩展、故障恢复功能
不产生磁盘碎片,因为MongoDB分配数据文件空间时以2GB为一块
GridFS用法:
./mongofiles -d bbs put test.txt
./mongofiles -d bbs get test.txt
./mongofiles -d bbs delete test.txt
./mongofiles -d bbs search test
./mongofiles -d bbs list
GridFS是建立在MongoDB文档规范基础上的轻量级文件存储规范
将大文件分块,每块独立存储
db.fs.chunks.find()
db.fs.files.find()
========================高级指南=================服务端脚本================
db.eval可在MongoDB服务端执行javascript脚本。
db.eval("return 1;")
db.eval("function() {return 1;}")
参数传递:
db.eval("function(u) { print('hello,'+u+'!');}",["user1"])
========================高级指南=================服务端脚本================存储javascript:
system.js保存javascript变量及代码
 db.system.js.insert({"_id":"x","value":1})
db.system.js.insert({"_id":"y","value":2})
 db.system.js.insert({"_id":"z","value":3})
db.eval中可引用变量:db.eval("function() {return x+y+z;}")
========================高级指南=================服务端脚本================写一个类似log4j的日志函数:
db.system.js.insert({"_id":"log","value": function(msg,level){ var levels=["DEBUG","WARN","ERROR","FATAL"]; level =level?level:0; var now=new Date(); print(now+" "+levels[level]+msg); }})
使用示例:db.eval("x=1;log(' x is '+x);x=2;log(' x is greater than 1',1);")
db.eval("log('refactor log test',2)")
========================高级指南=================服务端脚本================DBRef数据库引用:
DBRef指向一个集合的一个文档引用
类似表关联
{"ref":collection,"$id":id_value,"$db":database}
DBRef不是必须用,通常会引入复杂性让人误解。可有其它方式建立关联。
=======================高级指南=================系统管理高级技巧-系统监控=================
MongoDB持久化配置 :
持久化配置
journal=true
journalCommitInterval=100
正确关闭MongoDB
./mongod --shutdown或./mongod -f ../etc/mongo.conf --shutdown
不能直接kill进程,否则可能造成库文件损坏
=======================高级指南=================系统管理高级技巧-系统监控=================监控serverStatus
db.runCommand({"serverStatus":1})
参数含义简介:
        "globalLock" : {
                "totalTime" : NumberLong("511789041000"),--自实例启动全局锁创建以来到现在多长时间,单位微秒.
                "lockTime" : NumberLong(105416165),--自全局锁创建以来锁定总时间,单位微秒
                "currentQueue" : {
                        "total" : 0,--等待全局锁的队列中操作数目
                        "readers" : 0,--等待读锁的队列中操作数目
                        "writers" : 0--等待写锁的队列中操作数目
                },
                "activeClients" : {
                        "total" : 0,--连接到server的当前活动client数目
                        "readers" : 0, --执行读操作的当前活动client数目
                        "writers" : 0--执行写操作的当前活动client数目
                }
        },


        "mem" : {
                "bits" : 64,--64位机器
                "resident" : 31,--占用物理内存量
                "virtual" : 20478, --占用的虚拟内存量
                "supported" : true, --是否支持扩展内存
                "mapped" : 10188, --映射到内存的数据文件大小,很接近于你的所有数据库大小。
                "mappedWithJournal" : 20376
        },
        "connections" : {
                "current" : 1,--当前活动连接量。连接到server的当前活跃连接数目
                "available" : 19999--剩余空闲连接量。剩余的可用连接数目
        },
 "backgroundFlushing" : {
                "flushes" : 8527, --数据库刷新写到磁盘的次数
                "total_ms" : 599904,--数据库刷新数据到磁盘花费的微秒数
                "average_ms" : 70.35346546264806,--执行单次刷新花费的平均微秒数
                "last_ms" : 51,--最后一次执行完成刷新数据到磁盘花费的微秒数
                "last_finished" : ISODate("2012-12-26T00:41:32.013Z")-当最后一次刷新数据完成时的时间戳
        },
        "cursors" : {
                "totalOpen" : 0, --server为client保持的游标(cursor)总数
                "clientCursors_size" : 0,
                "timedOut" : 0--server启动以来游标(cursor)超时的总数
        },
        "network" : {
                "bytesIn" : 1925,--发送到数据库的数据总量(bytes)
                "bytesOut" : 4294,--数据库发出的数据总量(bytes)
                "numRequests" : 24--发送到数据库的请求量
        },
   
     "opcounters" : {
                "insert" : 0, --server启动以来总的insert数据量
                "query" : 16646, --server启动以来总的query数据量
                "update" : 1,--server启动以来总的update数据量
                "delete" : 0, --server启动以来总的delete数据量
                "getmore" : 0, --server启动以来调用任何游标的getMore总次数
                "command" : 22 --server启动以来执行其他命令的总次数
        },
        "asserts" : {
                "regular" : 0, --server启动以来抛出正规断言(assert 类似于异常处理的形式)总数目
                "warning" : 0,--server启动以来抛出的告警总数目
                "msg" : 0,--消息断言数目。服务器内部定义的良好字符串错误
                "user" : 0, --用户断言数目。用户产生的错误,譬如:磁盘空间满;重复键。
                "rollovers" : 0--server启动以来,assert counters have rolled over的次数
        },
   


     "writeBacksQueued" : false,--是否有从mongos执行的retry操作
        "dur" : {
                "commits" : 29,--上一间隔journal日志发生commit的次数
                "journaledMB" : 0,--上一间隔写到journal日志的数据量(单位:MB)
                "writeToDataFilesMB" : 0,--上一间隔journal日志写到数据文件的数据量(单位:MB)
                "compression" : 0,
                "commitsInWriteLock" : 0, --写锁期间发生commits的次数
                "earlyCommits" : 0,--schedule时间前请求commit的次数
                "timeMs" : {
                        "dt" : 3004,
                        "prepLogBuffer" : 0,--准备写journal日志花费的时间
                        "writeToJournal" : 0,--写journal日志花费的实际时间
                        "writeToDataFiles" : 0,--journal日志后写数据文件花费的时间
                        "remapPrivateView" : 0
                }
        },
=======================高级指南=================系统管理高级技巧-系统监控=================监控mongostat
mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出
insert:     一秒内的插入数
query :     一秒内的查询数
update:     一秒内的更新数
delete:     一秒内的删除数
getmore:    查询时游标(cursor)的getmore操作
command:    一秒内执行的命令数
flushes:    一秒内flush的次数
   mapped   所有的被mmap的数据量,单位M
   vsize        虚拟内存使用量,单位M
   res          物理内存使用量,单位M
faults/s 每秒访问失败数(只有Linux有),数据被交换出物理内存,放到swap。不要超过100,否则就是机器内存太小,造成频繁swap写入。此时要升级内存或者扩展
locked % 被锁的时间百分比,不要太大
idx miss:  索引不命中所占百分比。如果太高的话就要考虑索引是不是少了
qr|qw:客户端查询等待数
ar|aw:客户端文档读写等待数,都为0的话表示mongo毫无压力。高并发时,一般队列值会升高
netIn|netOut:网络带宽压力
conn 当前连接数
time 时间戳
=======================高级指南=================系统管理高级技巧-系统监控=================MongoDB安全
默认没有设置安全认证
增加root用户:
use admin
db.addUser("root","rootabc")
给自定义库增加用户:
use bbs
db.addUser("readwrite","rw")
db.addUser("read","readabc")
增加配置项auth=true,打开库安全认证
db.auth("root","rootabc")
用户存放在数据库的system.users集合中。
use test
db.auth("read","readabc")
=======================高级指南=================系统管理高级技巧-系统监控=================备份恢复
mongodump -h dbhost -d dbname -o dbdirectory -- 数据库备份
mongorestore -h dbhost -d dbname --directoryperdb dbdirectory -- 数据库恢复
可在线实时备份
提取快照方法:db.runCommand({"fsync":1,"lock":1})
fsync强制所有缓冲区写入磁盘
备份完后解锁:db.fsyncUnlock()
缺点:耽误读写操作
=======================高级指南=================系统管理高级技巧-系统监控=================数据库修复
mongod --repair启数据库修复
或db.repairDatabase()
修复原理:将所有文档导出并马上导入,忽略无效文档,然后重建索引
修复会化点时间
=======================高级指南=================复制功能=================
复制优点
数据备份
数据恢复
读写分离
主、从节点建立:
建立启动主节点:./mongod -f ../etc/mongo.conf --master,注意--master表示主节点,可跟--port表明启动端口

建立从节点: mkdir /data/slave,启动从节点: ./mongod --dbpath /data/slave --port 10001 --slave --source localhost:27017,

注意端口必须与主节点不同,--source指明主节点

ps:一个主节点挂载从节点不超过12个

复制管理

打印主从复制集群情况:

主节点上

db.printReplicationInfo()

configured oplog size日志大小

oplog first event time日志什么时候开始记录

oplog last event time日志最后一条记录时间

从节点上

source 主节点地址

syncedTo 最后一次同步时间

日志大小调节

./mongod  -f 启动配置文件路径 --oplogSize(log大小调节参数) xxxxx(值)

=======================高级指南================MongoDB数据文件内部结构=================


MongoDB数据文件内部结构
MongoDB在数据存储上按命名空间来划分,一个Collection是一个命名空间,一个索引也是一个命名空间。
同一个命名空间的数据被分成很多个Extent,Extent之间使用双向链表连接。
在每一个Extent中,保存了具体每一行的数据,这些数据也是通过双向链接来连接的。
每一行数据存储空间不仅包括数据占用空间,还可能包含一部分附加空间,这使得在数据Update变大后可以不移动位置。
索引以BTree结构实现
=======================高级指南================副本集数据同步机制=================


红色箭头表示写操作可以写到Primary上,然后异步同步到多个Secondary上。
蓝色箭头表示读操作可以从Primary或Secondary任意一个中读取。
各个Primary与Secondary之间一直保持心跳同步检测,用于判断Replica Sets的状态

=======================高级指南=================副本集=================
概念:
副本集是具有故障恢复功能的主从集群
与主从集群区别:副本集没有固定主节点
本质上是很牛X的具有HA功能的主从集群
副本集创建:
为副本集取名 (jm)
./mongod --dbpath /data/db1 --port 1111 --replSet jm
./mongod --dbpath /data/db1 --port 2222 --replSet jm
./mongod --dbpath /data/db1 --port 3333 --replSet jm
--replSet参数,创建副本集中一个节点
创建启动副本集中第二个节点
副本集初始化,初始化命令只能执行一次
config_jm={"_id":"jm",members:[{_id:0,host:"192.168.154.133:1111"},{_id:1,host:"192.168.154.143:2222"},{_id:2,host:"192.168.154.153:3333"}]}
rs.initiate(config_jm)
查看副本集状态:
rs.status()
db.isMaster()
副本集故障恢复:
副本集任何时间只有一个活跃节点
投票机制决定谁成为活跃节点,优先级最高、数据最新的节点获胜
节点类型:
standard:这种是常规节点,他存储一份完整的数据库副本,参与选举投票,有可能成为活动节点
passive:存储一份完整的数据库副本,参与选举投票,不能成为活动节点
arbiter:仲裁者只参与投票,不接收复制的数据,也不能成为活动节点
ps:注意一点:副本至少3个,因为2个的话有一个挂了另外一个不能投票了! 剩下一个会一直是secondary
=======================高级指南=================分片=================
概念:
分片是指将数据拆分,将其分散到不同机器上的过程
mongodb支持自动分片
何时分片:磁盘不够用了、单个mongd不能满足写数据性能要求、想将大量数据放在内存中提高性能
片键指从集合中挑选一个键,该键值做为数据拆分的依据

创建分片步骤:

选择合适的片键(eg:username)

1 :建立mongodb启动配置mongo.conf文件
logpath=../log/mongodb.log
dbpath=/home/tom/data/dbfp
logappend=false
cpu=false
journal=true
journalCommitInterval=100
rest=true
fork=true
auth=false
2 :启动mongodb
./mongod -f ../etc/mongo1.conf --port 27017
./mongod -f ../etc/mongo2.conf --port 27018
3 : 启动配置服务器
./mongod -f ../etc/mongoconf.conf --port 20000 
4 : 启动mongos
./mongos --port 30000 --configdb 配置服务器IP:20000
5 : 配置分片节点
./mongo mongos服务器IP:30000/admin
db.runCommand({addshard:"分片服务器1:27017",allowLocal:true})
db.runCommand({addshard:"分片服务器2:27018",allowLocal:true})
6 : 启动分片
db.runCommand({"enablesharding":"jmtest"})
7 : 在指定列上建立片键

db.runCommand({"shardcollection":"jmtest.account","key":{"userName",1}})   1表示升序

db.jmtest.getIndexs() 查看索引

8 : 查看各分片状态
登录mongos服务器
./mongo mongos服务器IP:30000/admin
db.printShardingStatus()


以上操作都会保存到配置服务器里面
生产配置:
三个配置服务器
多个mongos服务器
每个片都是副本集

生产环境应建立3个配置服务器

关于分片的其他操作如:删除,请查阅另一篇文章:http://blog.csdn.net/johnstrive/article/details/24690805

=======================高级指南=================分片机制=================

MongoDB的分片是指定一个分片key来进行,数据按范围分成不同的chunk,每个chunk的大小有限制。
有多个分片节点保存这些chunk,每个节点保存一部分的chunk。
每一个分片节点都是一个Replica Sets,这样保证数据的安全性。
当一个chunk超过其限制的最大体积时,会分裂成两个小的chunk。

当chunk在分片节点中分布不均衡时,会引发chunk迁移操作。

 客户端访问路由节点mongos来进行数据读写。
config服务器保存了两个映射关系,一个是key值的区间对应哪一个chunk的映射关系,另一个是chunk存在哪一个分片节点的映射关系。
路由节点通过config服务器获取数据信息,通过这些信息,找到真正存放数据的分片节点进行对应操作。
路由节点还会在写操作时判断当前chunk是否超出限定大小。如果超出,就分列成两个chunk。
对于按分片key进行的查询和update操作来说,路由节点会查到具体的chunk然后再进行相关的工作。
对于不按分片key进行的查询和update操作来说,mongos会对所有下属节点发送请求然后再对返回结果进行合并。



(责任编辑:IT)