zoukankan      html  css  js  c++  java
  • 32位下操作mongodb心得

    本文出处:http://blog.csdn.net/chaijunkun/article/details/7236911,转载请注明。

    随着互联网的变革,互联网的内容生成方式也逐渐地从网站生成转为用户生成。这种变化不仅仅是内容生成对象的转变那样简单的问题,随之带来的就是互联网数据的大爆炸(big bang)。社交网络的兴起也给互联网相关技术提出了挑战。

    MongoDB应用广泛,作为一款无关系型数据库产品,它具有伸缩性、高性能、开源、模式开放和基于文档等特性。因此很值得研究。

    通过本文,我将与你分享:

    1. MongoDB如何申请磁盘空间,采用何种策略申请

    2. 印证网上流传的32位平台下MongoDB数据库不能大于2GB的说法

    既然MongoDB擅长的是海量数据处理,对它进行研究避免不了使用庞大的数据来做测试。好了,问题来了——上哪找庞大的数据呢?

    公司里当然有那么多数据了,可是由于保密方面的要求,不能拿来做测试,更不能写出来。因此我想到了一个好东西——CSDN密码库。

    这个200+M的小家伙在年前闹得沸沸扬扬,弄得人人自危,掀起了一场改密码风暴,反正也被公布出来了,拿它来做测试不是很好么?

    至于从哪里得到的这个密码库,我就不说了,身为ITer的你一定有办法搞到手的。我的这个版本一共有6428632条数据,每条数据的结构都很简单:

    用户名 # 密码 # 邮箱

    分析的时候只需要一行行地读出来,然后按照“#”分割,最后对每一个字段都trim一下就可以了。

    我做本次实验使用的平台如下:

    Windows XP SP3(当然是32位版啦)

    奔腾E5300 CPU

    2G内存

    首先按照上一篇文章建立了本地的MongoDB服务(文章链接:http://blog.csdn.net/chaijunkun/article/details/7227967)

    然后使用MongoDB-Driver操作MongoDB,使用Morphia做ORM。

    下面是我写的数据迁移代码(从密码库txt文件存储至MongoDB)

    CSDNData.java

    [java] view plaincopy
     
    1. package net.csdn.blog.chaijunkun.entities;  
    2.   
    3. import org.bson.types.ObjectId;  
    4.   
    5. import com.google.code.morphia.annotations.Entity;  
    6. import com.google.code.morphia.annotations.Id;  
    7.   
    8. @Entity(value="users", noClassnameStored=true)  
    9. public class CSDNData {  
    10.     @Id  
    11.     private ObjectId id;  
    12.     private Integer idx;  
    13.     private String userName;  
    14.     private String password;  
    15.     private String email;  
    16.     public ObjectId getId() {  
    17.         return id;  
    18.     }  
    19.     public void setId(ObjectId id) {  
    20.         this.id = id;  
    21.     }  
    22.     public Integer getIdx() {  
    23.         return idx;  
    24.     }  
    25.     public void setIdx(Integer idx) {  
    26.         this.idx = idx;  
    27.     }  
    28.     public String getUserName() {  
    29.         return userName;  
    30.     }  
    31.     public void setUserName(String userName) {  
    32.         this.userName = userName;  
    33.     }  
    34.     public String getPassword() {  
    35.         return password;  
    36.     }  
    37.     public void setPassword(String password) {  
    38.         this.password = password;  
    39.     }  
    40.     public String getEmail() {  
    41.         return email;  
    42.     }  
    43.     public void setEmail(String email) {  
    44.         this.email = email;  
    45.     }  
    46. }  


    在实体中我增加了用于标识文档序号的idx字段。

    接下来就是数据转储代码了:

    TransformData.java

    [java] view plaincopy
     
    1. package net.csdn.blog.chaijunkun;  
    2.   
    3. import java.net.UnknownHostException;  
    4.   
    5. import net.csdn.blog.chaijunkun.entities.CSDNData;  
    6. import com.google.code.morphia.Datastore;  
    7. import com.google.code.morphia.Key;  
    8. import com.google.code.morphia.Morphia;  
    9. import com.mongodb.Mongo;  
    10. import com.mongodb.MongoException;  
    11.   
    12. import java.io.BufferedReader;  
    13. import java.io.File;  
    14. import java.io.FileNotFoundException;  
    15. import java.io.FileReader;  
    16. import java.io.IOException;  
    17. import java.io.UnsupportedEncodingException;  
    18.   
    19. public class TransformData {  
    20.     public static void main(String[] args) throws UnknownHostException, MongoException{  
    21.         Mongo connection= new Mongo("localhost", 27017);  
    22.         Morphia morphia= new Morphia();  
    23.         Datastore ds= morphia.createDatastore(connection, "csdn");  
    24.           
    25.         File dataFile= new File("D:\www.csdn.net.txt");  
    26.         FileReader fr;  
    27.         Integer idx=1;   
    28.         try {  
    29.             fr = new FileReader(dataFile);  
    30.             BufferedReader br=new BufferedReader(fr);  
    31.             String currentLine= null;  
    32.             try {  
    33.                 while((currentLine= br.readLine())!=null){  
    34.                     //读取操作  
    35.                     if (currentLine.trim().equals("")){  
    36.                         continue;  
    37.                     }  
    38.                       
    39.                     String[] record= currentLine.split("#");  
    40.                     if (record.length>=3){  
    41.                         CSDNData csdnData= new CSDNData();  
    42.                         csdnData.setIdx(idx);  
    43.                         csdnData.setUserName(record[0].trim());  
    44.                         csdnData.setPassword(record[1].trim());  
    45.                         csdnData.setEmail(record[2].trim());  
    46.                         Key<CSDNData> key= ds.save(csdnData);  
    47.                         System.out.println("已存入:"+ key.getId() + ",文档序列:"+ idx);  
    48.                     }else{  
    49.                         System.out.println("文档序列"+ idx+ "发生错误:"+currentLine);  
    50.                         break;  
    51.                     }  
    52.                       
    53.                       
    54.                     idx++;  
    55.                 }  
    56.             } catch (UnsupportedEncodingException e) {  
    57.                 // TODO Auto-generated catch block  
    58.                 e.printStackTrace();  
    59.             } catch (IOException e) {  
    60.                 // TODO Auto-generated catch block  
    61.                 e.printStackTrace();  
    62.             }  
    63.         } catch (FileNotFoundException e) {  
    64.             // TODO Auto-generated catch block  
    65.             e.printStackTrace();  
    66.         }         
    67.     }  
    68. }  

    就这样运行程序,密码库中的数据就开始向MongoDB中传送了。

    由于我启动MongoDB服务时使用了参数--directoryperdb,因此会在数据目录下建立csdn目录。

    随着数据越来越多,MongoDB中的自动分片算法开始起作用:

    [plain] view plaincopy
     
    1. C:MongoDBcsdn>dir  
    2.  Volume in drive C has no label.  
    3.  Volume Serial Number is F474-EC39  
    4.   
    5.  Directory of C:MongoDBcsdn  
    6.   
    7. 2012-02-06  14:59    <DIR>          .  
    8. 2012-02-06  14:59    <DIR>          ..  
    9. 2012-02-06  14:40        16,777,216 csdn.0  
    10. 2012-02-06  14:40        33,554,432 csdn.1  
    11. 2012-02-06  14:41        67,108,864 csdn.2  
    12. 2012-02-06  14:42       134,217,728 csdn.3  
    13. 2012-02-06  14:45       268,435,456 csdn.4  
    14. 2012-02-06  14:49       536,608,768 csdn.5  
    15. 2012-02-06  14:59       536,608,768 csdn.6  
    16. 2012-02-06  14:40        16,777,216 csdn.ns  
    17.                8 File(s)  1,610,088,448 bytes  
    18.                2 Dir(s)  20,669,665,280 bytes free  
    19.   
    20. C:MongoDBcsdn>  

    最早生成的文件分别是csdn.0和csdn.ns,当0分片存储满后建立1分片(csdn.1文件),可以仔细观察其文件大小

    csdn.ns==>  16MB
    csdn.0  ==>  16MB
    csdn.1  ==>  32MB
    csdn.2  ==>  64MB
    csdn.3  ==>128MB
    csdn.4  ==>256MB
    csdn.5  ==>512MB

    但是在第7个分片(csdn.6)时发生了问题,第7分片目前大小是512MB,和第6分片大小一致。这如何解释呢?

    其实MongoDB在存储时并不是按照实际数据量来严格申请磁盘空间。它会随着当前数据量的多少(说白了就是判断当前到第几个分片了)来动态申请空间,一次申请多少完全取决于前一分片的大小。

    例如csdn.0文件默认是16MB,当csdn.1刚出现时,它的大小也是16MB,也就是第一次申请磁盘空间16MB,随后16MB装满了,而该分片就会再次申请16MB空间。

    总而言之就是当前分片所占的最大空间将由2次申请磁盘空间来实现的(第一分片除外,固定16MB),而每一次申请的大小都是前一分片的最大尺寸。

    为什么在第7分片发生了问题呢?这个就是我要说的下一个问题了:

    在MongoDB的README中有如下一段话:

    [plain] view plaincopy
     
    1. MongoDB uses memory mapped files.  If built as a 32 bit executable, you will  
    2.  not be able to work with large (multi-gigabyte) databases.  However, 32 bit  
    3.  builds work fine with small development databases.  

    翻译如下:

    [plain] view plaincopy
     
    1. MongoDB使用内存映射文件,如果构建成32位可执行程序,您将不能使其工作在大数据库(若干GB)方式下  


    我们来计算一下:

    csdn.ns(16MB)+csdn.0(16MB)+csdn.1(32MB)+csdn.2(64MB)+csdn.3(128MB)+csdn.4(256MB)+csdn.5(512MB)+csdn.6(512MB)=1536MB,

    也就是说在发生问题之前数据库的总大小已经到达了1536MB。这时候由于存储的需求,按照算法,将再次申请512MB空间(csdn.5的大小)给csdn.6。

    试想一下,如果申请成功了,数据库的文件将达到多少?1536MB+512MB=2048,正好等于2GB。这与网上的”32位平台下,MongoDB最大不能超过2GB“的说法一致。

    那么我是怎么知道出问题了呢?

    很简单,代码在传送了5790004条记录后当要写入第5790005条记录时抛出了异常:

    [java] view plaincopy
     
    1. 已存入:4f2f7a4e5a2768e3dced269b,文档序列:5790001  
    2. 已存入:4f2f7a4e5a2768e3dced269c,文档序列:5790002  
    3. 已存入:4f2f7a4e5a2768e3dced269d,文档序列:5790003  
    4. 已存入:4f2f7a4e5a2768e3dced269e,文档序列:5790004  
    5. Exception in thread "main" com.mongodb.MongoException: can't map file memory - mongo requires 64 bit build for larger datasets  

    根据异常信息我们也可以知道:无法映射内存文件,MongoDB为大数据集需要使用64位构建。

  • 相关阅读:
    Leaf-spine data center architectures
    centreon 画图x轴乱码
    二分图匹配
    牛客练习赛17
    HDU-4550-贪心
    HDU-4511-ac自动机+dp
    UVA-11761-马尔可夫/记忆化搜索
    HDU-3853-期望/dp/坑
    HDU-4405-期望dp
    zoj-3329-期望/dp/方程优化
  • 原文地址:https://www.cnblogs.com/yxpblog/p/4296853.html
Copyright © 2011-2022 走看看