2010年3月4日 星期四

[引用]MongoDB入門簡介

引用

特性來源
MongoDB的特性

  • 簡單的查詢語句,沒有Join操作
  • 文檔型存儲,其數據是用二進制的Json格式Bson存儲的。其數據就像Ruby的hashes,或者Python的字典,或者PHP的數組
  • Sharding,MongoDB提供auto-sharding實現數據的擴展性
  • GridFS,MongoDB的提供的文件存儲API
  • 數組索引,你可以對文檔中的某個數組屬性建立索引
  • MapReduce,可以用於進行複雜的統計和並行計算
  • 高性能,通過使用mmap和定時fsync的方法,避免了頻繁IO,使其性能更高

MongoDB的優點

  • 高性能,速度非常快(如果你的內存足夠的話)
  • 沒有固定的表結構,不用為了修改表結構而進行數據遷移
  • 查詢語言簡單,容易上手
  • 使用Sharding實現水平擴展
  • 部署方便

使用MongoDB,你得記住以下幾點:

  • MongoDB 假設你有大磁盤空間
  • MongoDB 假設你的內存也足夠大於放下你的熱數據
  • MongoDB 假設你是部署在64位系統上的(32位有2G的限制,試用還可以)
  • MongoDB 假設你的系統是little-endian的
  • MongoDB 假設你有多台機器(並不專注於單機可靠性)
  • MongoDB 假設你希望用安全換性能,同時允許你用性能換安全

MongoDB在下面領域不太擅長

  • 不太穩定,特別是auto-sharding目前還有很多問題
  • 不支持SQL,這意味著你很多通過SQL接口的工具不再適用
  • 持久化,MongoDB單機可靠性不太好,宕機可能丟失一段時間的數據
  • 相關文檔比較少,新功能都有這個問題
  • 相關人才比較難找,這也是新功能的問題之一


相關網站:
Php 官方

有關於MongoDB的資料現在較少,且大多為英文網站,以上內容大多由筆者翻譯自官網,請翻譯或理解錯誤之處請指證。之後筆者會繼續關注MongoDB,並翻譯「Developer Zone」和「Admin Zone」的相關內容,敬請期待下期內容。
MongoDB是一個基於分佈式文件存儲的數據庫開源項目。由C++語言編寫。旨在為WEB應用提供可護展的高性能數據存儲解決方案。
它的特點是高性能、易部署、易使用,存儲數據非常方便。主要功能特性有:
*面向集合存儲,易存儲對象類型的數據。
*模式自由。
*支持動態查詢。
*支持完全索引,包含內部對象。
*支持查詢。
*支持複製和故障恢復。
*使用高效的二進制數據存儲,包括大型對象(如視頻等)。
*自動處理碎片,以支持雲計算層次的擴展性
*支持RUBY,PYTHON,JAVA,C++,PHP等多種語言。
*文件存儲格式為BSON(一種JSON的擴展)
*可通過網絡訪問
所謂「面向集合」(Collenction-Orented),意思是數據被分組存儲在數據集中,被稱為一個集合(Collenction)。每個 集合在數據庫中都有一個唯一的標識名,並且可以包含無限數目的文檔。集合的概念類似關係型數據庫(RDBMS)裡的表(table),不同的是它不需要定 義任何模式(schema)。
模式自由(schema-free),意味著對於存儲在mongodb數據庫中的文件,我們不需要知道它的任何結構定義。如果需要的話,你完全可以把不同結構的文件存儲在同一個數據庫裡。
存儲在集合中的文檔,被存儲為鍵-值對的形式。鍵用於唯一標識一個文檔,為字符串類型,而值則可以是各中複雜的文件類型。我們稱這種存儲形式為BSON(Binary Serialized dOcument Format)。
MongoDB服務端可運行在Linux、Windows或OS X平台,支持32位和64位應用,默認端口為27017。推薦運行在64位平台,因為MongoDB
在32位模式運行時支持的最大文件尺寸為2GB。
MongoDB把數據存儲在文件中(默認路徑為:/data/db),為提高效率使用內存映射文件進行管理。
安裝:
Linux/OS X下:
1 建立數據目錄
 mkdir -p /data/db
2 下載壓縮包
 curl -O http://downloads.mongodb.org/linux/mongodb-linux-i686-latest.tgz
3 解壓縮文件
 tar xzf mongodb-linux-i386-latest.tgz
4 啟動服務
 bin/mongod run &
5 使用自帶客戶端連接
 /bin/mongo
6 測試
 db.foo.save( { a : 1 } )
 db.foo.findOne()
windows下:
1 建立數據目錄c:\data\db
2 下載壓縮包,解壓文件
3 啟動服務
 bin\mongod.exe run
4 自帶客戶端
 bin\mongon.exe
在LINUX和WINDOWS系統下的使用大同小異,不同的地方主要是默認的數據存儲目錄。LINUX類系統下存放在/data/db下,而WINDOWS
會存放在C:\data\db下。可以在啟動時使用--dbpath參數指定存儲目錄並啟動。如:bin\mongod.exe --dbpath d:\data\mongo
常用啟動參數:
run 直接啟動。例:./mongod run
--dbpath 指定特定存儲目錄啟動,若目錄不存在則創建。例:./mongod --dbpath /var/data/mongo
--port 指定端口啟動。例:./mongod --port 12345
停止MONGO服務:
方法1:服務端停止,可使用Ctrl+C
方法2:在客戶端停止,可先連接客戶端
 ./mongo
 並使用命令
 db.shutdownerver()
 然後退出客戶端
 exit
使用JAVA語言操作MONGODB非常簡單,只要將驅動文件加入到CLASSPATH中就可以使用。
1 建立連接
  要建立MongoDB的連接,你只要指定要連接到的數據庫就可以。這個數據庫不一定存在,如果不存在,MongoDB會先為你建立這個
庫。同時,在連接時你也可以具體指定要連接到的網絡地址和端口。下面的是連接本機數據庫的一些例子:
import com.mongodb.Mongo;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.MongoAdmin;
Mongo db = new Mongo("mydb");
Mongo db = new Mongo("localhost", "mydb");
Mongo db = new Mongo("localhost", 27017, "mydb");
2 安全驗證(非必選)
MongoDB服務可以在安全模式運行,此時任何客戶端要連接數據庫時需使用用戶名和密碼。在JAVA中可使用如下方法連接:
boolean auth = db.authenticate(userName, password);
如果用戶名密碼驗證通過,返回值為true,否則為false
3 獲取集合列表
每個數據庫都存在零個或多個集合,需要時你可以獲得他們的列表:
Set colls = db.getCollectionNames();
for(String s : colls){
 System.out.println(s);
}

4 獲得一個集合
要獲得某個特定集合,你可以指定集合的名字,並使用getCollection()方法:
DBCollection coll = db.getCollection("testCollection");
當你獲取了這個集合對象,你就可以對數據進行增刪查改之類的操作。
5 插入文檔
當你獲得了一個集合對象,你就可以把文檔插入到這個對象中。例如,存在一個JSON式的小文檔:
{
 "name" : "MongoDB",
 "type" : "database",
 "count" : 1,
 "info" : {
   x : 203,
   y : 102
  }
}
請注意,這個文檔包含一個內部文檔。我們可以使用BasicDBObject類來創建這個文檔,並且使用insert()方法方便地將它插入到集
合中。
BasicDBObject doc = new BasicDBObject();
doc.put("name", "MongoDB");
doc.put("type", "database");
doc.put("count", 1);
BasicDBObject info = new BasicDBObject();
info.put("x", 203);
info.put("y", 102);
doc.put("info", info);
coll.insert(doc);
6 使用findOne()查找集合中第一個文檔
要查找我們上一步插入的那個文檔,可以簡單地使用findOne()操作來獲取集合中第一個文檔。這個方法返回一個單一文檔(這是相對於使用DBCursor的find()操作的返回),這對於只有一個文檔或我們剛插入第一個文檔時很有用,因為此時並不需要使用光標。
DBObject myDoc = coll.findOne();
System.out.println(myDoc);
返回類似:
{
 "_id" : "ac907a1f5b9d5e4a233ed300" ,
 "name" : "MongoDB" ,
 "type" : 1 ,
 "info" : {
  "x" : 203 ,
  "y" : 102} ,
 "_ns" : "testCollection"
}
注意_id和_ns元素是由MongoDB自動加入你的文檔。記住:MongoDB內部存儲使用的元素名是以「_」做為開始。
7 加入多種文檔
為了做更多有趣的查詢試驗,讓我們向集合中加入多種文檔類型,象:
{
 "i" : value
}
可以通過循環來實現
for(int i = 0; i < 100; i++){
 coll.insert(new BasicDBObject().append("i", i));
}
注意我們可以在一個集合中插入不同類型的文檔,這就是我們所說的「模式自由」(schema-free)。
8 統計文檔數量
 使用getCount()方法
System.out.println(coll.getCount());
9 使用光標(cursor)來獲取全部文檔
為了獲取集合中的所有文檔,我們可以使用find()方法。這個方法返回一上DBCursor對象,來允許我們將符合查詢條件的文檔迭代
出來。
DBCursor cur = coll.find();
while(cur.hasNext()){
 System.out.println(cur.next());
}
10 在查詢中獲取單一文檔
我們可以創建一個查詢,並傳遞給find()方法來獲取集合中所有文檔的一個子集。例如,我們想要查詢域名為"i",並且值為71的文檔:
BasicDBObject query = new BasicDBObject();
query.put("i", 71);
cur = coll.find(query);
while(cur.hasNext()){
 System.out.println(cur.next());
}
11 使用條件查詢獲取集合
例如,我們想要查詢所有i>50的文檔:
BasicDBObject query = new BasicDBObject();
query.put("i", new BasicDBObject("$gt", 50));
cur = coll.find(query);
while(cur.hasNext()){
 System.out.println(cur.next());
}
當然,我們也可以做20 < i <= 30的查詢
BasicDBObject query = new BasicDBObject();
query.put("i", new BasicDBObject("$gt", 20).append("$lte", 30));
cur = coll.find(query);
while(cur.hasNext()){
 System.out.println(cur.next());
}
12 創建索引
MongoDB支持索引,而且很容易在集合上增加索引。要創建索引,只需要指定要加索引的屬性,並且指定升序(1)或降序即可(-1)。
coll.createIndex(new BasicDBObject("i", 1));
13 獲取索引列表
List list = coll.getIndexInfo();
for(DBObject o : list){
 System.out.println(o);
}

14 MongoDB管理函數
管理函數在com.mongodb.MongoAdmin類中定義。
例A:獲取數據庫列表
 MongoAdmin admin = new MongoAdmin();
 for(String s : admin.getDatabaseNames()){
  System.out.println(s);
 }
例B:獲取數據庫對象
 Mongo m = admin.getDB("mydb");
例C:刪除數據庫
 admin.dropDatabase("mydb");
15 用DBObject存儲JAVA對象
MongoDB for JAVA驅動中提供了用於向數據庫中存儲普通對象的接口DBObject
例如,存在一個需要存儲的對象類Tweet
public class Tweet implements DBObject{
 /*...*/
}
可以使用如下代碼:
Tweet myTweet = new Tweet();
myTweet.put("user", userId);
myTweet.put("message", message);
myTweet.put("date", new Date());
collection.insert(myTweet);
當一個文檔從MongoDB中取出時,它會自動把文檔轉換成DBObject接口類型,要將它實例化為你的對象,需使用
DBCollection.setObjectClass()。
collection.setObjectClass(Tweet);
Tweet myTweet = (Tweet)collection.findOne();
16 JAVA驅動的並發性
JAVA的MongoDB驅動是線程安全的。如果你將它用在WEB服務中,可以創建它的一個單例,並在所有請求中使用它。
然而,如果你需要在一個會話(例如HTTP請求)中保證事務一致性,也許你會希望在這個會話中對驅動使用同一個端口。這僅僅在
請求量非常大的環境中,例如你經常會讀取剛寫入的數據。
為了這一點,你需要使用如下代碼:
Mongo m;
m.restartStart();
// code.........
m.requestDone();

以上介紹了簡單的mongoDB使用,更多信息請查閱MongoDB API for Java。
官方主頁:http://www.mongodb.org/display/DOCS/Home

====================MongoDB VS Mysql  ====================
在32位平台,MongoDB和容易出現「mmap failed with out of memory」錯誤,因為在32位平台MongoDB不允許數據庫文件(累計總和)超過2G,而64位平台沒有這個限制。本想在新系統(64bit)中嘗試採用MongoDB,但做一下MongoDB性能測試,結果卻也報「mmap failed with out of memory」錯誤,好幾天找不到答案,弄了個灰頭土臉

今天終於找到了答案,原來是虛擬內存不足所致,這使我想起某年攢電腦,就是沒聲音,換驅動,換內存、換主板折騰了兩天,最後才發現------------音箱電源沒開!呵呵。google時發現很多同學也碰到類似問題,記錄下來,希望有所幫助。

取消虛擬內存限制的方法:修改etc/profile文件,在文件最後加入一行

ulimit -v unlimited

保存,在命令行執行

# source /etc/profile

(重啟linux也可以生效)


順便記錄測試結果:

# 硬件環境 :suse11-64bit、xeon3.6*2、4G DDR333、scsi73G*2無raid 的老機器
# Client:java


1、連續「INSERT」3千萬條簡單數據(3個字段):平均值大約在27700條/s;同時,插入第一個一百萬和第九個一百萬效率沒有明顯差異,數據文件體積大概在10G,比較大;

2、連續「INSERT」10萬條標準數據(10個字段,含200字節文本字段):平均值大約在19531條/s; 標準數據體積記錄比大概為2.5G/百萬(簡單數據為:330M/百萬);

3、"SELECT"一萬條數據(有索引):46~58ms(個別的也達到180ms),一千條大概在6ms左右,非常穩定; CPU佔用率也很低,2%左右;有一點需要說明的是,百萬容量級別的數據庫和千萬容量級別的數據庫在檢索效率上幾乎沒有什麼差異,我想,這是因為mongodb採用文件內存映射機制,不管多少數據,都是通過內存執行索引檢索,所以數據庫容量跟檢索效率沒有直接聯繫。

注意!在MongoDB中,沒有索引的檢索效率相當低下,所以在進行系統設計時,必須做好索引的規劃,在這點上mongoDB和其他RDBMS其實是非常相似的。


# 對比Mysql 5.1的測試結果
# 採用InnoDB存儲引擎
# Client:java+c3p0


1、連續「INSERT」1千萬條標準數據(單條數據量和Mongodb測試中使用的等同):平均值大約在3448條/s;同時,插入第一個一百萬和第九個一百萬效率沒有明顯差異,數據文件體積3.38G,標準數據體積記錄比大概為346M/百萬,對比Mongodb相當小了,僅僅相當其1/7;

2、"SELECT"一萬條數據(有索引):87~89ms(個別的也達到131ms,但極少),一千條大概在3~4ms左右; 百萬容量級別的數據庫和千萬容量級別的數據庫在檢索效率上也沒有什麼差異。

3、「UPDATE」一萬條數據(有索引):120~123ms,一千條大概在12ms左右;

對比說明(僅針對千萬級別數據庫):

I、插入效率Mongodb1.3是mysql5.1的 5.7 倍;

II、萬條檢索效率Mongodb1.3是mysql5.1的 2.35 倍;

II、千條檢索效率mysql5.1是 Mongodb1.3 的 1.7 倍(這一回合Mysql獲勝);

III、Innodb的update單字段性能相當強悍,平均 83333條/秒(看來有時間我還得把Mongodb的update數據補上)

IV、在測試過程中我發現mysql的表現更為穩定,測試結果跳躍很小,在某次select循環中竟獲得了完全一致的測試結果,一大串88ms,很驚豔。而相對的,Mongodb則產生了較大跳躍;

V、Mongodb在以5.7倍的插入效率完勝mysql的同時,它也損失了約7倍的空間利用率;

注意,你的測試結果很可能和我的有較大差異,原因是mysql不同參數配置對測試結果影響非常大,我記得曾看到網上某個相當全面的測試,結果Mongodb的插入效率竟然可以達到mysql的20倍之多,場景也是千萬級別數據庫。我懷疑他的mysql沒有做優化,或者使用的是MyISAM引擎(MyISAM的插入效率和InnoDB能差一個數量級)。

安裝MongoDB in Windows


相關連結:
Linux 安裝教學

Windows Install MongoDB

【下列文章您可能也有興趣】

2 則留言:

匿名 提到...

謝謝您的翻譯 =)

匿名 提到...

感謝,看到heroku使用mongodb.所以來看看. 好像不錯. :)