1. 程式人生 > >【轉】使用YCSB測試MongoDB的微分片性能

【轉】使用YCSB測試MongoDB的微分片性能

設置 fin use 創建 寫日誌 io瓶頸 納秒 hpu 水平擴展

MongoDB的庫級鎖

MongoDB是目前最流行的NoSQL數據庫,以其自然的文檔型數據結構,靈活的數據模式以及簡單易用的水平擴展能力而獲得了很多開發人員的青睞。 但是金無足赤人無完人,MongoDB不是沒有它的一些弱點,比如說它的庫級鎖就是人們經常抱怨的一個性能瓶頸。簡單來說MongoDB的庫級鎖就是針對某一個數據庫的所有寫操作,必須在獲得這個數據庫僅有的一個互斥鎖情況下才能進行。這個聽上去很糟糕,但實際上由於一個寫操作只是針對於內存數據更新的那一剎那保留鎖,所以每個寫鎖的占用時間通常是在納秒級別。正因為如此,實際應用中庫級鎖並沒有對性能產生人們所擔憂的那樣顯著的影響。

在少數超高並發寫的應用場景下,庫級鎖會可能是一個瓶頸。這個可以通過MongoDB的MMS監控裏面的DB Lock %(或者mongostat的命令行輸出)指標來進行觀察。一般情況下如果DB Lock %超過70-80%並持續就可以認為已經到飽和狀態了。如何解決這個問題呢?

方案一: 分片
這個是MongoDB的標準答案如果你有足夠的硬件資源。 分片是解決大部分性能瓶頸問題的終極方式。

方案二:分庫
這是個非常有效的變通手段。具體做法就是把你的數據分到幾個不同的數據庫裏,然後在應用程序裏的數據訪問層實現一個路由切換,保證數據讀寫會被指向到相應的數據庫裏。一個比較好的例子在一個人口普查的數據庫裏,你可以為每個省建一個單獨的庫。31個數據庫組成一個邏輯大庫。但是這種做法不是什麽時候都能用的,比如說如果你需要很多整庫數據的查詢排序那樣的操作,那麽協調多個庫的結果就會顯得很麻煩或者無法實現。

方案三:等待
MongoDB 2.8 即將發布。2.8的最大改動就是把庫級鎖改成了文檔級鎖。由庫級鎖引起的性能問題應該有望得到較大改善。

方案四:微分片
微分片的定義就是使用MongoDB的分片技術,但是多個或者全部分片Mongod運行在同一臺服務器(服務器可以是物理機或者虛機)上。由於庫級鎖的存在,以及MongoDB對多核CPU的利用率不是很高的特性,微分片在滿足以下條件的場景下會是一個不錯的性能調優手段:
1) 服務器有多核(4或8或更多)CPU
2) 服務器尚未出現IO瓶頸
3) 有足夠內存裝下熱數據(沒有出現頻繁的 page faults)

在這篇文章裏我們通過做一些性能測試來看一下使用微分片技術以後對性能提升的影響。

YCSB 性能測試工具

在開始測試之前,我想首先花點時間介紹一下YCSB這個工具。原因是很多時候我看到開發工程師或者DBA們做測試的時候往往會用一些非常簡單的工具作為客戶端進行高並發的插入或讀取測試。MongoDB本身是一個高性能的數據庫,並發量在適當調優的情況下可以達到每秒數萬級。如果客戶端的代碼是簡單粗暴型的,甚至使用單線程的客戶端,那麽性能測試的瓶頸首先就是在客戶端本身,而不是服務器。所以選擇一個高效的客戶端是一個好的性能測試的重要的第一步。

YCSB是Yahoo開發的一個專門用來對新一代數據庫進行基準測試的工具。全名是Yahoo! Cloud Serving Benchmark。 他們開發這個工具的目的是希望有一個標準的工具用來衡量不同數據庫的性能。YCSB做了很多優化來提高客戶端性能,例如在數據類型上用了最原始的比特數組以減少數據對象本身創建轉換所需的時間等。YCSB的幾大特性:
* 支持常見的數據庫讀寫操作,如插入,修改,刪除及讀取
* 多線程支持。YCSB用Java實現,有很好的多線程支持。
* 靈活定義場景文件。可以通過參數靈活的指定測試場景,如100%插入, 50%讀50%寫等等
* 數據請求分布方式:支持隨機,zipfian(只有小部分的數據得到大部分的訪問請求)以及最新數據幾種請求分布方式
* 可擴展性:可以通過擴展Workload的方式來修改或者擴展YCSB的功能

安裝YCSB

由於YCSB本身會承擔很大的工作量,一般建議部署YCSB在單獨的機器上,最好是4-8核CPU,8G內存以上。YCSB和數據庫服務器最少要保證千兆的帶寬,最好是萬兆級。
* 安裝JDK 1.7
* 下載實現了MongoDB驅動的YCSB編譯版:

資源包下載地址

------------------------------------------分割線------------------------------------------

FTP地址:ftp://ftp1.linuxidc.com

用戶名:ftp1.linuxidc.com

密碼:www.linuxidc.com

在 2015年LinuxIDC.com\7月\使用YCSB測試MongoDB的微分片性能

下載方法見 http://www.linuxidc.com/Linux/2013-10/91140.htm

------------------------------------------分割線------------------------------------------

* 解壓縮
* 進入到ycsb目錄並運行(本地要有一個Mongo數據庫在 27017端口上):
./bin/ycsb run mongodb -P workloads/workloada
* 如果YCSB可以運行則表明安裝成功
你也可以用Git把源文件拉下來自己編譯。需要JDK和Maven工具。Github地址是:https://github.com/achille/YCSB 可以參考這個頁面進行編譯安裝YCSB: https://github.com/achille/YCSB/tree/master/mongodb

YCSB場景文件

使用YCSB測試不同場景只需要提供不同的場景文件就可以。YCSB會按照你的場景文件的屬性而自動生成響應的客戶端請求。在我們這次測試裏我們會使用到幾種場景:
場景S1: 100%插入。用來加載測試數據
場景S2: 寫多讀少 90% 更新 10%讀
場景S3: 混合讀寫 65%讀, 25% 插入, 10% 更新
場景S4: 讀多寫少 90% 讀, 10% 插入、更新
場景S5: 100%讀

如下是其中場景文件S2的內容:
recordcount=5000000
operationcount=100000000
workload=com.yahoo.ycsb.workloads.CoreWorkload
readallfields=true
readproportion=0.1
updateproportion=0.9
scanproportion=0
insertproportion=0
requestdistribution=uniform
insertorder=hashed
fieldlength=250
fieldcount=8
mongodb.url=mongodb://192.168.1.2:27017
mongodb.writeConcern=acknowledged
threadcount=32

一些說明:
* 測試數據包括500萬個文檔(recordcount)
* 每個文檔大小大約2KB(fieldlength x fieldcount)。數據總共大小是10G+600M的索引
* MongoDB數據庫的url是192.168.1.2:27017
* MongoDB的寫安全設置(mongodb.writeConcern)是acknowledged
* 線程數是32(threadcount)
* 插入文檔的順序:哈希/隨機 (insertorder)
* 更新操作: 90% (0.9)
* 讀操作: 10% (0.1)

下載所有場景文件(S1 – S5)(見上面的Linux公社下載地址) 並解壓到上面創建的ycsb目錄下面:

MongoDB配置

本次測試是在AWS的虛擬主機上進行測試的。以下是服務器配置情況:
* OS: Amazon Linux (和CentOS基本類似)
* CPU: 8 vCPU
* RAM: 30G
* Storage: 160G SSD
* Journal: 25G EBS with 1000 PIOPS
* Log: 10G EBS with 250 IOPS
*
* MongoDB: 2.6.0
* Readahead:32

幾點說明:
MongoDB的數據,恢復日誌(journal)以及系統日誌(log)分別用了3個不同的存儲盤。這是一個常見的優化方式,以保證寫日誌的操作不會影響到數據的刷盤IO。另外服務器的readahead設置改到了推薦的32。關於readahead等可以參見: http://www.linuxidc.com/Linux/2015-07/120173.htm

單機基準測試

在我們測試使用微分片性能之前我們首先需要得出單機的最高性能。啟動目標MongoDB服務器,登錄上去後先刪除ycsb數據庫(如果已經存在)
# mongo
> use ycsb
> db.dropDatabase()

場景S1: 數據插入
接下來開始運行YCSB。進到ycsb目錄下,運行以下命令(確認當前目錄下已經有場景文件S1, S2, S3, S4,S5)
./bin/ycsb load mongodb -P S1 -s

如果運行正常,你會看到每隔10秒YCSB打印一下當前狀態,包括每秒的並發率以及平均響應時間。 如:
Loading workload…
Starting test.
0 sec: 0 operations;
mongo connection created with localhost:27017/ycsb
10 sec: 67169 operations; 7002.16 current ops/sec; [INSERT AverageLatency(us)=4546.87]
20 sec: 151295 operations; 7909.24 current ops/sec; [INSERT AverageLatency(us)=3920.9]
30 sec: 223663 operations; 7235.35 current ops/sec; [INSERT AverageLatency(us)=4422.63]

在運行的同時你可以用mongostat(或者更好的選擇:MMS)來監控MongoDB的實時指標,看是否和YCSB的報告大體一致。

運行結束後可以看到類似於如下輸出:
[OVERALL], RunTime(ms), 687134.0
[OVERALL], Throughput(ops/sec), 7295.168457372555

[INSERT], Operations, 5000000
[INSERT], AverageLatency(us), 4509.1105768
[INSERT], MinLatency(us), 126
[INSERT], MaxLatency(us), 3738063
[INSERT], 95thPercentileLatency(ms), 10
[INSERT], 99thPercentileLatency(ms), 37
[INSERT], Return=0, 5000000

這個輸出告訴我們插入了500萬條記錄, 耗時687秒,平均並發量每秒7295條,平均響應時間4.5ms。註意這個數值本身來說對於MongoDB的性能指標沒有任何參考價值。如果你的環境有任意一點不一致,或者插入數據的大小,或者索引的多少不一樣,都會導致結果很大的不同。所以這個值只能在作為本次測試和微分片性能比較的基準值。

在MongoDB方面,要特別註意一下mongostat或者MMS匯報的page faults,network,DB Lock %等指標。如果你的network是1Gb/s 而mongostat匯報了100m的數字,那你的網絡就基本是飽和了。1Gb/s的帶寬也就是128m/s的傳輸速率。在我的這個測試裏network in保持在14-15m/s的樣子,和每秒的並發率及文檔大小(7300x2KB)是一致的。

為了找到一個比較理??的客戶端線程數,我對同樣的操作重復了多次,每一次修改了場景文件裏面的threadcount數值。測試的結果發現到了30 個線程左右並發量就到達了最高值。再增加線程數量性能不再提高。因為我的場景文件中的threadcount值設為32。

現在我們已經在數據庫內有了500萬測試數據,現在我們可以測一下其他的幾個場景。註意:YCSB的第一個參數是測試階段。剛才是數據導入所以第一個參數是”load”。導入完數據後接下來就是運行階段所以第二個參數都是”run”。

場景S2: 寫多讀少
命令:
./bin/ycsb run mongodb -P S2 -s
結果

[OVERALL], Throughput(ops/sec), 12102.2928384723

場景S3: 混合讀寫(65%read)
命令:
./bin/ycsb run mongodb -P S3 -s
結果

[OVERALL], Throughput(ops/sec), 15982.39239483840

場景S4: 讀多寫少
命令:
./bin/ycsb run mongodb -P S4 -s
結果

[OVERALL], Throughput(ops/sec), 19102.39099223948

場景S5: 100% 讀
命令:
./bin/ycsb run mongodb -P S5 -s
結果

[OVERALL], Throughput(ops/sec), 49020.29394020022

微分片測試

剛才我們已經得到了單機在5個場景下的性能指標。接下來我們可以開始測試在微分片以及不同數量微分片的情景下的性能指標。

首先我們停掉單機上MongoDB數據庫。
接下來我們要建一個分片集群。在這裏讓我要推薦給大家一個非常方便的MongoDB工具:mtools https://github.com/rueckstiess/mtools

mtools是幾個MongoDB相關工具的集合,其中的mlaunch可以幫助我們不費吹灰之力地在單機上創建復制集或分片集群。

安裝mtools(需要Python以及Python的包管理工具pip 或者easy_install):
# pip install mtools

# easy_install mtools

然後建一個新的目錄並在新目錄下創建微分片集群:
# mkdir shard2
# cd shard2
# mlaunch –sharded 2 –single

這個命令會在同一臺機器上創建一下4個進程:
* 1 個mongos 在27017 端口
* 1 個配置服務器的mongod 在27020端口
* 2 個分片服務器的mongod 在27018和27019端口

這四個進程組成了具有兩個分片的微分片集群。值得指出的是雖然我們已經搭建了一個分片集群,在這個時候所有的數據還是只會去到其中一個分片,這個分片叫做主分片。要讓MongoDB把數據分布到各個分片上,必須顯式地激活需要分片的數據庫以及集合名。
# mongo
mongos> sh.enableSharding(“ycsb”)
{ “ok” : 1 }
mongos> sh.shardCollection(“ycsb.usertable”, {_id:”hashed”})
{ “collectionsharded” : “ycsb.usertable”, “ok” : 1 }

上述兩個命令分別激活了 ”ycsb“ 數據庫以及庫內 “usertable”集合的分片功能。在對集合開啟分片的時候還需要指定分片鍵。在這裏我們使用了 {_id: “hashed” } 表示使用 _id 字段的哈希值作為分片鍵。哈希值分片鍵對大量寫的場景比較合適,可以把寫操作均勻的分布到各個分片上。

接下來我們可以按順序運行以下5個場景並收集測試結果(註意ycsb的第一個參數):
./bin/ycsb load mongodb -P S1 -s
./bin/ycsb run mongodb -P S2 -s
./bin/ycsb run mongodb -P S3 -s
./bin/ycsb run mongodb -P S4 -s
./bin/ycsb run mongodb -P S5 -s

測試完以後要用下述命令關掉整個集群:
# mlaunch stop

以次類推,可以對4個,6個,和8個成員的微分片集群分別建立單獨的目錄並重復5個場景的測試。如下是所有測試結果:

技術分享

技術分享

技術分享

結論

從上表我們可以得出以下結論

* 微分片在合適的應用場景下可以顯著的提高MongoDB並發量

* 微分片對只讀的應用場景沒有任何幫助

* 微分片對混合讀寫的場景(也是實際中最常見的場景)的優化最好:275%

* 6個微分片就已經基本到了飽和狀態,再增加更多分片已經沒有明顯改善。 這個數字可能會因人而異。

MongoDB 3.0 正式版發布下載 http://www.linuxidc.com/Linux/2015-03/114414.htm

CentOS編譯安裝MongoDB http://www.linuxidc.com/Linux/2012-02/53834.htm

CentOS 編譯安裝 MongoDB與mongoDB的php擴展 http://www.linuxidc.com/Linux/2012-02/53833.htm

CentOS 6 使用 yum 安裝MongoDB及服務器端配置 http://www.linuxidc.com/Linux/2012-08/68196.htm

Ubuntu 13.04下安裝MongoDB2.4.3 http://www.linuxidc.com/Linux/2013-05/84227.htm

MongoDB入門必讀(概念與實戰並重) http://www.linuxidc.com/Linux/2013-07/87105.htm

Ubunu 14.04下MongoDB的安裝指南 http://www.linuxidc.com/Linux/2014-08/105364.htm

《MongoDB 權威指南》(MongoDB: The Definitive Guide)英文文字版[PDF] http://www.linuxidc.com/Linux/2012-07/66735.htm

Nagios監控MongoDB分片集群服務實戰 http://www.linuxidc.com/Linux/2014-10/107826.htm

基於CentOS 6.5操作系統搭建MongoDB服務 http://www.linuxidc.com/Linux/2014-11/108900.htm

MongoDB 的詳細介紹:請點這裏
MongoDB 的下載地址:請點這裏

【轉】使用YCSB測試MongoDB的微分片性能