背景說明python
近期北京理財頻道反饋用來存放股市實時數據的MongoDB數據庫寫響應請求很慢,難以跟上業務寫入速度水平。咱們分析了線上現場的狀況,發現去年升級到SSD磁盤後,數據持久化的磁盤IO開銷已經不是瓶頸.經過日誌分析,線上單次寫入(更新)請求大多在數十毫秒這個級別,數據庫端觀察幾個主要的db在繁忙時一般有95%以上的時間在進行鎖等待。線上數據庫併發很高,接近1000個鏈接,因此懷疑是併發爭用表鎖致使性能不足。web
咱們知道MongoDB的mmap存儲引擎一直是庫/表級鎖,所以任何寫操做併發越高鎖爭用形成的性能損耗越大。爲了改善鎖併發性能MongoDB,升級到行級鎖引擎應該可以改善線上更新數據的性能瓶頸。3.0的WT存儲引擎和toku開發的tokumx存儲引擎都號稱實現了行級鎖和多版本併發控制。所以,爲了肯定咱們升級的方向,決定使用線上相似的場景,對三種存儲引擎進行一次性能測試,評估最能改善併發更新寫的方案。數據庫
咱們取得了線上最繁忙的stock和stock_status數據,而且仿照線上併發更新最頻繁的根據證券code更新的方式,在測試環境進行測驗。併發
硬件環境app
CPU: 24 核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHzdom
內存: 48Gasync
磁盤: SSD函數
MongoDB版本高併發
1. Mmap存儲引擎 MongoDB-2.6.9性能
2. Toku存儲引擎 MongoDB-2.4.10
3. WiredTiger存儲引擎 MongoDB 3.0.5
測試用例
從線上將股票信息表數據導入測試環境,建立與線上一致的索引,股票碼code_id爲惟一索引。
單純寫測試:從股票表stock中抽取1000個code_id,用隨機函數獲取其中一個code_id,對這一行數據進行一次update操做;
讀寫混合測試:在必定併發度的寫操做狀況下,以一樣併發度經過code_id讀取一行數據,讀寫混合比例爲1:1。
測試腳本
1.寫測試腳本
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import multiprocessing
import time
import random
import pymongo
client = pymongo.MongoClient("172.17.1.234", 27017) db = client.stock
def get_id(): code_list = [1000個code_id] code_loct = random.randint(0, 999) up_value = random.randint(10, 99)/10.0 return code_list[code_loct], up_value
def update_func():
while True: code_id, up_value = get_id()
db.stock.update_one({"CODE":str(code_id)},{"$set":
{"ASK1":str(up_value),"ASK2":str(up_value),"ASK3":str(up_value),"ASK4":str(up_value),"ASK5":str(up_value),"ASKVOL1":str(up_value),"ASKVOL2":str(up_value),"ASKVOL3":str(up_value),"ASKVOL4":str(up_value),"ASKVOL5":str(up_value),"BID1":str(up_value),"BID2":str(up_value),"BID3":str(up_value),"BID4":str(up_value),"BID5":str(up_value)}})
if __name__ == "__main__": pool = multiprocessing.Pool(processes=併發度)
for i in xrange(10000000): pool.apply_async(update_func,) pool.close() pool.join()
print "\n" print "All done."
2.讀測試腳本
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import multiprocessing
import time
import random
import pymongo
client = pymongo.MongoClient("172.17.1.234", 27017) db = client.stock
def get_id(): code_list = [1000個code_id] code_loct = random.randint(0, 499)
return code_list[code_loct]
def update_func():
while True: code_id = get_id()
db.stock.find_one({"CODE":str(code_id)},{"CODE":1,"ASK1":1,"ASK2":1})
if __name__ == "__main__": pool = multiprocessing.Pool(processes=併發度)
for i in xrange(1000000): pool.apply_async(update_func,) pool.close() pool.join()
print "\n" print "All done."
測試結果
1.單純寫的測試結果
結論:WiredTiger在純update測試場景中性能明顯高於toku和mmap
a.toku和mmap併發度超過32後TPS穩定在1.4萬到1.5萬左右,此時總體DB的鎖爭用很是高
b.WiredTiger表現良好,128併發度時TPS處理能力達到5萬多,更高併發下處理能力逐漸降低,穩定在3萬到4萬之間

2.讀寫1比1混合的測試結果
結論:WiredTiger在讀寫1比1混合測試場景中,綜合能力優於toku和mmap,且讀寫互不影響,都比較穩健
a.WiredTiger在讀寫混合測試場景中更新性能明顯高於toku和mmap,讀性能在高於256時不如toku和mmap,可是讀寫互不影響且性能較爲穩定
b.mmap在高併發狀況下讀性能良好,可是更新性能降低很明顯,受讀的影響較大
c.toku在讀寫兩端就像是WiredTiger和mmap的中庸版
讀寫混合模式下,WiredTiger在32到256之間的併發狀況下,綜合能力優於toku和mmap,其餘併發度狀況下讀寫綜合能力相近
小結
由測試結果能夠看出,3.0的WT引擎對多併發更新的場景明顯好於其餘兩種引擎,TPS性能有較大的提高,所以建議線上升級3.0而且更換存儲引擎。
目前線上已經在測試環境部署了3.0的數據庫,等待應用反饋迴歸測試結果,若是一切順利,打算儘快升級
原創文章
禁止其餘公衆帳號轉載