MongoDB性能測(cè)試

Nodejs編寫的應(yīng)用,后端連MongoDB進(jìn)行持久化存儲(chǔ)。Mongodb分別有兩個(gè)版本,分別跑在虛擬機(jī)和kubernetes里面,進(jìn)行讀寫性能測(cè)試

測(cè)試基線

分別在虛擬機(jī)和K8S中安裝Mongodb數(shù)據(jù)庫,版本為4.0.18,測(cè)試目標(biāo)為考察mongodb跑在虛擬機(jī)和K8S中的性能差異

  • 虛擬機(jī)配置:2C4G
  • K8S中的pod配額(limits)為2C4G,mongodb后端掛接ceph rbd存儲(chǔ)

壓力測(cè)試使用的軟件為wrk,地址為:https://github.com/wg/wrk。這里推薦一下wrk,可以以極少的線程模擬出高并發(fā)的場(chǎng)景,比之前用的ab好用了不是一點(diǎn)。

Node性能測(cè)試

首先我們來看下node的基礎(chǔ)性能測(cè)試,眾所周知nodejs是異步非阻塞的編程模型,在處理高并發(fā)場(chǎng)景有天然優(yōu)勢(shì),這邊我們測(cè)試一下,在不接后端數(shù)據(jù)庫的情況下,純nodejs處理(比如請(qǐng)求校驗(yàn)錯(cuò)誤),性能可以到多少。node應(yīng)用也是跑在k8里的,設(shè)置的配額(limits)為6C,并發(fā)數(shù)設(shè)置為200:

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    61.84ms   26.29ms 479.18ms   94.73%
    Req/Sec     1.65k   209.52     2.03k    85.00%
  32905 requests in 10.01s, 8.38MB read
  Non-2xx or 3xx responses: 32905
Requests/sec:   3287.93
Transfer/sec:    857.30KB

可以看到QPS在3200多,而且這個(gè)數(shù)值是線性增長(zhǎng)的,即如果起兩個(gè)實(shí)例,則QPS可以到6000多,3個(gè)實(shí)例的話可以到9000多。記住這個(gè)數(shù)據(jù),這是后面進(jìn)行比較的基礎(chǔ)(單個(gè)node的最高性能,也就是加上數(shù)據(jù)庫以后理論上也不會(huì)超過這個(gè)QPS)

虛擬機(jī)Mongo實(shí)例測(cè)試

node后端接入跑在虛擬機(jī)上的mongodb實(shí)例(mongo本身均為單實(shí)例,未做集群),我們來看一下:

寫入測(cè)試

單node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   810.15ms    1.62s    9.80s    88.46%
    Req/Sec   317.73    113.81   727.00     71.36%
  6323 requests in 10.02s, 3.41MB read
Requests/sec:    631.35
Transfer/sec:    348.95KB

cpu使用率為20%

2個(gè)node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua -d 30s http://22.196.66.200:31010/users
Running 30s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   176.34ms  266.36ms   3.79s    97.12%
    Req/Sec   710.32    168.50     1.01k    63.83%
  42445 requests in 30.03s, 22.91MB read
Requests/sec:   1413.36
Transfer/sec:    781.11KB

cpu使用率為40%

5個(gè)node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua -d 30s http://22.196.66.200:31010/users
Running 30s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    60.30ms   35.27ms   1.06s    96.79%
    Req/Sec     1.71k   236.41     2.18k    76.83%
  102166 requests in 30.02s, 55.12MB read
Requests/sec:   3403.58
Transfer/sec:      1.84MB

cpu使用率為60%

寫入測(cè)試總結(jié)

總體來說隨著副本數(shù)增加,整體性能呈線性增加,5副本時(shí)mongo數(shù)據(jù)庫的cpu也只有60%,應(yīng)該說還有余量。應(yīng)該是mongodb默認(rèn)的連接池的限制起了作用(默認(rèn)連接數(shù)為5個(gè))

讀取測(cè)試

數(shù)據(jù)庫中放置測(cè)試數(shù)據(jù)780萬條,根據(jù)ObjectId關(guān)鍵字進(jìn)行查詢:

單node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
Running 10s test @ http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   726.33ms    1.46s    8.79s    88.23%
    Req/Sec   524.42    158.59     1.00k    72.00%
  10448 requests in 10.01s, 5.59MB read
Requests/sec:   1043.39
Transfer/sec:    572.14KB

cpu利用率16%

5個(gè)node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -d 30s http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
Running 30s test @ http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    33.17ms   18.24ms 584.77ms   87.45%
    Req/Sec     3.10k   303.76     3.64k    85.17%
  184886 requests in 30.01s, 98.91MB read
Requests/sec:   6159.80
Transfer/sec:      3.30MB

cpu利用率63%

讀取測(cè)試總結(jié)

讀取方面,因?yàn)橛芯彺娴年P(guān)系(命中率較高),整體的QPS比寫入還略高,基本也是隨副本數(shù)呈線性增長(zhǎng)的態(tài)勢(shì)。

kubernetes mongo 實(shí)例測(cè)試

接下來我們測(cè)試一下,mongodb跑在k8s中,后端掛ceph塊存儲(chǔ)的性能(k8的work與ceph集群連接為千兆網(wǎng)卡)

寫入測(cè)試

單node副本

[root@dce304-cal-vm3 ~]# wrk -c 500 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 500 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   470.51ms    1.13s    9.77s    93.67%
    Req/Sec   398.62    150.61     0.91k    71.81%
  7654 requests in 10.02s, 4.13MB read
Requests/sec:    763.54
Transfer/sec:    422.03KB

cpu使用率 13.7%

2個(gè)node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   281.70ms  628.13ms   5.50s    93.31%
    Req/Sec   738.18    142.56     1.14k    79.50%
  14710 requests in 10.01s, 7.94MB read
Requests/sec:   1468.87
Transfer/sec:    811.73KB

cpu使用率25%

5個(gè)node 副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    61.27ms   29.67ms 453.58ms   83.79%
    Req/Sec     1.66k   233.53     2.09k    93.00%
  33091 requests in 10.02s, 17.85MB read
Requests/sec:   3303.79
Transfer/sec:      1.78MB

cpu使用率57%

寫入測(cè)試總結(jié)

可以看到使用網(wǎng)絡(luò)存儲(chǔ)和本地磁盤,在寫入性能上基本沒有區(qū)別,在單副本情況下,使用rbd的性能甚至還好于本地磁盤。

讀取測(cè)試

單node 副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
Running 10s test @ http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   564.36ms    1.19s    7.58s    89.28%
    Req/Sec   610.83    224.26     1.01k    58.38%
  12119 requests in 10.02s, 6.49MB read
Requests/sec:   1210.00
Transfer/sec:    663.37KB

cpu使用率20%

5個(gè)node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
Running 10s test @ http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    36.44ms   26.26ms 542.40ms   96.53%
    Req/Sec     2.91k   498.88     3.58k    87.00%
  58009 requests in 10.01s, 31.03MB read
Requests/sec:   5792.89
Transfer/sec:      3.10MB

cpu使用率91%

測(cè)試總結(jié)

可以看到,不管是跑在虛擬機(jī)中,還是k8s里,測(cè)試的結(jié)果是基本接近的。而按照我們的一般認(rèn)知,本地磁盤的讀寫性能肯定還是要高于網(wǎng)絡(luò)存儲(chǔ)的,這里面的關(guān)鍵,還是要說到mongodb的讀寫機(jī)制。mongo作為一款典型的nosql數(shù)據(jù)庫,其絕大部分的操作都是在內(nèi)存中完成的。MongoDB把文檔寫進(jìn)內(nèi)存之后就返回了,所以說QPS基本不受后端存儲(chǔ)性能的影響。

這邊簡(jiǎn)單說一下mongodb數(shù)據(jù)存儲(chǔ)的原理:

內(nèi)存映射機(jī)制

Mongo使用了內(nèi)存映射技術(shù)(mmap) - 寫入數(shù)據(jù)時(shí)候只要在內(nèi)存里完成就可以返回給應(yīng)用程序,而保存到硬盤的操作則在后臺(tái)異步完成。這也就是說,MongoDB并不對(duì)RAM和磁盤這兩者進(jìn)行區(qū)別對(duì)待,只是將文件看作一個(gè)巨大的數(shù)組,然后按照字節(jié)為單位訪問其中的數(shù)據(jù),剩下的都交由操作系統(tǒng)(OS)去處理。先了解一下Memeory-Mapped Files:
1、內(nèi)存映射文件是OS通過mmap在內(nèi)存中創(chuàng)建一個(gè)數(shù)據(jù)文件,這樣就把文件映射到一個(gè)虛擬內(nèi)存的區(qū)域。
2、虛擬內(nèi)存對(duì)于進(jìn)程來說,是一個(gè)物理內(nèi)存的抽象,尋址空間大小為2^64
3、操作系統(tǒng)通過mmap來把進(jìn)程所需的所有數(shù)據(jù)映射到這個(gè)地址空間(紅線),然后再把當(dāng)前需要處理的數(shù)據(jù)映射到物理內(nèi)存(灰線)
4、當(dāng)進(jìn)程訪問某個(gè)數(shù)據(jù)時(shí),如果數(shù)據(jù)不在虛擬內(nèi)存里,觸發(fā)page fault,然后OS從硬盤里把數(shù)據(jù)加載進(jìn)虛擬內(nèi)存和物理內(nèi)存
5、如果物理內(nèi)存滿了,觸發(fā)swap-out操作,這時(shí)有些數(shù)據(jù)就需要寫回磁盤,如果是純粹的內(nèi)存數(shù)據(jù),寫回swap分區(qū),如果不是就寫回磁盤。


mmap.png

Storage View

Mongodb有三個(gè)storage view:Share view,private view,journal日志,前兩個(gè)位于內(nèi)存中,后一個(gè)位于磁盤上。

  • Share view:位于內(nèi)存上,會(huì)存儲(chǔ)已經(jīng)改變的要刷新到磁盤上的數(shù)據(jù)(臟數(shù)據(jù))。Share view是唯一一個(gè)直接連映射到數(shù)據(jù)庫文件上的view。當(dāng)你啟用mongoDB的日志功能時(shí),mongod會(huì)請(qǐng)求操作系統(tǒng)把磁盤上的數(shù)據(jù)文件指向share view內(nèi)存視圖上。操作系統(tǒng)不會(huì)數(shù)據(jù)文件加載到share view中。Mongdb在需要時(shí)自己把數(shù)據(jù)文件加載到share view上。
  • Private view:位于內(nèi)存上,存儲(chǔ)用于讀請(qǐng)求的數(shù)據(jù),更改請(qǐng)求最先在這執(zhí)行。MongDB把Private view指向share view。
  • Journal view:存儲(chǔ)已經(jīng)在private cache上發(fā)生更改的數(shù)據(jù),但是會(huì)在更改數(shù)據(jù)刷新到 share view(cache) 之前存儲(chǔ)。Journal 確保了數(shù)據(jù)的持久化。如果更改的數(shù)據(jù)沒有刷新到磁盤上的數(shù)據(jù)文件里,mongodb crash了,當(dāng)mongodb 起來以后,mongodb會(huì)把journallog中沒應(yīng)用到數(shù)據(jù)文件中的數(shù)據(jù)回放到 share view(cache) 中,最終會(huì)應(yīng)用到數(shù)據(jù)文件中。

當(dāng)一個(gè)寫請(qǐng)求發(fā)生時(shí):
1、更改 private view (cache)中的數(shù)據(jù)
2、默認(rèn)每100毫秒刷新到j(luò)ournal log。journal log有一個(gè)記錄當(dāng)前日志點(diǎn)的pointer
3、應(yīng)用journal log中的寫操作到share view ,這時(shí)share view 就和數(shù)據(jù)文件不一致
4、默認(rèn)每隔60秒,mongodb會(huì)請(qǐng)求操作系統(tǒng)刷新shared view中更改的數(shù)據(jù)到數(shù)據(jù)文件
5、mongdb會(huì)把journal log中記錄更改數(shù)據(jù)日志點(diǎn)的pointer,以前的數(shù)據(jù)刪除掉。
6、為了數(shù)據(jù)的一致性,Mongodb通常會(huì)請(qǐng)求操作系統(tǒng)重新把share view 指向private view。


image.png

所以說,在客戶端連接數(shù)一定的情況下(使用mongoose情況下連接池默認(rèn)為5),單個(gè)node實(shí)例占用的mongodb資源是固定的,性能也是接近的(都是操作內(nèi)存),實(shí)測(cè)將k8s中的mongodb實(shí)例的內(nèi)存配額調(diào)低到2GB,測(cè)出的性能沒有太大差距,所以說mongo的性能和內(nèi)存的關(guān)系不大(當(dāng)然大內(nèi)存會(huì)降低cpu的資源消耗)。

補(bǔ)充測(cè)試

既然前面提高了使用node連接mongo,默認(rèn)連接池大小為5(數(shù)據(jù)庫連接相關(guān)設(shè)置,請(qǐng)參考http://www.mongoosejs.net/docs/connections.html
),那么我們來測(cè)試一下,如果調(diào)整參數(shù),是否會(huì)對(duì)于性能產(chǎn)生影響。仍然還是單node副本,數(shù)據(jù)庫連接配置如下:

  config.mongoose = {
    client: {
      url: 'mongodb://22.196.66.200:31669/test',
      options: {
        user: 'test',
        pass: 'test',
        poolSize: 50,
      },
    },
  };

調(diào)整為50,測(cè)試結(jié)果如下:

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   188.41ms  111.62ms   1.87s    90.22%
    Req/Sec   316.79    126.13   626.00     70.90%
  6236 requests in 10.02s, 3.37MB read
  Socket errors: connect 0, read 0, write 0, timeout 85
Requests/sec:    622.50
Transfer/sec:    344.11KB

cpu使用率為13%
結(jié)果:增強(qiáng)pooSize大小對(duì)于QPS并沒有實(shí)質(zhì)性影響,最有效的增加性能的方式還是添加實(shí)例數(shù)。從測(cè)試結(jié)果來看,影響QPS的不是mongodb的連接數(shù),而是nodejs的并發(fā)數(shù)限制,因?yàn)閚ode本身是單進(jìn)程模型,單進(jìn)程能處理的并發(fā)數(shù)有限,不能充分利用cpu多核的優(yōu)勢(shì)。

為了進(jìn)一步驗(yàn)證,我們把eggjs的工作線程workers的數(shù)量設(shè)置為4,重啟pod進(jìn)行測(cè)試:
[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
2 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 82.35ms 29.02ms 347.47ms 76.04%
Req/Sec 1.21k 285.20 1.76k 81.50%
24194 requests in 10.02s, 13.06MB read
Requests/sec: 2415.47
Transfer/sec: 1.30MB

可以看出來QPS馬上變成原來的4倍,所以說影響nodejs性能的主要因素還是**線程數(shù)**

參考資料:
[http://blog.chinaunix.net/uid-25135004-id-3810200.html](http://blog.chinaunix.net/uid-25135004-id-3810200.html)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容