文章出處

背景說明

近期北京理財頻道反饋用來存放股市實時數據的MongoDB數據庫寫響應請求很慢,難以跟上業務寫入速度水平。我們分析了線上現場的情況,發現去年升級到SSD磁盤后,數據持久化的磁盤IO開銷已經不是瓶頸.通過日志分析,線上單次寫入(更新)請求大多在數十毫秒這個級別,數據庫端觀察幾個主要的db在繁忙時通常有95%以上的時間在進行鎖等待。線上數據庫并發很高,接近1000個連接,所以懷疑是并發爭用表鎖導致性能不足。

 

我們知道MongoDB的mmap存儲引擎一直是庫/表級鎖,因此任何寫操作并發越高鎖爭用造成的性能損耗越大。為了改善鎖并發性能MongoDB,升級到行級鎖引擎應該能夠改善線上更新數據的性能瓶頸。3.0的WT存儲引擎和toku開發的tokumx存儲引擎都號稱實現了行級鎖和多版本并發控制。因此,為了確定我們升級的方向,決定使用線上類似的場景,對三種存儲引擎進行一次性能測試,評估最能改善并發更新寫的方案。

 

我們取得了線上最繁忙的stock和stock_status數據,并且仿照線上并發更新最頻繁的根據證券code更新的方式,在測試環境進行測驗。

 

硬件環境

CPU:  24 核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz

內存:  48G

磁盤:  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的數據庫,等待應用反饋回歸測試結果,如果一切順利,打算盡快升級

 

原創文章  

禁止其他公眾賬號轉載


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()