??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美巨乳在线,98精品在线视频,视频一区二区在线观看http://www.aygfsteel.com/dongbule/category/48840.html建造高性能门户|?/description>zh-cnSat, 30 Jul 2011 15:45:22 GMTSat, 30 Jul 2011 15:45:22 GMT60述MongoDB的管理操?/title><link>http://www.aygfsteel.com/dongbule/archive/2011/07/30/355409.html</link><dc:creator>陈于?/dc:creator><author>陈于?/author><pubDate>Sat, 30 Jul 2011 10:23:00 GMT</pubDate><guid>http://www.aygfsteel.com/dongbule/archive/2011/07/30/355409.html</guid><wfw:comment>http://www.aygfsteel.com/dongbule/comments/355409.html</wfw:comment><comments>http://www.aygfsteel.com/dongbule/archive/2011/07/30/355409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/dongbule/comments/commentRss/355409.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/dongbule/services/trackbacks/355409.html</trackback:ping><description><![CDATA[<div>     不知不觉房pȝ已经使用MongoDB一q多?jin),记得一q多以前Q正是NOSQL被热炒时QMongoDB更是作ؓ(f)NOSQL中的g者,被炒得火烫,也应该就在当时被q股火烫着?jin),所以义无反儡选择?jin)MongoDBQ现在想惛_时确实有些冲动了(jin)Q当时MongoDB的资料还是比较少Q更别说中文资料?jin),后来q出C用MongoDB成功应用的范例Foursquare的宕Z件。现在确实应该很感谢MongoDB为我们的pȝ服务?jin)一q了(jin)Q在q一q的旉里,实出现q不的问题,特别是在理操作上,我想q大概也是因为MongoDB在系l维护上不如Mysql那样有着各种的业界实践,往往只能通过理员自己去摸烦(ch)?br /> 下面在q一q的一些简单的理操作做一下记?br /><br /><div><div>    <a href="#x1">Starting and Stopping Mongo</a></div> <div>    <a href="#x2">Security and Authentication</a></div> <div>    <a href="#x3">Monitoring and Diagnostics</a></div> <div>    <a href="#x4">Backups</a></div> </div><br /> <div><strong><a target=""><span style="font-size: 12pt;">Starting and Stopping Mongo</span></a></strong><a target=""><a name='x1' id='x1'></a></a><strong><a target=""><span style="font-size: 12pt;"></span></a><br /> <br /> </strong><span style="background-color: #ccffcc;">MongoDB启动</span><strong><br /> </strong> <div>对了(jin)QMongoDB在linux下是无需安装的,从官|上下蝲下安装包后解压,直接执行mongodQ就可以启动MongoDB服务器,当然mongodq有很多的启动选择,q行mongod --help可以查看所有的选择V?br /> <br /> -f [ --config ] arg   configuration file specifying additional options<br /> 一般来_(d)启动选择可以直接写在在mongod后面Q也可以指定配置文gQ用文g来加载各U启动项Q如<br /> /home/mongodb/bin/mongod --config /home/mongodb/conf/mongod.conf</div> <strong><br /> </strong></div> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/1.jpg" alt="" width="725" border="0" height="195" /></div> <div>上面是一台测试机的启动选择V?br /> <br /> dbpath = /home/mongodb/data<br />     指定数据库的存储目录Q如果不讄则以mongodb的根目录为目录,当MongoDB启动之后Q在数据库的存储目录下会(x)创徏一个mongod.lock文gQ它是用来记录当前的mongod的进E号Q同时也用于区分各个mongod的进E实例,所以不同的mongodq程实例是不能用相同的dbpath?br /> logpath = /home/mongodb/mongodb.log<br />     指定日志输出的\径,如果没有讄logappend = trueQ系l会(x)清除原来的日志记录,把已有的文gq行覆盖?br /> logappend = true<br />     日志以追加的方式q行记录<br /> bind_ip = 192.168.86.111<br />     指定对外服务的绑定ipQ这里指定内|的ip方式Q如果外|无Ҏ(gu)的处理方式是无法q行q接?br /> port = 27017<br />     指定服务器的监听端口P默认?7017Q如果单个机器要q行多个mongodq程Q则需要给每个q程指定不同的端口号?br /> fork = true<br />     指定以守护进E的方式来启动MongoDBQ如果不指定Q在启动mongod命o(h)是加“&”也是可以的?br /> auth = true<br />     启动mongodb客户端登录的认证机制?br /> master = true<br />     指定该机器ؓ(f)M模式下的L器?br /> 配置完配|文件后启栋mongodQ启动时要盯着日志文g看,因ؓ(f)日志通常?x)告诉我们一些错误或警告的信息,q样能够更好的帮助我们了(jin)解和避免错误?br /> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/2.jpg" alt="" width="729" border="0" height="94" /><br /> <br /> <div>q里l出?jin)个提示Q用的?2位的MongodbQ所以MongoDB只是存储最大ؓ(f)2GB的数据。其实这个跟MongoDB的mmap机制有关Q如果是64位则不会(x)存在q种限制?br /> h意一定要盯着日志?br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">tail </span><span style="color: #000000;">-</span><span style="color: #000000;">100f </span><span style="color: #000000;">/</span><span style="color: #000000;">home</span><span style="color: #000000;">/</span><span style="color: #000000;">mongodb</span><span style="color: #000000;">/</span><span style="color: #000000;">mongodb.log</span></div> <br /> <div><span style="background-color: #ccffcc;">停止MongoDB</span></div> <div>千万要强调的是千万不要用kill -9d闭mongodQ这h据库?x)不理一切直接杀死该q程Q会(x)使得数据文g损坏?br /> E_的方法是使用kill -2 pidd闭mongodQ也是当mongodq程接受到关闭指令后?x)等待当前运行操作或文g分配{操作完毕后Q关闭所有打开的连接,q将~存的数据刷新到盘后才正式关闭?br /> 最E_的方式是使用shutdown命o(h)来结?br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">></span><span style="color: #000000;"> use admin<br /> switched to db admin<br /> </span><span style="color: #000000;">></span><span style="color: #000000;"> db.shutdownServer();</span></div> <br /> <div><strong>Security and Authentication</strong><a name='x2' id='x2'></a><br /><strong> <br /> </strong></div> </div> <div>打开mongodb.org的Security文档Q第一句话是 Running Without Security(Trusted Environment)Q跟我们世界上没有什么百分百安全的环境,最好的安全是放在一个安全的环境中运行,q么无底气的话语未免也让Zؓ(f)它的安全担心(j)Q不q事实上MongoDBq是有安全认证模式的Q只不过跟mysqlҎ(gu)h有一点简陋?br /> <br /> <span style="background-color: #ccffcc;">MongoDB的安?/span><br /> MongoDB目前只支持最基本的安全认证,如果我们开启了(jin)安全性检查,则只有数据库认证用户才能q行d操作Q当然我们还可以创徏d权限用户和只L限用P如果我们在admin的数据库中进行创建用P那么admin中的用户׃(x)被当作超U用P用户可以d所有的数据库,q且q可以进行特D的理操作Q比如可以再创徏其他用户关闭q程{操作?br /> <br /> <span style="background-color: #ccffcc;">配置MongoDb用户认证</span><br /> Ҏ(gu)官网上的例子Q我们也来创Z个超U用P一个test库中hd操作的普通用P一个test库中只有L作的普通用戗?/div> <br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">> use admin<br /> switched to db admin<br /> > db.addUser(</span><span style="color: #000000;">"</span><span style="color: #000000;">cyz</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">abc</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br /> {<br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">_id</span><span style="color: #000000;">"</span><span style="color: #000000;"> : ObjectId(</span><span style="color: #000000;">"</span><span style="color: #000000;">4dba5fe7c6792ae30fea3c31</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">cyz</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;"> : false</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">8658a5bf469e005b047560619ef0d51c</span><span style="color: #000000;">"</span><span style="color: #000000;"><br /> }<br /> > use test<br /> switched to db test<br /> > db.addUser(</span><span style="color: #000000;">"</span><span style="color: #000000;">cyz001</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">abc</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br /> {<br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">cyz001</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;"> : false</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">7a597bef551027cc2161d5e0efe4049e</span><span style="color: #000000;">"</span><span style="color: #000000;"><br /> }<br /> > db.addUser(</span><span style="color: #000000;">"</span><span style="color: #000000;">cyz002</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">abc</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">true)<br /> {<br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">cyz002</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;"> : true</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">2dde0a3777cd7dd92459a6c3f98afac6</span><span style="color: #000000;">"</span><span style="color: #000000;"><br /> }<br /> </span></div> </div> <div>q里cyz是在admin库中创徏Q属于超U用P可以Ҏ(gu)有库q行操作Q在test库中创徏的cyz001和cyz002属于test库的操作人员Q只能对test库进行相应操作,记得要ؓ(f)安全验证生效需要将启动auth讄为true?br /> <br /> <span style="background-color: #ccffcc;">查看用户</span><br /> 所有的用户信息都存储在每个数据库的db.system.users中,可以使用find()q行查看<br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">> use admin<br /> switched to db admin<br /> > db.system.users.find()<br /> { </span><span style="color: #000000;">"</span><span style="color: #000000;">_id</span><span style="color: #000000;">"</span><span style="color: #000000;"> : ObjectId(</span><span style="color: #000000;">"</span><span style="color: #000000;">4dba5fe7c6792ae30fea3c31</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">,</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">"</span><span style="color: #000000;">cyz</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;"> : false</span><span style="color: #000000;">,</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;"> : <br /> <br /> </span><span style="color: #000000;">"</span><span style="color: #000000;">8658a5bf469e005b047560619ef0d51c</span><span style="color: #000000;">"</span><span style="color: #000000;"> }</span></div> <br /> 其中的pwd是根据用户名和用户密码生成的散列倹{?br /> <br /> <span style="background-color: #ccffcc;">修改用户</span><br /> 不管是添加用P修改用户密码Q修改用h作权限都使用addUser()来完成。删除用户可以用remove()来实现?/div> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">> db.system.users.find({</span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;">:</span><span style="color: #000000;">"</span><span style="color: #000000;">cyz001</span><span style="color: #000000;">"</span><span style="color: #000000;">})</span></div> </div> <br /> <div><span style="background-color: #ccffcc;">更多的安全考虑</span><br /> <br /> 刚说?jin)MongoDB的安全认证其实还是简陋的Q所以我们还是有其他很多的安全考虑?br /> 1.比如说MongoDB传输协议是不加密的,如果需要加密的话,我们可以考虑使用ssh隧道或是他们的技术来对客L(fng)和服务端之间的通讯q行加密?br /> 2.MongoDB部v在只有客L(fng)服务器才能访问到的环境,比如内网Qvpn|络中,可以使用 bind_ip = 本机或内|??br /> 3.如果实需要将MongoDB暴露在外部环境可以考虑使用IPTABLES{技术进行访问限制?br /> <br /> <div><strong>Monitoring and Diagnostics</strong><a name='x3' id='x3'></a><br /> <br /> <div>官网首先l我们推荐了(jin)mongostat监控工具Q基本上mongostat可以作ؓ(f)一个外部观MongoDB内部状态指标的工具Qƈ且一U更Cơ,如果出现一些性能问题可以用这里入手进行分析?br /> <br /> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/3.jpg" alt="" width="1144" border="0" height="122" /></div> <br /> <div>q里的属性都可以通过mongostat --helpq行查看Q有几个列需要解释一下,可以帮助到我们发生性能问题时比较准备的扑ֈ定位?br /> <br /> faultsQ这是一个重要的性能指标Q显CZ的机器每U页面故障的数量Q这个是mongoDB映射到虚拟地址I间Q而不是物理内存,q个值如果飙高的话,可能意味着你的机器没有_的内存来存储数据和磁盘的讉K?br /> flushesQ每U做?jin)多次fsyncQ表面多次数据被刷新进?jin)磁盘?br /> mappedQ是指mmap有多数据量Q也是服务器的内存映射Q其中包含了(jin)虚拟内存和常d存?br /> lockedQ这个D面全局写入锁占用了(jin)机器多少旉Q?当放生全局写入锁时Q所有的查询操作都将{待Q直到写入锁的解锁,如果q个锁飙高有可能是你的程序那部分出现问题?br /> idx missQB?wi)未命中的比例,q个应该是我们查询的命中的实时指敎ͼ一般在特定查询中会(x)有用到?br /> qr | qwQ如果有太多的查询进行处理,它们׃一个队列的方式q行Q如果这个值飙高的话,那么查询也会(x)变得很慢Q因为后面的队列必须{待前面的队列执行完毕,高ƈ发时Q一般队列g(x)升高?br /> 另外我们q可以在mongodb shell中进行检查,使用db.serverStatus()</div> </div> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/4.jpg" alt="" width="683" border="0" height="376" /></div> <br /> <div>基本上db.serverStatus()跟mongostat 差不多,不过它显C的数据更ؓ(f)具体Q它也有一个缺陷就是它的数据是?rn)态的Q不是实时的?br /> <br /> <span style="background-color: #ccffcc;">Http Console</span><br /> 其实mongodbq提供了(jin)一个跟直观的检工P在默认情况下Q启动mongodb的同时还?sh)(x)启动一个http的服务器Q用|页展示的信息比前两个工h得更加直观,启动默认的监听端口ؓ(f)28017 httpQ?/ip:28017<br /> <br /> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/5.jpg" alt="" width="1178" border="0" height="385" /></div> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/6.jpg" alt="" width="1151" border="0" height="236" /><br /> 基本上我们可以看到查询,复制Q锁{等q些的情况,具体的参数还是上官网looklookQhttp://www.mongodb.org/display/DOCS/Http+Interface<br /> <div>当然?jin),我们q可以用其他的专业监控软gq行监控Q如nagiosQcactiQ这些都有mongodb的插件?br /> <br /> <div><strong>Backups</strong><a name='x4' id='x4'></a><br /> MongoDB的备份机制还是不错的Q备份的方式也是很多Q这个ƈ不比mysql要差?br /> <br /> Shutdown and Backup<br /> 关闭服务Q直接把dbpath参数的目录进行备份,只需把所有的文gq行复制到其他地方就可以Q不q如果这个备份是在服务启动时候做的话Q有可能备䆾的文件会(x)被损坏,虽然q种关闭服务的备份很有效也很安全Q都效果相当不理惟?br /> <br /> mongodump & mongorestore<br /> mongodump直就是mysqldump的另一版,如果你用过mysqldump那就再熟(zhn)不q了(jin)Qmongodbdump可以使用在各个客L(fng)Q对正在q行的mongodb服务做出查询Q然后将所有查到的文本写入到客L(fng)的磁盘?/div> </div> <img src="http://www.aygfsteel.com/images/blogjava_net/dongbule/46046/7.jpg" alt="" width="704" border="0" height="257" /><br /> <br /> <div><br /> 除了(jin)mongodumpQMongoDBq提供了(jin)从备份中恢复数据的工具mongorestoreQmongorestore从mongodump获取l果Qƈ备份的数据插入到运行的MongoDB实例?/div> <br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">./mongodump --db test --collection user --out - > /home/chenyz/cyz.bson<br /> ./mongorestore --db test --collection user --directoryperdb /home/chenyz/cyz.bson --drop cyz.bson</span></div> <br /> <div>上面的例子中Q指定了(jin)要备份的db和要备䆾的collectionQ?-drop表明要在恢复前删除集合,否则Q数据将和现有的集合数据合ƈ?br /> <br /> <span style="background-color: #ccffcc;">M备䆾</span><br /> 上面说的几种备䆾数据方式已经很灵zM(jin)Q但都不?qing)在从服务器上备份来得方便,从服务器的数据几乎是于主服务器进行同步,涉?qing)C从方面还有很多,从服务器备䆾׃攑֜q里讲了(jin)?br /> <br /> <span style="background-color: #ccffcc;">修复</span><br /> 遇到一些停?sh),或非法关闭mongodbQ不合理备䆾文g的操作,往往?x)出现文件损毁的提示Q幸好,mongodb内置的修复功能会(x)试着L复损坏的文g?br /> 操作很简单,只需在启动mongod 加入 --repair启动,pȝ׃(x)所有的文g导入忽略那些无效的文档然后进行导入,完成之后Q会(x)重新建立索引Q数据量大的话需要花费很长的旉Q因为所有的文g都需要进行验证,所有的索引都需要重建,另外修复数据库还能v到压~数据的作用Q闲|的I间Q碎片在修复后会(x)被重新回收进行用?br /> <br /> 另外在shell中也可以直接q行repair操作<br /> <div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">> db.repairDatabase()<br /> {<br />         </span><span style="color: #000000;">"</span><span style="color: #000000;">ok</span><span style="color: #000000;">"</span><span style="color: #000000;"> : </span><span style="color: #000000;">1</span><span style="color: #000000;"><br /> }</span></div> </div><img src ="http://www.aygfsteel.com/dongbule/aggbug/355409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/dongbule/" target="_blank">陈于?/a> 2011-07-30 18:23 <a href="http://www.aygfsteel.com/dongbule/archive/2011/07/30/355409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说MongoDB的ObjectIdhttp://www.aygfsteel.com/dongbule/archive/2011/06/12/352138.html陈于?/dc:creator>陈于?/author>Sun, 12 Jun 2011 10:30:00 GMThttp://www.aygfsteel.com/dongbule/archive/2011/06/12/352138.htmlhttp://www.aygfsteel.com/dongbule/comments/352138.htmlhttp://www.aygfsteel.com/dongbule/archive/2011/06/12/352138.html#Feedback4http://www.aygfsteel.com/dongbule/comments/commentRss/352138.htmlhttp://www.aygfsteel.com/dongbule/services/trackbacks/352138.html前段旉有个朋友问我Q分布式主键生成{略在我们这Ҏ(gu)怎么实现的,当时我给的答案是sequenceQ当然这在不高ƈ发的情况下是没有M问题Q实际上Q我们的主键生成是可控的Q但如果是在分布式高q发的情况下Q那肯定是有问题的?br />
H然惌vmongodb的objectidQ记得以前看q文档,objectid是一U轻量型的,不同的机器都能用全局唯一的同U方法轻量的生成它,而不是采用传l的自增的主键策略,因ؓ(f)在多台服务器上同步自动增加主键既费力又费Ӟ不得不佩服,mongodb从开始设计就被定义ؓ(f)分布式数据库?br />下面深入一Ҏ(gu)ȝq个Objectid的底l,在mongodb集合中的每个document中都必须有一?_id"建,q个键的值可以是Mcd的,在默认的情况下是个Objectid对象?br />当我们让一个collection中插入一条不带_id的记录,pȝ?x)自动地生成一个_id的key
> db.t_test.insert({"name":"cyz"})
> db.t_test.findOne({"name":"cyz"})
{ "_id" : ObjectId("4df2dcec2cdcd20936a8b817"), "name" : "cyz" }

可以发现q里多出一个Objectidcd的_idQ当然了(jin)Q这个_id是系l默认生成的Q你也可以ؓ(f)其指定一个|不过在同一collections中该值必L唯一?br />
?ObjectId("4df2dcec2cdcd20936a8b817")q串值拿出来q对照官|的解析来深入分析?br />
"4df2dcec2cdcd20936a8b817" 以这D字W串Z来进行解析,q是一?4位的字符Ԍ看v来很长,很难理解Q实际上它是由O(jin)bjectId(string)所创徏的一l十六进制的字符Q每个字节两位的十六q制数字Qd使用?2字节的存储空_(d)可能有些朋友?x)感到很奇怪,居然是用?2个字节,而mysql的INTcd也只?个字节,不过按照现在的存储设备,多出来的q点字节也应该不?x)成Z么瓶颈,实际上,mongodb在设计上无处不在的体现着用空间换旉的思想Q接下看?br />
下面是官|指定Bson中ObjectId的详l规?br />


TimeStamp
?位是一个unix的时间戳Q是一个intcdQ我们将上面的例子中的objectid的前4位进行提?#8220;4df2dcec”Q然后再他们安装十六进制专为十q制Q?#8220;1307761900”Q这个数字就是一个时间戳Qؓ(f)?jin)让效果更佳明显Q我们将q个旉戌{换成我们?fn)惯的时间格?/div>
$ date -d '1970-01-01 UTC 1307761900  sec'  -u
2011q?nbsp;06?nbsp;11?nbsp;星期?nbsp;03:11:40 UTC

?个字节其实隐藏了(jin)文档创徏的时_(d)q且旉戛_在于字符的最前面Q这意味着ObjectId大致?x)按照插入进行排序,q对于某些方面v到很大作用,如作为烦(ch)引提高搜索效率等{。用时间戳q有一个好处是Q某些客L(fng)驱动可以通过ObjectId解析?gu)记录是何时插入的Q这也解{了(jin)我们qx(chng)快速连l创建多个ObjectidӞ?x)发现前几位数字很少发现变化的现实,因?f)使用的是当前旉Q很多用h?j)要?gu)务器q行旉同步Q其实这个时间戳的真实值ƈ不重要,只要其M停增加就好?/div>
Machine
接下来的三个字节Q就?2cdcd2 ,q三个字节是所在主机的唯一标识W,一般是机器L名的散列|q样q保了(jin)不同L生成不同的机器hash|保在分布式中不造成冲突Q这也就是在同一台机器生成的objectid中间的字W串都是一模一L(fng)原因?br />
pid
上面的Machine是ؓ(f)?jin)确保在不同机器产生的objectid不冲H,而pid是Z(jin)在同一台机器不同的mongodbq程产生?jin)objectid不冲H,接下来的0936两位是产生o(w)bjectid的进E标识符?br />
increment
前面的九(ji)个字节是保证?jin)一U内不同机器不同q程生成objectid不冲H,q后面的三个字节a8b817Q是一个自动增加的计数器,用来保在同一U内产生的objectid也不?x)发现冲H,允许256?ơ方{于16777216条记录的唯一性?/div>
客户端生?/strong>
mongodb产生o(w)bjectidq有一个更大的优势Q就是mongodb可以通过自n的服务来产生o(w)bjectidQ也可以通过客户端的驱动E序来生,如果你仔l看文档你会(x)感叹Qmongodb的设计无处不在的?br />
用空间换旉的思想Q比较objectid是轻量Q但服务端生也必须开销旉Q所以能从服务器转移到客L(fng)驱动E序完成的就量的{U,必须事务扔l客L(fng)来完成,减低服务端的开销Q另q有一点原因就是扩展应用层比扩展数据库层要变量得多?br />
好吧Q既然我们了(jin)解到我们的程序生o(w)bjectid是在客户端完成,那再l箋Q进一步了(jin)解,打开mongodb java driver源码Q无源码可以到mongodb官网q行下蝲Q下面摘录部分代?br />
public class ObjectId implements Comparable<ObjectId> , java.io.Serializable {

    
final int _time;
    
final int _machine;
    
final int _inc;

    
public ObjectId( byte[] b ){
        
if ( b.length != 12 )
            
throw new IllegalArgumentException( "need 12 bytes" );
        ByteBuffer bb 
= ByteBuffer.wrap( b );
        _time 
= bb.getInt();
        _machine 
= bb.getInt();
        _inc 
= bb.getInt();
        _new 
= false;
    }
    
    
public ObjectId( int time , int machine , int inc ){
        _time 
= time;
        _machine 
= machine;
        _inc 
= inc;
        _new 
= false;
    }
    
    
public ObjectId(){
        _time 
= (int) (System.currentTimeMillis() / 1000);
        _machine 
= _genmachine;
        _inc 
= _nextInc.getAndIncrement();
        _new 
= true;
    }


Q完整代码请查看源码Q?/span>

q里可以发现ObjectId的构建可以有多种方式Q可以由自己制定字节Q也可以指定旉Q机器码和自增|q里重点看看驱动E序默认的构建,也就是public ObjectId()
可以看到objectid主要由_time _machine _inc 所l成Q其?_time直接?System.currentTimeMillis() / 1000)计算出所谓的旉戻Iq里很简单,接下来是重点Q主要看?strong>机器码和q程?/strong>的构?/div>

 private static final int _genmachine;
    
static {

        
try {
            final int machinePiece;//机器码块
            {
                StringBuilder sb 
= new StringBuilder();
                Enumeration
<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();//NetworkInterface此类表示一个由名称和分配给此接口的 IP 地址列表l成的网l接口,它用于标识将多播l加入的本地接口Q这里通过NetworkInterface此机器上所有的接口
                while ( e.hasMoreElements() ){
                    NetworkInterface ni 
= e.nextElement();
                    sb.append( ni.toString() );
                }
                machinePiece 
= sb.toString().hashCode() << 16//得到所有接口的字符串进行取散列?/span>
                LOGGER.fine( "machine piece post: " + Integer.toHexString( machinePiece ) );
            }

            final int processPiece;//q程?/span>
            {
                
int processId = new java.util.Random().nextInt();
                
try {
                    processId 
= java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();//RuntimeMXBean是Java虚拟机的q行时系l的理接口Q这里是q回表示正在q行?nbsp;Java 虚拟机的名称Qƈq行取散列倹{?/span>
                }
                
catch ( Throwable t ){
                }

                ClassLoader loader 
= ObjectId.class.getClassLoader();
                
int loaderId = loader != null ? System.identityHashCode(loader) : 0;

                StringBuilder sb 
= new StringBuilder();
                sb.append(Integer.toHexString(processId));
                sb.append(Integer.toHexString(loaderId));
                processPiece 
= sb.toString().hashCode() & 0xFFFF;
                LOGGER.fine( 
"process piece: " + Integer.toHexString( processPiece ) );
            }
            _genmachine 
= machinePiece | processPiece; //最后将机器码块的散列gq程块的散列D行位或运,得到 _genmachine 
            LOGGER.fine( "machine : " + Integer.toHexString( _genmachine ) );
        }
        
catch ( java.io.IOException ioe ){
            
throw new RuntimeException( ioe );
        }
    }

 Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
               while ( e.hasMoreElements() ){
                    NetworkInterface ni = e.nextElement();
                    sb.append( ni.toString() );
                }
 machinePiece = sb.toString().hashCode() << 16;

q里的NetworkInterface.getNetworkInterfaces();取得的接口通常是按名称Q如 "le0"Q区分的Q大U是下面的类?/div>
name:lo (Software Loopback Interface 1) index: 1 addresses:
/0:0:0:0:0:0:0:1;
/127.0.0.1;
name:net0 (WAN Miniport (SSTP)) index: 
2 addresses:
name:net1 (WAN Miniport (IKEv2)) index: 
3 addresses:
name:net2 (WAN Miniport (L2TP)) index: 
4 addresses:
name:net3 (WAN Miniport (PPTP)) index: 
5 addresses:
name:ppp0 (WAN Miniport (PPPOE)) index: 
6 addresses:

q里Z么要采取q样斚wq行取散列|感觉有些不太理解Q应该网l接口本w相对而言是ƈ不稳定的

int processId = new java.util.Random().nextInt();
 try {
        processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
 }
 catch ( Throwable t ){
}

RuntimeMXBean是Java虚拟机的q行时系l的理接口Q这里是q回表示正在q行?Java 虚拟机的名称Qƈq行取散列|如果在这q程中出现异常,processId 以随机数的方式l箋计算

_genmachine = machinePiece | processPiece;
最后将机器码块的散列gq程块的散列D行位或运,当然q里是十q制Q你把这里的十进制专为十六进Ӟ׃(x)发现q块的值就是生产objectid中间部分的|q里的构服务端的构徏是有些不一L(fng)Q不q最基本的构建元素还是一致的Q就?strong>TimeStampQMachine QpidQincrement?br />
mongodb的ObejctId生思想在很多方面挺值得我们借鉴的,特别是在大型分布式的开发,如何构徏轻量U的生Q如何将生的负载进行{U,如何以空间换取时间提高生产的最大优化等{?/div>
----------------------------------------

by 陈于?
QQ:34174409
Mail: dongbule@163.com


]]> վ֩ģ壺 | | ͭϿ| | | | ͤ| ߺ| | | | ƽ| | | | ̴| Ϫ| | | Ѯ| | | | ܱ| | | ˮ| | ͬ| ɳ| ɽ| ڶ| | Դ| ɽ| ƽ| Զ| | | Դ| Դ|