MongoDB vs Redis vs Tokyo Tyrant

* MongoDB vs Redis vs Tokyo Tyrant
準備對MongoDB, Redis以及Tokyo Tyrant的讀寫做一個簡單的測試,爲了進行相對公平的測試,需要了解他們背後的實現機制,下面是一些比較:

存儲實現的比較:
   * 內存文件映像(Memory-File Mapping) Redis, MongoDB
   * 文件 + Cache  Tokyo Tyrant
   * 內存: Redis, Tokyo Tyrant
Key/Value索引形式:
  * B+ Tree  : MongoDB, Tokyo Tyrant
  * Hash Table: Redis, Tokyo Tyrant
  * Fixed Length: Tokyo Tyrant

從上面的比較可以看出,Redis和MongoDB是基於系統內存映像文件,數據能命中在內存的時候讀寫操作性能應該是非常強的,當然,反過來,如果數據十分分散不能在內存命中,那麼內存頁的切換開銷將是非常可怕的,MongoDB和Redis數據文件不同的是將數據存放在多個文件中,每當上一個存滿的時候就會創建新的數據空間文件。鑑於MongoDB 是主要比較對象,而其採用B+Tree進行存儲,故TT也使用B+Tree引擎進行比較。

那麼該測試什麼自然就可以得知:儘管使用內存映像文件讀寫操作會很快(快到什麼程度),但是當寫滿內存以後呢?

文件大小限制:
32bit: MongoDB <= 2G
       TT no limits if u ./configure --enable-off
64bit: MongoDB和TT均無限制。

注:Redis 總是受限於內存的大小。

爲了進行相對公平的測試:
首先通過虛擬機對內存的使用進行同等限制,因爲MongoDB和Redi實際上讀寫都是在內存操作的(利用MemoryMap文件),故當數據庫的大小超過內存大小時候的性能尤爲重要。故用虛擬機來設置一個較小的內存大小,來快速觀察數據庫大小超過內存的時候的性能。
這裏設置虛擬機內存256M,實際可使用內存200M左右,CPU 2核,Unbuntu Server 9.10

測試記錄:
Key: 512的隨機字符串
Value: 大約5k的隨機字符串
每項記錄數據大小:大約5.5k
計劃插入數據100000條:5.5k*1000=5.5M*100=550M 數據量大約 550M。

注:key開始是用1k的隨機字符串來測試,但是在測試mongoDB 報告key too large to index, 因此減小key的大小到512字節。

當沒有任何數據的時候:
MongoDB的大小: 
  64M: (db.0, db.1, ..)data FIle
  16M: (database.ns) name space index file.

TC的大小:
133K btree.tcb
256  fixed.tcf
517K hash.tch

Redis的大小:
VirtualMemFile: 41M redis-3546.vm
DB: 0M
注:redis的文件初始大小基本等於你設置的內存以及內存頁的大小,可以自己調整。redis通過定時存盤的策略進行保存,定時策略可以自行設置。
通常情況下,redis的數據庫必須<=內存,如果要讓redis的數據庫大於內存,那麼必須在配置中打開vm_enabled選項(貌似沒用,當插入數據超過內存後,會被Unbuntu的後臺保護進程給殺掉,如果設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值)。

key/value 功能:
Redis: 讀寫key/value,value可以有各種結構,但Value無索引。
MongoDB: 以collection組織,key如果不特別指定將由系統作爲ObjectId產生(指定使用“_id”字段),value是結構化的,value裏的字段可以被索引。
TokyoTyrant: 讀寫key/value,table 數據引擎支持結構化的value和字段索引,其它數據引擎不支持,b+tree可以用key索引。

基準測試機器:
虛擬機是跑在 2 CPU 2.26G Intel Core 2 Duo,內存爲2G
虛擬機:
  CPU  2核
  內存 256M
  操作系統:Unbuntu Server 9.10 32bit

使用軟件版本:
  * MongoDB: mongodb-linux-i686-2010-02-26
  * TokyoTyrant:  TT1.1.40; TC1.4.42
  * Redis: 2010-03-01(GIT SRC)

啓動:
redis-server ./redis.conf(設置了最大內存210兆:maxmemory 210000000, vm-enable=yes,vm-max-memory 20000000,vm-pages 1342177)
./ttserver -port 1974 /data/db/tt.tcb
 bin/mongod -port 1974 --dbpath /data/db/mongo

MongoDB
如上所述測試添加10萬條數據:
內存,剛開始的時候虛擬內存佔用48564,物理內存佔用 3432,在插入2000條數據後,虛擬內存到達143M,物理內存33M,內存增長很迅速。最後虛擬內存穩定在1048M,物理內存則在160M-211M徘徊。
CPU佔用率最低的時候爲6%,最高的時候達到30%,平時在8%-10%之間。
從測試看,每次分配DB空間的時候所有插入操作被凍結,最壞的一次插入2000條耗時1分多(這個時候正好有分配空間文件發生),平時,插入2000條數據大約耗時17-18秒。
最後MongoDB的數據文件總大小達到:977M

接着測試MongoDB讀取10萬條記錄(非命中形式:該key是隨機產生的,因此大都不會存在數據庫中)

內存:虛擬內存穩定在1048M,物理內存佔用在90M-94M。
CPU:最低佔用8%,最高到45%;平時在10%-12%左右。
讀取2000條記錄大約耗時3-4秒,第一次用了6秒。

Redis
同樣測試添加10萬條數據:
內存,開始的時候忘記看了,大致較開始的虛擬內存佔用112M,物理內存82M,在4萬條記錄的時候VM佔用196M,物理內存佔用163M,最後的時候VM佔用237M,物理內存204M。
CPU:最低佔用3%,最高的時候15%,平時在7%-11%之間。
當Redis向磁盤寫入數據的時候,有變慢(2000條記錄耗時21秒),平時存2000條記錄大約耗時18-19秒左右。
不過沒有設定maxmemory的時候,在大約寫入 6萬多個數據後服務器被掛掉。當設置最大使用內存(200M)後,達到內存限制,寫入不了(已寫入48136個數據),但是不會掛了。
Redis文件在寫入48136個數據時候的大小(包括VM文件):277M,其中VM 41M,數據庫236M。

接着測試Redis讀取10萬條記錄(非命中形式:該key大都不會存在數據庫中)
內存:虛擬內存237M,物理內存佔用204M
CPU:在26%-43%

讀取2000條記錄大約耗時在3-4秒。

Tokyo Tyrant
如上所述測試添加10萬條數據:採用默認配置參數運行TT B+Tree
內存:初始的時候VM: 76928 物理內存: 1232,在插入的過程內存的增加很少,在插入到4萬條記錄的時候虛擬內存僅爲99540,物理內存23M,到最後虛擬內存117M,物理內存37M。
CPU佔用率始終穩定在2%

在插入到5萬條記錄前,平均插入2000條耗時約19-20秒,到8萬條記錄前時候,插入2000條耗時20-22秒,再接下來的2萬條,平均插入2000條耗時在慢慢增加並有震盪,28秒,最後到42秒(B+Tree的索引節點在內存中滿了?可能需要調整參數?)。
TT的數據庫只有一個文件大小爲:589M 

接着測試TT讀取10萬條記錄(非命中形式:該key大都不會存在數據庫中)
內存穩定在:VM110M;物理內存36M。
CPU:最低2%,最高6%,平時在4%

讀取2000條記錄大約耗時在7-8秒,偶爾6秒或9秒。

小結:
MongoDB和Redis寫入數據不是直接寫入磁盤,所以當重啓系統時候沒有存盤的數據將全部丟失。TT實際上也有內存緩衝,不過和前者相比要小的多。
以上測試並不完善,只是一個開始,比如沒有測試小數據(以數字作爲key,100字節Value),沒有測試較大的數據(20K左右);沒有測試在命中情況下的性能;沒有測試併發讀寫的性能,據聞MongoDB的併發讀寫效率不是特別出色,MongoDB的特色在於支持的查詢語言非常強大,其語法有點類似於面向對象的查詢語言,幾乎可以實現類似關係數據庫單表查詢的絕大部分功能,並實現了存儲節點的自動sharding管理等配套功能;以及由於MongoDB是分佈在多個文件中,當數據量遠大內存,分佈在足夠多的文件的時候的性能;對開啓同步日誌後的Replication測試....對於TT來說,需要對TT的其它數據引擎進行測試,以及TT的各種數據引擎如何優化?TC/TT在mixi的實際應用當中,存儲了2000萬條以上的數據,同時支撐了上萬個併發連接,是一個久經考驗的項目。TC在保證了極高的併發讀寫性能的同時,具有可靠的數據持久化機制,同時還支持類似關係數據庫表結構的hashtable以及簡單的條件,分頁和排序操作,是一個很棒的NoSQL數據庫。TC的主要缺點是在數據量達到上億級別以後,併發寫數據性能會大幅度下降(讀不受影響),NoSQL: If Only It Was That Easy提到,他們發現在TC裏面插入1.6億條2-20KB數據的時候,寫入性能開始急劇下降。Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據flush到硬盤上進行保存。因爲是純內存操作,Redis的性能非常出色,Redis最大的魅力是支持保存List鏈表和Set集合的數據結構,而且還支持對List進行各種操作,例如從List兩端push和pop數據,取 List區間,排序等等,對Set支持各種集合的並集交集操作,此外單個value的最大限制是1GB,不像memcached只能保存1MB的數據,Redis可以用來實現很多有用的功能,比方說用他的List來做FIFO雙向鏈表,實現一個輕量級的高性能消息隊列服務,用他的Set可以做高性能的tag系統等等。另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一個功能加強版的memcached來用。

測試程序和詳細記錄見附件: testbench.tgz.zip

 

Refs:
* http://porteightyeight.com/2009/11/09/redis-benchmarking-on-amazon-ec2-flexiscale-and-slicehost/
* http://www.eb163.com/club/viewthread.php?tid=2470
* http://timyang.net/data/mcdb-tt-redis/
* http://www.javaeye.com/topic/524977
* http://bjclark.me/2009/08/04/nosql-if-only-it-was-that-easy/

文章來源:http://www.cnblogs.com/riceball/archive/2010/03/05/1679041.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章