曾經在收集數據的項目中,用過 mongodb 的數據存儲,但是當數據很大的時候,還是比較的吃力。很可能當時的應用水平不高,也可以是當時的服務器不是很強。 所以這次能力比以前高點了,然後服務器比以前也高端了很多,好嘞 ~再測試下。


    (更多的是單機測試,沒有用複製分片的測試 ~)!


    相比較 mysql,mongodb 數據庫更適合那些讀作業較重的任務模型。mongodb 能充分利用機器的內存資源。如果機器的內存資源豐富的話,mongodb 的查詢效率會快很多。


    這次測試的服務器是 dell 的 r510!


    圖片 15.1 pic


    內存還行,是 48 g 的,本來想讓同事給加滿,但是最終還是沒有說出口 ~


    圖片 15.2 pic


    磁盤是 10 個 2t 的,但是因為格式化的時間太久了,哥們直接把其他的硬盤給拔出來了,就用了三個盤。。。data 目錄沒有做 raid,是為了讓他們體現更好的硬盤速度。


    圖片 15.3 pic


    既然說好了是在 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  </pre>


    圖片 15.4 pic


    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) # 切片  </pre>


    測試的代碼:


    #!/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.timefunc(*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", "rfyiamcool.51cto"],"date": datetime.datetime.uow}posts.insert(post)if __name__ == "__main__":    num = sys.argv[1]    ainsert(int(num))  </pre>


    咱們就先來個百萬的數據做做測試~


    綜合點的數據:


    圖片 15.5 pic


    在 top 下看到的程序占用資源的情況 ~ 我們看到的是有兩個進程的很突出,對頭 ! 正是 mongodb 的服務和我們正在跑的 python 腳本!


    圖片 15.6 pic


    看下服務的 io 的情況 ~


    圖片 15.7 pic


    腳本運行完畢,總結下運行的時間 ~


    圖片 15.8 pic


    查看 mongodb 的狀態~


    他的 insert 也不到 5k ~ 插入量也就 800k 左右 ~


    它的輸出有以下幾列:


    inserts/s 每秒插入次數


    query/s 每秒查詢次數


    update/s 每秒更新次數


    delete/s 每秒刪除次數


    getmore/s 每秒執行 getmore 次數


    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 時間戳


    瞅下麵的監控數據!


    圖片 15.9 pic


    然後我們在測試下在一千萬的數據下的消耗時間情況 ~


    共用了 2294 秒,每秒插入 4359 個數據 ~


    圖片 15.10 pic


    看看他的內存的使用情況:


    虛擬內存在 8 gb 左右,真實內存在 2 gb 左右


    圖片 15.11 pic


    再換成多線程的模式跑跑 ~  個人不太喜歡用多線程,這東西屬於管你忙不忙,老大說了要公平,我就算搶到了,但是沒事幹,我也不讓給你。。。屬於那種蠻幹的機製 ~


    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.uow} #       goodinsert(post)a=threading.thread(target=goodinsert,args=(post,))a.start  </pre>


    圖片 15.12 pic


    python 畢竟有 gil 的限製,雖然 multiprocess 號稱可以解決多進程的。但是用過的朋友知道,這個東西更不靠譜 ~  屬於坑人的東西 ~


    要是有朋友懷疑是 python 的單進程的性能問題,那咱們就用 supervisord 跑了幾個後台的 python 壓力腳本 ~ supervisord 的配置我就不說了,我以前的文章裏麵有詳述的 ~


    圖片 15.13 pic


    cpu 方麵是跑的有點均勻了,但是 mongodb 那邊的壓力總是上不去


    當加大到 16 個後台進程做壓力測試的時候 ~ 大家會發現 insert 很不穩定。 看來他的極限也就是 2 mb 左右的數據 ~


    圖片 15.14 pic


    當減少到 8 個壓力進程的時候 ~ 我們發現他的 insert 慢慢的提供到正常了,也就是說  他真的是 2 mb 的極限 ~


    圖片 15.15 pic


    腳本裏麵是有做有序的 id 插入的,我們試試把 id 的插入給去掉,看看有沒有提升~


    結果和不插入 id 差不多的結果 ~


    圖片 15.16 pic


    調優之後~ 再度測試


    ulimit 的優化


    cat /etc/security/limits.conf*       soft   nofile       102400*       hard   nofile       102400  </pre>


    內核的 tcp 優化


    cat /etc/sysctl.con.ipv4.tcp_syncookies = .ipv4.tcp_tw_reuse = .ipv4.tcp_tw_recycle = .ipv4.tcp_timestsmps = .ipv4.tcp_synack_retries = .ipv4.tcp_syn_retries = .ipv4.tcp_wmem = 8192 436600 87320.ipv4.tcp_rmem = 32768 436600 87320.ipv4.tcp_mem = 94500000 91500000 9270000.ipv4.tcp_max_orphans = 327680.ipv4.tcp_fin_timeout = 30 #直接生效/sbin/sysctl -p  </pre>


    啟動的時候,加上多核的優化參數


    多核問題可以在啟動時加入啟動參數: numactl --interleave=all  </pre>


    insert 的頻率已經到了 2 w 左右 ~  內存占用了 8 g 左右 ~


    圖片 15.17 pic


    圖片 15.18 pic


    我想到的一個方案:


    當然不用非要 celery,就算咱們用 socket 寫分發,和 zeromq 的 pub sub 也可以實現這些的。這是 celery 的調度更加專業點。


    圖片 15.19 pic


    剛才我們測試的都是insert,現在我們再來測試下在千萬級別數據量下的查詢如何:


    查詢正則的,以2開頭的字符


    posts = db.userinfofor i in posts.find({"author":repile(\''^2.mike\'')}):    print i  </pre>


    圖片 15.20 pic


    精確的查詢:


    查詢在 5s 左右 ~


    圖片 15.21 pic


    圖片 15.22 pic


    圖片 15.23 pic


    圖片 15.24 pic


    圖片 15.25 pic


    總結:


    典型的高讀低寫數據庫!


    本文出自 “峰雲,就她了。” 博客,謝絕轉載!

章節目錄

閱讀記錄

Python實戰-從菜鳥到大牛的進階之路所有內容均來自互聯網,鉛筆小說網隻為原作者極客學院的小說進行宣傳。歡迎各位書友支持極客學院並收藏Python實戰-從菜鳥到大牛的進階之路最新章節