﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-于吉吉的技术博客-随笔分类-MongoDB</title><link>http://www.blogjava.net/dongbule/category/48840.html</link><description>建造高性能门户网</description><language>zh-cn</language><lastBuildDate>Sat, 30 Jul 2011 15:45:22 GMT</lastBuildDate><pubDate>Sat, 30 Jul 2011 15:45:22 GMT</pubDate><ttl>60</ttl><item><title>浅述MongoDB的管理操作</title><link>http://www.blogjava.net/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.blogjava.net/dongbule/archive/2011/07/30/355409.html</guid><wfw:comment>http://www.blogjava.net/dongbule/comments/355409.html</wfw:comment><comments>http://www.blogjava.net/dongbule/archive/2011/07/30/355409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongbule/comments/commentRss/355409.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongbule/services/trackbacks/355409.html</trackback:ping><description><![CDATA[<div>&nbsp;&nbsp;&nbsp;&nbsp; 不知不觉房产系统已经使用MongoDB一年多了，记得一年多以前，正是NOSQL被热炒时，MongoDB更是作为NOSQL中的佼佼者，被炒得火烫，也应该就在当时被这股火烫着了，所以义无反顾的选择了MongoDB，现在想想当时确实有些冲动了，当时MongoDB的资料还是比较少，更别说中文资料了，后来还出现使用MongoDB成功应用的范例Foursquare的宕机事件。现在确实应该很感谢MongoDB为我们的系统服务了一年了，在这一年的时间里，确实出现过不少的小问题，特别是在管理操作上，我想这大概也是因为MongoDB在系统维护上不如Mysql那样有着各种的业界实践，往往就只能通过管理员自己去摸索。<br />
下面将在这一年的一些简单的管理操作做一下记录<br /><br /><div><div>&nbsp;&nbsp;&nbsp; <a href="#x1">Starting and Stopping Mongo</a></div> <div>&nbsp;&nbsp;&nbsp; <a href="#x2">Security and Authentication</a></div> <div>&nbsp;&nbsp;&nbsp; <a href="#x3">Monitoring and Diagnostics</a></div> <div>&nbsp;&nbsp;&nbsp; <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>对了，MongoDB在linux下是无需安装的，从官网上下载下安装包后解压，直接执行mongod，就可以启动MongoDB服务器，当然mongod还有很多的启动选择项，运行mongod --help就可以查看所有的选择项。<br />
<br />
-f [ --config ] arg&nbsp;&nbsp; configuration file specifying additional options<br />
一般来说，启动选择项可以直接写在在mongod后面，也可以指定配置文件，用文件来加载各种启动项，如<br />
/home/mongodb/bin/mongod --config /home/mongodb/conf/mongod.conf</div>
<strong><br />
</strong></div>
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/1.jpg" alt="" width="725" border="0" height="195" /></div>
<div>上面是一台测试机的启动选择项。<br />
<br />
dbpath = /home/mongodb/data<br />
&nbsp;&nbsp;&nbsp; 指定数据库的存储目录，如果不设置则以mongodb的根目录为目录，当MongoDB启动之后，在数据库的存储目录下会创建一个mongod.lock文件，它是用来记录当前的mongod的进程号，同时也用于区分各个mongod的进程实例，所以不同的mongod进程实例是不能用相同的dbpath。<br />
logpath = /home/mongodb/mongodb.log<br />
&nbsp;&nbsp;&nbsp; 指定日志输出的路径，如果没有设置logappend = true，系统会清除原来的日志记录，把已有的文件进行覆盖。<br />
logappend = true<br />
&nbsp;&nbsp;&nbsp; 日志以追加的方式进行记录<br />
bind_ip = 192.168.86.111<br />
&nbsp;&nbsp;&nbsp; 指定对外服务的绑定ip，这里指定内网的ip方式，如果外网无特殊的处理方式是无法进行连接。<br />
port = 27017<br />
&nbsp;&nbsp;&nbsp; 指定服务器的监听端口号，默认是27017，如果单个机器要运行多个mongod进程，则需要给每个进程指定不同的端口号。<br />
fork = true<br />
&nbsp;&nbsp;&nbsp; 指定以守护进程的方式来启动MongoDB，如果不指定，在启动mongod命令是加&#8220;&amp;&#8221;也是可以的。<br />
auth = true<br />
&nbsp;&nbsp;&nbsp; 启动mongodb客户端登录的认证机制。<br />
master = true<br />
&nbsp;&nbsp;&nbsp; 指定该机器为主从模式下的主机器。<br />
配置完配置文件后启栋mongod，启动时要盯着日志文件看，因为日志通常会告诉我们一些错误或警告的信息，这样能够更好的帮助我们了解和避免错误。<br />
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/2.jpg" alt="" width="729" border="0" height="94" /><br />
<br />
<div>这里给出了个提示，使用的是32位的Mongodb，所以MongoDB只是存储最大为2GB的数据。其实这个跟MongoDB的mmap机制有关，如果是64位则不会存在这种限制。<br />
请注意一定要盯着日志看<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&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">100f&nbsp;</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 -9去关闭mongod！这样数据库会不理一切直接杀死该进程，会使得数据文件损坏。<br />
稳妥的方法是使用kill -2 pid去关闭mongod，也就是当mongod进程接受到关闭指令后会等待当前运行操作或文件分配等操作完毕后，关闭所有打开的连接，并将缓存的数据刷新到磁盘后才正式关闭。<br />
最稳妥的方式是使用shutdown命令来结束<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;">&gt;</span><span style="color: #000000;">&nbsp;use&nbsp;admin<br />
switched&nbsp;to&nbsp;db&nbsp;admin<br />
</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;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文档，第一句话就是 Running Without Security(Trusted Environment)，跟我们强调世界上没有什么百分百安全的环境，最好的安全是放在一个安全的环境中运行，这么无底气的话语未免也让人为它的安全担心，不过事实上MongoDB还是有安全认证模式的，只不过跟mysql对比起来有一点简陋。<br />
<br />
<span style="background-color: #ccffcc;">MongoDB的安全</span><br />
MongoDB目前只支持最基本的安全认证，如果我们开启了安全性检查，则只有数据库认证用户才能进行读写操作，当然我们还可以创建读写权限用户和只读权限用户，如果我们在admin的数据库中进行创建用户，那么admin中的用户就会被当作超级用户，超级用户可以读写所有的数据库，并且还可以进行特殊的管理操作，比如可以再创建其他用户关闭进程等操作。<br />
<br />
<span style="background-color: #ccffcc;">配置MongoDb用户认证</span><br />
根据官网上的例子，我们也来创建一个超级用户，一个test库中具有读写操作的普通用户，一个test库中只有读操作的普通用户。</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;">&gt;&nbsp;use&nbsp;admin<br />
switched&nbsp;to&nbsp;db&nbsp;admin<br />
&gt;&nbsp;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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">_id</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;false</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">8658a5bf469e005b047560619ef0d51c</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
}<br />
&gt;&nbsp;use&nbsp;test<br />
switched&nbsp;to&nbsp;db&nbsp;test<br />
&gt;&nbsp;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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;false</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">7a597bef551027cc2161d5e0efe4049e</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
}<br />
&gt;&nbsp;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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;true</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</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>这里cyz是在admin库中创建，属于超级用户，可以对所有库进行操作，在test库中创建的cyz001和cyz002属于test库的操作人员，只能对test库进行相应操作，记得要为安全验证生效需要将启动项auth设置为true。<br />
<br />
<span style="background-color: #ccffcc;">查看用户</span><br />
所有的用户信息都存储在每个数据库的db.system.users中，可以使用find()进行查看<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;">&gt;&nbsp;use&nbsp;admin<br />
switched&nbsp;to&nbsp;db&nbsp;admin<br />
&gt;&nbsp;db.system.users.find()<br />
{&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">_id</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;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;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">user</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</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;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">readOnly</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;false</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">pwd</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;<br />
<br />
</span><span style="color: #000000;">"</span><span style="color: #000000;">8658a5bf469e005b047560619ef0d51c</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;}</span></div>
<br />
其中的pwd是根据用户名和用户密码生成的散列值。<br />
<br />
<span style="background-color: #ccffcc;">修改用户</span><br />
不管是添加用户，修改用户密码，修改用户操作权限都使用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;">&gt;&nbsp;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 />
刚说了MongoDB的安全认证其实还是简陋的，所以我们还是有其他很多的安全考虑。<br />
1.比如说MongoDB传输协议是不加密的，如果需要加密的话，我们可以考虑使用ssh隧道或是他们的技术来对客户端和服务端之间的通讯进行加密。<br />
2.将MongoDB部署在只有客户端服务器才能访问到的环境，比如内网，vpn网络中，可以使用 bind_ip = 本机或内网 。<br />
3.如果确实需要将MongoDB暴露在外部环境可以考虑使用IPTABLES等技术进行访问限制。<br />
<br />
<div><strong>Monitoring and Diagnostics</strong><a name='x3' id='x3'></a><br />
<br />
<div>官网首先给我们推荐了mongostat监控工具，基本上mongostat可以作为一个外部观测MongoDB内部状态指标的工具，并且一秒更新一次，如果出现一些性能问题可以用这里入手进行分析。<br />
<br />
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/3.jpg" alt="" width="1144" border="0" height="122" /></div>
<br />
<div>这里的属性都可以通过mongostat --help进行查看，有几个列需要解释一下，可以帮助到我们发生性能问题时比较准备的找到定位。<br />
<br />
faults：这是一个重要的性能指标，显示你的机器每秒页面故障的数量，这个是mongoDB映射到虚拟地址空间，而不是物理内存，这个值如果飙高的话，可能意味着你的机器没有足够的内存来存储数据和磁盘的访问。<br />
flushes：每秒做了多少次fsync，表面多少次数据被刷新进了磁盘。<br />
mapped：是指mmap有多少数据量，也就是服务器的内存映射，其中包含了虚拟内存和常驻内存。<br />
locked：这个值表面全局写入锁占用了机器多少时间， 当放生全局写入锁时，所有的查询操作都将等待，直到写入锁的解锁，如果这个锁飙高有可能是你的程序那部分出现问题。<br />
idx miss：B树未命中的比例，这个应该是我们查询的命中的实时指数，一般在特定查询中会有用到。<br />
qr | qw：如果有太多的查询进行处理，它们就以一个队列的方式进行，如果这个值飙高的话，那么查询也会变得很慢，因为后面的队列必须等待前面的队列执行完毕，高并发时，一般队列值会升高。<br />
另外我们还可以在mongodb shell中进行检查，使用db.serverStatus()</div>
</div>
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/4.jpg" alt="" width="683" border="0" height="376" /></div>
<br />
<div>基本上db.serverStatus()跟mongostat 差不多，不过它显示的数据更为具体，它也有一个缺陷就是它的数据是静态的，不是实时的。<br />
<br />
<span style="background-color: #ccffcc;">Http Console</span><br />
其实mongodb还提供了一个跟直观的检测工具，在默认情况下，启动mongodb的同时还会启动一个http的服务器，用网页展示的信息比前两个工具来得更加直观，启动默认的监听端口为28017 http：//ip:28017<br />
<br />
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/5.jpg" alt="" width="1178" border="0" height="385" /></div>
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/6.jpg" alt="" width="1151" border="0" height="236" /><br />
基本上我们可以看到查询，复制，锁等等这些的情况，具体的参数还是上官网looklook，http://www.mongodb.org/display/DOCS/Http+Interface<br />
<div>当然了，我们还可以使用其他的专业监控软件进行监控，如nagios，cacti，这些都有mongodb的插件。<br />
<br />
<div><strong>Backups</strong><a name='x4' id='x4'></a><br />
MongoDB的备份机制还是不错的，备份的方式也是很多，这个并不比mysql要差。<br />
<br />
Shutdown and Backup<br />
关闭服务，直接把dbpath参数的目录进行备份，只需把所有的文件进行复制到其他地方就可以，不过如果这个备份是在服务启动时候做的话，有可能备份的文件会被损坏，虽然这种关闭服务的备份很有效也很安全，都效果相当不理想。<br />
<br />
mongodump &amp; mongorestore<br />
mongodump简直就是mysqldump的另一版，如果你使用过mysqldump那就再熟悉不过了，mongodbdump可以使用在各个客户端，对正在运行的mongodb服务做出查询，然后将所有查到的文本写入到客户端的磁盘。</div>
</div>
<img src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/7.jpg" alt="" width="704" border="0" height="257" /><br />
<br />
<div><br />
除了mongodump，MongoDB还提供了从备份中恢复数据的工具mongorestore，mongorestore从mongodump获取结果，并将备份的数据插入到运行的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&nbsp;--db&nbsp;test&nbsp;--collection&nbsp;user&nbsp;--out&nbsp;-&nbsp;&gt;&nbsp;/home/chenyz/cyz.bson<br />
./mongorestore&nbsp;--db&nbsp;test&nbsp;--collection&nbsp;user&nbsp;--directoryperdb&nbsp;/home/chenyz/cyz.bson&nbsp;--drop&nbsp;cyz.bson</span></div>
<br />
<div>上面的例子中，指定了要备份的db和要备份的collection，--drop表明要在恢复前删除集合，否则，数据将和现有的集合数据合并。<br />
<br />
<span style="background-color: #ccffcc;">主从备份</span><br />
上面说的几种备份数据方式已经很灵活了，但都不及在从服务器上备份来得方便，从服务器的数据几乎是于主服务器进行同步，涉及到主从方面还有很多，从服务器备份就不放在这里讲了。<br />
<br />
<span style="background-color: #ccffcc;">修复</span><br />
遇到一些停电，或非法关闭mongodb，不合理备份文件的操作，往往会出现文件损毁的提示，幸好，mongodb内置的修复功能会试着去恢复损坏的文件。<br />
操作很简单，只需在启动mongod 加入 --repair启动项，系统就会将所有的文件导入忽略那些无效的文档然后进行导入，完成之后，会重新建立索引，数据量大的话需要花费很长的时间，因为所有的文件都需要进行验证，所有的索引都需要重建，另外修复数据库还能起到压缩数据的作用，闲置的空间，碎片在修复后会被重新回收进行使用。<br />
<br />
另外在shell中也可以直接进行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;">&gt;&nbsp;db.repairDatabase()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">ok</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
}</span></div>
</div><img src ="http://www.blogjava.net/dongbule/aggbug/355409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongbule/" target="_blank">陈于喆</a> 2011-07-30 18:23 <a href="http://www.blogjava.net/dongbule/archive/2011/07/30/355409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说MongoDB的ObjectId</title><link>http://www.blogjava.net/dongbule/archive/2011/06/12/352138.html</link><dc:creator>陈于喆</dc:creator><author>陈于喆</author><pubDate>Sun, 12 Jun 2011 10:30:00 GMT</pubDate><guid>http://www.blogjava.net/dongbule/archive/2011/06/12/352138.html</guid><wfw:comment>http://www.blogjava.net/dongbule/comments/352138.html</wfw:comment><comments>http://www.blogjava.net/dongbule/archive/2011/06/12/352138.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/dongbule/comments/commentRss/352138.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongbule/services/trackbacks/352138.html</trackback:ping><description><![CDATA[<div>前段时间有个朋友问我，分布式主键生成策略在我们这边是怎么实现的，当时我给的答案是sequence，当然这在不高并发的情况下是没有任何问题，实际上，我们的主键生成是可控的，但如果是在分布式高并发的情况下，那肯定是有问题的。<br /><br />突然想起mongodb的objectid，记得以前看过文档，objectid是一种轻量型的，不同的机器都能用全局唯一的同种方法轻量的生成它，而不是采用传统的自增的主键策略，因为在多台服务器上同步自动增加主键既费力又费时，不得不佩服，mongodb从开始设计就被定义为分布式数据库。<br />下面深入一点来翻翻这个Objectid的底细，在mongodb集合中的每个document中都必须有一个"_id"建，这个键的值可以是任何类型的，在默认的情况下是个Objectid对象。<br />当我们让一个collection中插入一条不带_id的记录，系统会自动地生成一个_id的key</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;">&gt;&nbsp;db.t_test.insert({"name":"cyz"})<br />&gt;&nbsp;db.t_test.findOne({"name":"cyz"})<br />{&nbsp;"_id"&nbsp;:&nbsp;ObjectId("4df2dcec2cdcd20936a8b817"),&nbsp;"name"&nbsp;:&nbsp;"cyz"&nbsp;}</span></div><br /><div>可以发现这里多出一个Objectid类型的_id，当然了，这个_id是系统默认生成的，你也可以为其指定一个值，不过在同一collections中该值必须是唯一的<br /><br />把 ObjectId("4df2dcec2cdcd20936a8b817")这串值拿出来并对照官网的解析来深入分析。<br /><br />"4df2dcec2cdcd20936a8b817" 以这段字符串为例来进行解析，这是一个24位的字符串，看起来很长，很难理解，实际上它是由ObjectId(string)所创建的一组十六进制的字符，每个字节两位的十六进制数字，总共使用了12字节的存储空间，可能有些朋友会感到很奇怪，居然是用了12个字节，而mysql的INT类型也只有4个字节，不过按照现在的存储设备，多出来的这点字节也应该不会成为什么瓶颈，实际上，mongodb在设计上无处不在的体现着用空间换时间的思想，接下看吧<br /><br />下面是官网指定Bson中ObjectId的详细规范<br /><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/dongbule/46046/o_111.PNG" /><br /><br /><div><strong>TimeStamp</strong><br />前4位是一个unix的时间戳，是一个int类别，我们将上面的例子中的objectid的前4位进行提取&#8220;4df2dcec&#8221;，然后再将他们安装十六进制专为十进制：&#8220;1307761900&#8221;，这个数字就是一个时间戳，为了让效果更佳明显，我们将这个时间戳转换成我们习惯的时间格式</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;">$&nbsp;date&nbsp;-d&nbsp;'1970-01-01&nbsp;UTC&nbsp;1307761900&nbsp;&nbsp;sec'&nbsp;&nbsp;-u<br />2011年&nbsp;06月&nbsp;11日&nbsp;星期六&nbsp;03:11:40&nbsp;UTC</span></div><br /><div>前4个字节其实隐藏了文档创建的时间，并且时间戳处在于字符的最前面，这就意味着ObjectId大致会按照插入进行排序，这对于某些方面起到很大作用，如作为索引提高搜索效率等等。使用时间戳还有一个好处是，某些客户端驱动可以通过ObjectId解析出该记录是何时插入的，这也解答了我们平时快速连续创建多个Objectid时，会发现前几位数字很少发现变化的现实，因为使用的是当前时间，很多用户担心要对服务器进行时间同步，其实这个时间戳的真实值并不重要，只要其总不停增加就好。</div><br /><div><strong>Machine </strong><br />接下来的三个字节，就是 2cdcd2 ,这三个字节是所在主机的唯一标识符，一般是机器主机名的散列值，这样就确保了不同主机生成不同的机器hash值，确保在分布式中不造成冲突，这也就是在同一台机器生成的objectid中间的字符串都是一模一样的原因。<br /><br /><strong>pid</strong><br />上面的Machine是为了确保在不同机器产生的objectid不冲突，而pid就是为了在同一台机器不同的mongodb进程产生了objectid不冲突，接下来的0936两位就是产生objectid的进程标识符。<br /><br /><strong>increment</strong><br />前面的九个字节是保证了一秒内不同机器不同进程生成objectid不冲突，这后面的三个字节a8b817，是一个自动增加的计数器，用来确保在同一秒内产生的objectid也不会发现冲突，允许256的3次方等于16777216条记录的唯一性。</div><br /><div><strong>客户端生成</strong><br />mongodb产生objectid还有一个更大的优势，就是mongodb可以通过自身的服务来产生objectid，也可以通过客户端的驱动程序来产生，如果你仔细看文档你会感叹，mongodb的设计无处不在的使<br /><br />用空间换时间的思想，比较objectid是轻量级，但服务端产生也必须开销时间，所以能从服务器转移到客户端驱动程序完成的就尽量的转移，必须将事务扔给客户端来完成，减低服务端的开销，另还有一点原因就是扩展应用层比扩展数据库层要变量得多。<br /><br />好吧，既然我们了解到我们的程序产生objectid是在客户端完成，那再继续，进一步了解，打开<strong>mongodb java driver源码</strong>，无源码可以到mongodb官网进行下载，下面摘录部分代码<br /><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: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ObjectId&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Comparable</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ObjectId</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;,&nbsp;java.io.Serializable&nbsp;{<br /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;_time;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;_machine;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;_inc;<br /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ObjectId(&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[]&nbsp;b&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;b.length&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IllegalArgumentException(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">need&nbsp;12&nbsp;bytes</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteBuffer&nbsp;bb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ByteBuffer.wrap(&nbsp;b&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_time&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;bb.getInt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_machine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;bb.getInt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_inc&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;bb.getInt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_new&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ObjectId(&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;time&nbsp;,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;machine&nbsp;,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;inc&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_time&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;time;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_machine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;machine;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_inc&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;inc;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_new&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ObjectId(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_time&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">)&nbsp;(System.currentTimeMillis()&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_machine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;_genmachine;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_inc&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;_nextInc.getAndIncrement();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_new&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />（完整代码请查看源码）</span></div><br /><div>这里可以发现ObjectId的构建可以有多种方式，可以由自己制定字节，也可以指定时间，机器码和自增值，这里重点看看驱动程序默认的构建，也就是public ObjectId()<br />可以看到objectid主要由_time _machine _inc 所组成，其中 _time直接由(System.currentTimeMillis() / 1000)计算出所谓的时间戳，这里很简单，接下来是重点，主要看看<strong>机器码和进程码</strong>的构建</div></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;">&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;_genmachine;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;machinePiece;</span><span style="color: #008000;">//</span><span style="color: #008000;">机器码块</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;sb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;StringBuilder();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Enumeration</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">NetworkInterface</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;e&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;NetworkInterface.getNetworkInterfaces();</span><span style="color: #008000;">//</span><span style="color: #008000;">NetworkInterface此类表示一个由名称和分配给此接口的&nbsp;IP&nbsp;地址列表组成的网络接口，它用于标识将多播组加入的本地接口，这里通过NetworkInterface此机器上所有的接口</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(&nbsp;e.hasMoreElements()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NetworkInterface&nbsp;ni&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;e.nextElement();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(&nbsp;ni.toString()&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;machinePiece&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;sb.toString().hashCode()&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">将得到所有接口的字符串进行取散列值</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOGGER.fine(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">machine&nbsp;piece&nbsp;post:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Integer.toHexString(&nbsp;machinePiece&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;processPiece;</span><span style="color: #008000;">//</span><span style="color: #008000;">进程块</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;processId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;java.util.Random().nextInt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();</span><span style="color: #008000;">//</span><span style="color: #008000;">RuntimeMXBean是Java虚拟机的运行时系统的管理接口，这里是返回表示正在运行的&nbsp;Java&nbsp;虚拟机的名称，并进行取散列值。</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(&nbsp;Throwable&nbsp;t&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader&nbsp;loader&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ObjectId.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getClassLoader();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;loaderId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;loader&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;System.identityHashCode(loader)&nbsp;:&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;sb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;StringBuilder();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(Integer.toHexString(processId));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(Integer.toHexString(loaderId));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processPiece&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;sb.toString().hashCode()&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xFFFF</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOGGER.fine(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">process&nbsp;piece:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Integer.toHexString(&nbsp;processPiece&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_genmachine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;machinePiece&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;processPiece;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">最后将机器码块的散列值与进程块的散列值进行位或运算，得到&nbsp;_genmachine&nbsp;</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOGGER.fine(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">machine&nbsp;:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Integer.toHexString(&nbsp;_genmachine&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(&nbsp;java.io.IOException&nbsp;ioe&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;RuntimeException(&nbsp;ioe&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></div><br /><div><strong>&nbsp;Enumeration&lt;NetworkInterface&gt; e = NetworkInterface.getNetworkInterfaces();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( e.hasMoreElements() ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NetworkInterface ni = e.nextElement();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sb.append( ni.toString() );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;machinePiece = sb.toString().hashCode() &lt;&lt; 16;</strong><br />这里的NetworkInterface.getNetworkInterfaces();取得的接口通常是按名称（如 "le0"）区分的，大约是下面的类型</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;">name:lo&nbsp;(Software&nbsp;Loopback&nbsp;Interface&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;index:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;addresses:<br /></span><span style="color: #000000;">/</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">0</span><span style="color: #000000;">:</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br /></span><span style="color: #000000;">/</span><span style="color: #000000;">127.0</span><span style="color: #000000;">.</span><span style="color: #000000;">0.1</span><span style="color: #000000;">;<br />name:net0&nbsp;(WAN&nbsp;Miniport&nbsp;(SSTP))&nbsp;index:&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">&nbsp;addresses:<br />name:net1&nbsp;(WAN&nbsp;Miniport&nbsp;(IKEv2))&nbsp;index:&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">&nbsp;addresses:<br />name:net2&nbsp;(WAN&nbsp;Miniport&nbsp;(L2TP))&nbsp;index:&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">&nbsp;addresses:<br />name:net3&nbsp;(WAN&nbsp;Miniport&nbsp;(PPTP))&nbsp;index:&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">&nbsp;addresses:<br />name:ppp0&nbsp;(WAN&nbsp;Miniport&nbsp;(PPPOE))&nbsp;index:&nbsp;</span><span style="color: #000000;">6</span><span style="color: #000000;">&nbsp;addresses:</span></div><br /><div>这里为什么要采取这样方面进行取散列值，感觉有些不太理解，应该网络接口本身相对而言是并不稳定的<br /><br /><div><strong>int processId = new java.util.Random().nextInt();<br />&nbsp;try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();<br />&nbsp;}<br />&nbsp;catch ( Throwable t ){<br />}</strong><br />RuntimeMXBean是Java虚拟机的运行时系统的管理接口，这里是返回表示正在运行的 Java 虚拟机的名称，并进行取散列值，如果在这过程中出现异常，processId 将以随机数的方式继续计算<br /><br /><strong>_genmachine = machinePiece | processPiece;</strong><br /><div>最后将机器码块的散列值与进程块的散列值进行位或运算，当然这里是十进制，你把这里的十进制专为十六进制，就会发现这块的值就是生产objectid中间部分的值，这里的构建跟服务端的构建是有些不一样的，不过最基本的构建元素还是一致的，就是<strong>TimeStamp，Machine ，pid，increment</strong>。<br /><br />mongodb的ObejctId生产思想在很多方面挺值得我们借鉴的，特别是在大型分布式的开发，如何构建轻量级的生产，如何将生产的负载进行转移，如何以空间换取时间提高生产的最大优化等等。</div></div>----------------------------------------<br />  <br />  by 陈于喆 <br />  QQ:34174409<br />  Mail: dongbule@163.com<br /></div><img src ="http://www.blogjava.net/dongbule/aggbug/352138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongbule/" target="_blank">陈于喆</a> 2011-06-12 18:30 <a href="http://www.blogjava.net/dongbule/archive/2011/06/12/352138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>