新聞中心
曾經(jīng)在收集數(shù)據(jù)的項(xiàng)目中,用過mongodb的數(shù)據(jù)存儲,但是當(dāng)數(shù)據(jù)很大的時候,還是比較的吃力。很可能當(dāng)時的應(yīng)用水平不高,也可以是當(dāng)時的服務(wù)器不是很強(qiáng)。 所以這次能力比以前高點(diǎn)了,然后服務(wù)器比以前也高端了很多,好嘞 ~再測試下。

(更多的是單機(jī)測試,沒有用復(fù)制分片的測試 ~)!
相比較MySQL,MongoDB數(shù)據(jù)庫更適合那些讀作業(yè)較重的任務(wù)模型。MongoDB能充分利用機(jī)器的內(nèi)存資源。如果機(jī)器的內(nèi)存資源豐富的話,MongoDB的查詢效率會快很多。
這次測試的服務(wù)器是dell 的 r510!
內(nèi)存還行,是48G的,本來想讓同事給加滿,但是最終還是沒有說出口 ~
磁盤是10個2T的,但是因?yàn)楦袷交臅r間太久了,哥們直接把其他的硬盤給拔出來了,就用了三個盤。。。data目錄沒有做raid,是為了讓他們體現(xiàn)更好的硬盤速度。
既然說好了是在python下的應(yīng)用測試,那就需要安裝mongodb python下的模塊 !
對了,不知道m(xù)ongodb-server的安裝要不要說下?
| 1 2 3 4 5 | cat /etc/yum.repos.d/ 10 .repo [10gen] name=10gen Repository baseurl=http: //downloads-distro.mongodb.org/repo/redhat/os/x86_64 gpgcheck= 0 |
Pymongo的基本用法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | from pymongo import * # 導(dǎo)包 con = Connection(...) # 鏈接 db = con.database # 鏈接數(shù)據(jù)庫 db.authenticate( 'username' , 'password' ) # 登錄 db.drop_collection( 'users' ) #刪除表 db.logout() # 退出 db.collection_names() # 查看所有表 db.users.count() # 查詢數(shù)量 db.users.find_one({ 'name' : 'xiaoming' }) # 單個對象 db.users.find({ 'age' : 18 }) # 所有對象 db.users.find({ 'id' : 64 }, { 'age' : 1 , '_id' : 0 }) # 返回一些字段 默認(rèn)_id總是返回的 0 不返回 1 返回 db.users.find({}).sort({ 'age' : 1 }) # 排序 db.users.find({}).skip( 2 ).limit( 5 ) # 切片 |
測試的代碼:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/usr/bin/env python from pymongo import Connection import time,datetime import os,sys connection = Connection( '127.0.0.1' , 27017 ) db = connection[ 'xiaorui' ] def func_time(func): def _wrapper(*args,**kwargs): start = time.time() func(*args,**kwargs) print func.__name__, 'run:' ,time.time()-start return _wrapper @func_time def ainsert(num): posts = db.userinfo for x in range(num): post = { "_id" : str(x), "author" : str(x)+ "Mike" , "text" : "My first blog post!" , "tags" : [ "xiaorui" , "xiaorui.cc" , "rfyiamcool.51cto" ], "date" : datetime.datetime.utcnow()} posts.insert(post) if __name__ == "__main__" : num = sys.argv[ 1 ] ainsert( int (num)) |
咱們就先來個百萬的數(shù)據(jù)做做測試~
綜合點(diǎn)的數(shù)據(jù):
在top下看到的程序占用資源的情況 ~ 我們看到的是有兩個進(jìn)程的很突出,對頭 ! 正是mongodb的服務(wù)和我們正在跑的python腳本 !
看下服務(wù)的io的情況 ~
腳本運(yùn)行完畢,總結(jié)下運(yùn)行的時間 ~
查看mongodb的狀態(tài)~
他的insert也不到5k ~ 插入量也就800k左右 ~
它的輸出有以下幾列:
inserts/s 每秒插入次數(shù)
query/s 每秒查詢次數(shù)
update/s 每秒更新次數(shù)
delete/s 每秒刪除次數(shù)
getmore/s 每秒執(zhí)行g(shù)etmore次數(shù)
command/s 每秒的命令數(shù),比以上插入、查找、更新、刪除的綜合還多,還統(tǒng)計(jì)了別的命令
flushs/s 每秒執(zhí)行fsync將數(shù)據(jù)寫入硬盤的次數(shù)。
mapped/s 所有的被mmap的數(shù)據(jù)量,單位是MB,
vsize 虛擬內(nèi)存使用量,單位MB
res 物理內(nèi)存使用量,單位MB
faults/s 每秒訪問失敗數(shù)(只有Linux有),數(shù)據(jù)被交換出物理內(nèi)存,放到swap。不要超過100,否則就是機(jī)器內(nèi)存太小,造成頻繁swap寫入。此時要升級內(nèi)存或者擴(kuò)展
locked % 被鎖的時間百分比,盡量控制在50%以下吧
idx miss % 索引不命中所占百分比。如果太高的話就要考慮索引是不是少了
q t|r|w 當(dāng)Mongodb接收到太多的命令而數(shù)據(jù)庫被鎖住無法執(zhí)行完成,它會將命令加入隊(duì)列。這一欄顯示了總共、讀、寫3個隊(duì)列的長度,都為0的話表示mongo毫無壓力。高并發(fā)時,一般隊(duì)列值會升高。
conn 當(dāng)前連接數(shù)
time 時間戳
瞅下面的監(jiān)控?cái)?shù)據(jù) !
然后我們在測試下在一千萬的數(shù)據(jù)下的消耗時間情況 ~
共用了2294秒,每秒插入 4359個數(shù)據(jù) ~
看看他的內(nèi)存的使用情況:
虛擬內(nèi)存在8gb左右,真實(shí)內(nèi)存在2gb左右
再換成多線程的模式跑跑 ~ 個人不太喜歡用多線程,這東西屬于管你忙不忙,老大說了要公平,我就算搶到了,但是沒事干,我也不讓給你。。。屬于那種蠻干的機(jī)制 ~
nima,要比單個跑的慢呀 ~ 線程這東西咋會這么不靠譜呀 ~
應(yīng)該是沒有做線程池pool,拉取隊(duì)列。導(dǎo)致線程過多導(dǎo)致的。不然不可能比單進(jìn)程都要慢~
還有就是像這些涉及到IO的東西,交給協(xié)程的事件框架更加合理點(diǎn) ?。?!
| 1 2 3 4 5 6 7 8 9 10 11 12 | def goodinsert(a): posts.insert(a) def ainsert(num): for x in range(num): post = { "_id" : str(x), "author" : str(x)+ "Mike" , "text" : "My first blog post!" , "tags" : [ "mongodb" , "python" , "pymongo" ], "date" : datetime.datetime.utcnow()} # goodinsert(post) a=threading.Thread(target=goodinsert,args=(post,)) a.start() |
python畢竟有g(shù)il的限制,雖然multiprocess號稱可以解決多進(jìn)程的。但是用過的朋友知道,這個東西更不靠譜 ~ 屬于坑人的東西 ~
要是有朋友懷疑是python的單進(jìn)程的性能問題,那咱們就用supervisord跑了幾個后臺的python壓力腳本 ~ supervisord的配置我就不說了,我以前的文章里面有詳述的 ~
cpu方面是跑的有點(diǎn)均勻了,但是mongodb那邊的壓力總是上不去
當(dāng)加大到16個后臺進(jìn)程做壓力測試的時候 ~ 大家會發(fā)現(xiàn)insert很不穩(wěn)定。 看來他的極限也就是2MB左右的數(shù)據(jù) ~
當(dāng)減少到8個壓力進(jìn)程的時候 ~ 我們發(fā)現(xiàn)他的insert慢慢的提供到正常了,也就是說 他真的是2MB的極限 ~
腳本里面是有做有序的id插入的,我們試試把id的插入給去掉,看看有沒有提升~
結(jié)果和不插入id差不多的結(jié)果 ~
調(diào)優(yōu)之后~ 再度測試
ulimit的優(yōu)化
| 1 2 3 | cat /etc/security/limits.conf * soft nofile 102400 * hard nofile 102400 |
內(nèi)核的tcp優(yōu)化
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | cat /etc/sysctl.conf net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_timestsmps = 0 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_wmem = 8192 436600 873200 net.ipv4.tcp_rmem = 32768 436600 873200 net.ipv4.tcp_mem = 94500000 91500000 92700000 net.ipv4.tcp_max_orphans = 3276800 net.ipv4.tcp_fin_timeout = 30 #直接生效 /sbin/sysctl -p |
啟動的時候,加上多核的優(yōu)化參數(shù)
| 1 | 多核問題可以在啟動時加入啟動參數(shù): numactl --interleave=all |
insert的頻率已經(jīng)到了2w左右 ~ 內(nèi)存占用了8G左右 ~
我想到的一個方案:
當(dāng)然不用非要celery,就算咱們用socket寫分發(fā),和zeromq的pub sub也可以實(shí)現(xiàn)這些的。這是celery的調(diào)度更加專業(yè)點(diǎn)。
剛才我們測試的都是insert,現(xiàn)在我們再來測試下在***別數(shù)據(jù)量下的查詢?nèi)绾危?/p>
查詢正則的,以2開頭的字符
| 1 2 3 | posts = db.userinfo for i in posts.find({ "author" :re.compile( '^2.Mike' )}): print i |
精確的查詢:
查詢在5s左右 ~
總結(jié):
典型的高讀低寫數(shù)據(jù)庫 !
有時間加索引再度測試下 !
本文出自 “峰云,就她了?!?博客,謝絕轉(zhuǎn)載!
當(dāng)前名稱:Mongodb千萬級數(shù)據(jù)在python下的綜合壓力測試及應(yīng)用探討
標(biāo)題URL:http://m.fisionsoft.com.cn/article/cdodiph.html


咨詢
建站咨詢
