曾經在收集資料的項目中,用過mongodb的資料存放區,但是當資料很大的時候,還是比較的吃力。很可能當時的應用水平不高,也可以是當時的伺服器不是很強。 所以這次能力比以前高點了,然後伺服器比以前也高端了很多,好嘞 ~再測試下。
更多的是單機測試,沒有用複製分區的測試 ~)!
相比較MySQL,MongoDB資料庫更適合那些讀作業較重的任務模型。MongoDB能充分利用機器的記憶體資源。如果機器的記憶體資源豐富的話,MongoDB的查詢效率會快很多。
這次測試的伺服器是dell 的 r510!
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225163627-0.jpg" title="2013-11-20_235424.jpg" alt="235621353.jpg" />
記憶體還行,是48G的,本來想讓同事給加滿,但是最終還是沒有說出口 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225162Z1-1.jpg" title="2013-11-20_235403.jpg" alt="235739466.jpg" />磁碟是10個2T的,但是因為格式化的時間太久了,哥們直接把其他的硬碟給拔出來了,就用了三個盤。。。data目錄沒有做raid,是為了讓他們體現更好的硬碟速度。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225163T1-2.jpg" title="2013-11-20_235808.jpg" alt="235930831.jpg" />
既然說好了是在python下的應用測試,那就需要安裝mongodb python下的模組 !
對了,不知道mongodb-server的安裝要不要說下?
cat /etc/yum.repos.d/10.repo[10gen]name=10gen Repositorybaseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64gpgcheck=0
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225162062-3.jpg" title="2013-11-21_000313.jpg" alt="000408806.jpg" />
Pymongo的基本用法
from pymongo import * # 導包con = Connection(...) # 連結db = con.database # 連結資料庫db.authenticate('username', 'password') # 登入db.drop_collection('users') #刪除表db.logout() # 退出db.collection_names() # 查看所有表db.users.count() # 查詢數量db.users.find_one({'name' : 'xiaoming'}) # 單個對象db.users.find({'age' : 18}) # 所有對象db.users.find({'id':64}, {'age':1,'_id':0}) # 返回一些欄位 預設_id總是返回的 0不返回 1返回db.users.find({}).sort({'age': 1}) # 排序db.users.find({}).skip(2).limit(5) # 切片
測試的代碼:
#!/usr/bin/env pythonfrom pymongo import Connectionimport time,datetimeimport os,sysconnection = 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_timedef 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))
咱們就先來個百萬的資料做做測試~
綜合點的資料:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225163450-4.jpg" title="2013-11-21_001805.jpg" alt="002508131.jpg" />
在top下看到的程式佔用資源的情況 ~ 我們看到的是有兩個進程的很突出,對頭 ! 正是mongodb的服務和我們正在跑的python指令碼 !
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225161Z0-5.jpg" title="2013-11-21_001824.jpg" alt="002605855.jpg" />
看下服務的io的情況 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251634c-6.jpg" title="io.jpg" alt="002741677.jpg" />
指令碼運行完畢,總結下啟動並執行時間 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251C0Q-7.jpg" title="2013-11-21_002156.jpg" alt="002816300.jpg" />
查看mongodb的狀態~
他的insert也不到5k ~ 插入量也就800k左右 ~
它的輸出有以下幾列:
inserts/s 每秒插入次數
query/s 每秒查詢次數
update/s 每秒更新次數
delete/s 每秒刪除次數
getmore/s 每秒執行getmore次數
command/s 每秒的命令數,比以上插入、尋找、更新、刪除的綜合還多,還統計了別的命令
flushs/s 每秒執行fsync將資料寫入硬碟的次數。
mapped/s 所有的被mmap的資料量,單位是MB,
vsize 虛擬記憶體使用量,單位MB
res 實體記憶體使用量,單位MB
faults/s 每秒訪問失敗數只有Linux有),資料被交換出實體記憶體,放到swap。不要超過100,否則就是機器記憶體太小,造成頻繁swap寫入。此時要升級記憶體或者擴充
locked % 被鎖的時間百分比,盡量控制在50%以下吧
idx miss % 索引不命中所佔百分比。如果太高的話就要考慮索引是不是少了
q t|r|w 當Mongodb接收到太多的命令而資料庫被鎖住無法執行完成,它會將命令排入佇列。這一欄顯示了總共、讀、寫3個隊列的長度,都為0的話表示mongo毫無壓力。高並發時,一般隊列值會升高。
conn 當前串連數
time 時間戳記
瞅下面的監控資料 !
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251C307-8.jpg" title="2013-11-21_002937.jpg" alt="003310317.jpg" />
然後我們在測試下在一千萬的資料下的消耗時間情況 ~
共用了2294秒,每秒插入 4359個資料 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251AX8-9.jpg" title="99.jpg" alt="010140526.jpg" />看看他的記憶體的使用方式:
虛擬記憶體在8gb左右,真實記憶體在2gb左右
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251645J-10.jpg" title="2013-11-21_010204.jpg" alt="010245223.jpg" />
再換成多線程的模式跑跑 ~ 個人不太喜歡用多線程,這東西屬於管你忙不忙,老大說了要公平,我就算搶到了,但是沒事幹,我也不讓給你。。。屬於那種蠻乾的機制 ~
nima,要比單個跑的慢呀 ~ 線程這東西咋會這麼不靠譜呀 ~
應該是沒有做線程池pool,拉取隊列。導致線程過多導致的。不然不可能比單進程都要慢~
還有就是像這些涉及到IO的東西,交給協程的事件架構更加合理點 !!!
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()
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251B3F-11.jpg" title="2013-11-21_023449.jpg" alt="023536618.jpg" />
python畢竟有gil的限制,雖然multiprocess號稱可以解決多進程的。但是用過的朋友知道,這個東西更不靠譜 ~ 屬於坑人的東西 ~
要是有朋友懷疑是python的單進程的效能問題,那咱們就用supervisord跑了幾個背景python壓力指令碼 ~ supervisord的配置我就不說了,我以前的文章裡面有詳述的 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251C4c-12.jpg" title="2013-11-21_014849.jpg" alt="015034609.jpg" />
cpu方面是跑的有點均勻了,但是mongodb那邊的壓力總是上不去
當加大到16個後台進程做壓力測試的時候 ~ 大家會發現insert很不穩定。 看來他的極限也就是2MB左右的資料 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251AL8-13.jpg" title="2013-11-21_015353.jpg" alt="015448335.jpg" />
當減少到8個壓力進程的時候 ~ 我們發現他的insert慢慢的提供到正常了,也就是說 他真的是2MB的極限 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225163494-14.jpg" title="2013-11-21_015416.jpg" alt="015559242.jpg" />
指令碼裡面是有做有序的id插入的,我們試試把id的插入給去掉,看看有沒有提升~
結果和不插入id差不多的結果 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225164257-15.jpg" title="2013-11-21_085147.jpg" alt="085221687.jpg" />
調優之後~ 再度測試
ulimit的最佳化
cat /etc/security/limits.conf* soft nofile 102400* hard nofile 102400
核心的tcp最佳化
cat /etc/sysctl.confnet.ipv4.tcp_syncookies = 1net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_timestsmps = 0net.ipv4.tcp_synack_retries = 2net.ipv4.tcp_syn_retries = 2net.ipv4.tcp_wmem = 8192 436600 873200net.ipv4.tcp_rmem = 32768 436600 873200net.ipv4.tcp_mem = 94500000 91500000 92700000net.ipv4.tcp_max_orphans = 3276800net.ipv4.tcp_fin_timeout = 30#直接生效/sbin/sysctl -p
啟動的時候,加上多核的最佳化參數
多核問題可以在啟動時加入啟動參數: numactl --interleave=all
insert的頻率已經到了2w左右 ~ 記憶體佔用了8G左右 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225161242-16.png" style="float:none;" title="2013-11-21 14:24:37的螢幕.png" alt="143629965.png" />
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251B257-17.png" style="float:none;" title="2013-11-21 14:32:29的螢幕.png" alt="143630829.png" />
我想到的一個方案:
當然不用非要celery,就算咱們用socket寫分發,和zeromq的pub sub也可以實現這些的。這是celery的調度更加專業點。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225162429-18.jpg" title="kk.jpg" alt="021114653.jpg" />
剛才我們測試的都是insert,現在我們再來測試下在千萬層級資料量下的查詢如何:
查詢正則的,以2開頭的字元
posts = db.userinfofor i in posts.find({"author":re.compile('^2.Mike')}): print i
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251AV0-19.jpg" title="2013-11-21_013429.jpg" alt="013606877.jpg" />
精確的查詢:
查詢在5s左右 ~
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225164543-20.jpg" title="2013-11-21_013858.jpg" alt="013944841.jpg" />
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251A1N-21.jpg" style="float:none;" title="ops.jpg" alt="225244177.jpg" />650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251B207-22.jpg" title="mem.jpg" style="float:none;" alt="225244313.jpg" />
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/12251C942-23.jpg" style="float:none;" title="load.jpg" alt="225244670.jpg" />
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131229/1225161495-24.jpg" style="float:none;" title="cpu.jpg" alt="225244798.jpg" />
總結:
典型的高讀低寫資料庫 !
有時間加索引再度測試下 !
本文出自 “峰雲,就她了。” 部落格,謝絕轉載!