* 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-off64bit: 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.tcb256 fixed.tcf517K hash.tchRedis的大小:VirtualMemFile: 41M redis-3546.vmDB: 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,實體記憶體佔用204MCPU:在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