您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)Nginx的性能優(yōu)化,文章內(nèi)容質(zhì)量較高,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
Nginx如果只是做一個(gè)簡單的反向代理,它的優(yōu)化方式簡單且有效,比如增加worker進(jìn)程,增加長連接,減少硬盤存儲(chǔ)臨時(shí)文件,優(yōu)化內(nèi)核配置等。但隨著Nginx被當(dāng)作開發(fā)工具后,代碼復(fù)雜度也在逐步加深,無論Nginx是作為反向代理還是Web應(yīng)用,任何語言在不合理的使用中都會(huì)出現(xiàn)性能問題。本章中我們會(huì)介紹多個(gè)開源工具,利用它們幫助開發(fā)者在Nginx中查找性能問題。
注意:本章內(nèi)容包含Ngx_Lua有關(guān)的分析但不僅限于此。這些指令可以在Nginx和OpenResty兩個(gè)平臺(tái)測試。部分工具對LuaJIT 2.0和LuaJIT 2.1有區(qū)別,會(huì)在講解時(shí)說明。
16.1 性能分析場景搭建
性能分析一般會(huì)在測試環(huán)境中進(jìn)行分析(當(dāng)然線上服務(wù)有性能問題并且測試環(huán)境不易復(fù)現(xiàn)的情況下,那就另當(dāng)別論了),這樣可以確保上線前做好性能優(yōu)化,而且性能分析需要開啟debug模式,這對線上的服務(wù)來說不是很友好,所以先搭建一個(gè)debug環(huán)境,性能分析的安裝環(huán)境依賴很多包,請大家按照步驟一步一步地來。
16.1.1 SystemTap安裝
SystemTap是用來分析Linux系統(tǒng)性能問題的工具,通過它提供的接口就可以開發(fā)出用來調(diào)試和分析性能的代碼,本章中的分析工具都是依賴此SystemTap的。
1.首先確認(rèn)你的系統(tǒng)內(nèi)核版本,推薦Linux內(nèi)核版本大于3.5+的,如果低于此版本的官方也會(huì)提供utrace補(bǔ)丁在其內(nèi)核中,本測試安裝在CentOS 6.4上。
2.6.32
2.安裝對應(yīng)版本的內(nèi)核包:
先確認(rèn)是否安裝了kernel-devel。
kernel-devel-2.6.32-696.30.1.el6.x86_64
如果沒有安裝就yum,安裝時(shí)顯示了update到新的版本,下面對應(yīng)的其他rpm包也需要找到對應(yīng)的版本。
3.提供debug支持
4.安裝systemtap
驗(yàn)證安裝是否成功:
Pass 1: parsed user script and 117 library script(s) using 213788virt/41172res/3232shr/38628data kb, in 330usr/20sys/348real ms.
Pass 2: analyzed script: 1 probe(s), 2 function(s), 0 embed(s), 0 global(s) using 214580virt/42280res/3536shr/39420data kb, in 10usr/0sys/8real ms.
Pass 3: translated to C into "/tmp/stapldNGqo/stap_193cfbe6fbce06a86a9581c649f20084_960_src.c" using 214580virt/42668res/3892shr/39420data kb, in 0usr/0sys/0real ms.
Pass 4: compiled C into "stap_193cfbe6fbce06a86a9581c649f20084_960.ko" in 1040usr/210sys/1281real ms.
Pass 5: starting run.
Test Nginx Systemtap!
Pass 5: run completed in 0usr/10sys/345real ms.
16.1.2 LuaJIT的debug模式
需要在安裝LuaJIT時(shí)啟動(dòng)debug模式,即make CCDEBUG=-g。下面是安裝步驟順序:
16.1.3 開啟pcre的debug模式
有些時(shí)候需要對Nginx正則表達(dá)式的使用情況進(jìn)行分析,確保服務(wù)在正則方面的性能。
如果Nginx是在靜態(tài)編譯中使用了--with-pcre=的方式,請重新編譯開啟debug模式:
--with-pcre-jit --with-pcre-opt=-g \
如果是動(dòng)態(tài)鏈接的,可直接安裝rpm即可
確保這3個(gè)包都在:
pcre-debuginfo-7.8-7.el6.x86_64
pcre-7.8-7.el6.x86_64
pcre-devel-7.8-7.el6.x86_64
16.1.4 分析工具包下載
安裝基礎(chǔ)環(huán)境后,就可以使用下面的工具來進(jìn)行性能分析了。
openresty-systemtap-toolkit和stapxx,其中stapxx是對openresty-systemtap-toolkit的一個(gè)簡單的擴(kuò)展,我們會(huì)在分析中混用兩個(gè)工具,它們都有各自使用的場景,其中stapxx更側(cè)重于Ngx_Lua有關(guān)的性能分析。
下載:
然后下載FlameGraph,它是將上面兩個(gè)工具采集的性能數(shù)據(jù)生成火焰圖的工具。
最后編譯Nginx,它需要加上--with-debug即可。
注意:Linux系統(tǒng)需要Perl至少5.6.1以上的版本,默認(rèn)情況下已經(jīng)安裝。
16.1.5 找出debug不支持的包
通過下面命令可以找出不支持debug模式的lib,如果lib不支持,你又需要測試功能和這個(gè)lib有關(guān),可能會(huì)出現(xiàn)報(bào)錯(cuò),所以在性能分析中按需安裝。
check-debug-info -p pid, pid可以是Nginx的worker進(jìn)程pid,它也可以用來檢測非Nginx的進(jìn)程,此命令就是剛才下載的openresty-systemtap-toolkit目錄中的命令。
File /lib64/ld-2.12.so has no debug info embedded.
File /lib64/libc-2.12.so has no debug info embedded.
File /lib64/libcrypt-2.12.so has no debug info embedded.
File /lib64/libdl-2.12.so has no debug info embedded.
File /lib64/libfreebl3.so has no debug info embedded.
File /lib64/libm-2.12.so has no debug info embedded.
File /lib64/libnss_files-2.12.so has no debug info embedded.
File /lib64/libpthread-2.12.so has no debug info embedded.
File /lib64/libresolv-2.12.so has no debug info embedded.
16.2 流量復(fù)制
性能分析的環(huán)境已經(jīng)搭建完成,現(xiàn)在需要有流量進(jìn)入才可以驗(yàn)證這些代碼的使用情況。我們可以用下面2種工具模擬出真實(shí)的請求和并發(fā)。它們在13.5.2和13.5.3節(jié)有介紹,就不重復(fù)說明了。
如果是新的服務(wù),URL也是新的,可以理解為線上還沒有流量可以復(fù)制,因?yàn)闆]有上線此功能,就可以利用壓測工具,如AB、Webbench等
16.3 各項(xiàng)指標(biāo)分析和優(yōu)化建議
性能測試環(huán)境全部就位,可以進(jìn)行性能分析了。
注意:所有的分析操作都是在Nginx的worker進(jìn)程pid上執(zhí)行的。
16.3.1 連接池使用狀態(tài)分析
我們在前面介紹過lua-resty-redis和lua-resty-mysql,它們都有使用過連接池的配置。如下:
local ok, err = db:set_keepalive(10000, 100)
if not ok then
ngx.say("failed to set keepalive: ", err)
return
end
連接池的作用可以極大地減少timewait和建聯(lián)的開銷,但如何才知道連接池配置是否滿足需求呢?可以使用如下方式:
Tracing 30396 (/usr/local/nginx/sbin/nginx) for LuaJIT 2.0...
pool "172.16.1.51:6301"
out-of-pool reused connections: 1
in-pool connections: 2
reused times (max/avg/min): 29/18/7
pool capacity: 100
pool "172.16.13.171:6398"
out-of-pool reused connections: 0
in-pool connections: 1
reused times (max/avg/min): 0/0/0
pool capacity: 100
pool "172.16.1.55:8186"
out-of-pool reused connections: 0
in-pool connections: 1
reused times (max/avg/min): 377/377/377
pool capacity: 30
pool "172.16.1.7:5689"
out-of-pool reused connections: 0
in-pool connections: 1
reused times (max/avg/min): 1/1/1
pool capacity: 100
For total 4 connection pool(s) found.
122 microseconds elapsed in the probe handler.
指令:ngx-lua-conn-pools
語法:ngx-lua-conn-pools -p $pid (--luajit20 or--lua51)
它的作用是獲取指定worker進(jìn)程中的Ngx_Lua的連接池狀態(tài)。如果是Nginx編譯時(shí)采取的是Lua 5.1就用--lua51。如果是LuaJIT 2.0就用--luajit20,目前測試在Luajit2.1也可以用。
分析結(jié)果說明如表16-1所示。
結(jié)果 說明
pool "172.16.1.51:6301" 連接池所連接的服務(wù),比如Redis、MySQL
out-of-pool reused connections: 1 外部連接池重?cái)?shù)量
in-pool connections: 2 池內(nèi)連接數(shù)量
reused times (max/avg/min): 29/18/7 重用次數(shù)、最大值、平均值、最小值
pool capacity: 100 連接池容量,配置文件內(nèi)的配置連接池的數(shù)量
表16-1 連接池信息說明
通過此命令我們可以獲取連接池的使用數(shù)量和配置數(shù)量,在流量測試中觀察連接池使用情況,來確認(rèn)是否需要調(diào)整連接池的配置。
16.3.2 找出硬盤讀寫頻繁的文件
找出讀文件次數(shù)最多的文件名,默認(rèn)前10:
Tracing 48070 (/usr/local/nginx/sbin/nginx)...
Hit Ctrl-C to end.
^C
=== Top 10 file reads ===
#1: 1 times, 2033 bytes reads in file middle_page.lua.
#2: 1 times, 2374 bytes reads in file rand_str.lua.
找出被寫入次數(shù)最多的文件名,默認(rèn)前10:
Tracing 48070 (/usr/local/nginx/sbin/nginx)...
Hit Ctrl-C to end.
^C
=== Top 10 file writes ===
#1: 1976 times, 3353103 bytes writes in file access.log-2018-06-28-20-14-01.log.
#2: 1975 times, 841837 bytes writes in file wireless.access.log.
#3: 1360 times, 2206474 bytes writes in file access.log.
#5: 17 times, 5598 bytes writes in file error.log.
16.3.3 執(zhí)行階段耗時(shí)分析
請求會(huì)在多個(gè)執(zhí)行階段進(jìn)行處理,獲取到每個(gè)階段的執(zhí)行效率,就可以指定優(yōu)化范圍,以此提升響應(yīng)速度:
Start tracing process 18993 (/usr/local/nginx/sbin/nginx)...
[1530153801023919] pid:18993 GET /zhe800_n_api/search/hot_words?new_user=1&user_id=0&user_type=0&callback=hot_words
total: 1235us, accept() ~ header-read: 65us, rewrite: 23us, pre-access: 23us, access: 26us, content: 985us
upstream: connect=270us, time-to-first-byte=496us, read=0us
./samples/ngx-single-req-latency.sxx -x $pid,獲取worker進(jìn)程的單個(gè)請求在各個(gè)階段的消耗時(shí)間(us是微妙)。默認(rèn)它只獲取它看到的第一條請求,所以要測試某個(gè)請求的階段耗時(shí)時(shí),在goreplay進(jìn)行過濾,只發(fā)送特定的URL就可以完成驗(yàn)證,也可以ab測試。
16.3.4 連接數(shù)和文件打開數(shù)分析
分析worker進(jìn)程的連接數(shù)量和文件打開數(shù)量,可以得知系統(tǒng)的配置資源是否足夠,避免出現(xiàn)文件數(shù)或者連接數(shù)不夠用的情況。
Start tracing 18993 (/usr/local/nginx/sbin/nginx)...
====== CONNECTIONS ======
Max connections: 102400 #Nginx配置文件設(shè)置最大連接數(shù)
Free connections: 101854 #還可以接受的連接數(shù)
Used connections: 546 #已經(jīng)使用的連接數(shù)
====== FILES ======
Max files: 102400 #Nginx配置文件設(shè)置最大文件打開數(shù)
Open normal files: 20 #當(dāng)前打開的數(shù)量
16.3.5 找出CPU偷竊者
通過下面的命令可以獲取到其他進(jìn)程搶占指定pid的CPU的頻率,此命令也支持分析其他非Nginx的進(jìn)程。
Start tracing process 30396 (/usr/local/nginx/sbin/nginx)...
Hit Ctrl-C to end.
^C
#1 consul: 38% (5 samples)
#2 events/0: 30% (4 samples)
#3 kblockd/0: 15% (2 samples)
#4 watchdog/0: 7% (1 samples)
#5 zabbix_agentd: 7% (1 samples)
16.3.6 正則表達(dá)式耗時(shí)分析
Nginx中會(huì)大量使用正則表達(dá)式,特別是有些動(dòng)態(tài)路由,如果正則的耗時(shí)過長對整體的請求還有CPU消耗都會(huì)造成不良影響,通過下面的命令,我們可以捕獲Nginx中耗時(shí)最長的正則操作:
Found exact match for libluajit: /usr/local/lib/libluajit-5.1.so.2.1.0
Found exact match for libpcre: /lib64/libpcre.so.0.0.1
Start tracing 18999 (/usr/local/nginx/sbin/nginx)
Hit Ctrl-C to end.
^C
Top N regexes with longest total running time:
^[[AFound exact match for libluajit: /usr/local/lib/libluajit-5.1.so.2.1.0
Found exact match for libpcre: /lib64/libpcre.so.0.0.1
Start tracing 18999 (/usr/local/nginx/sbin/nginx)
Hit Ctrl-C to end.
^C
Top N regexes with longest total running time:
Found exact match for libpcre: /lib64/libpcre.so.0.0.1
Start tracing 18999 (/usr/local/nginx/sbin/nginx)
Hit Ctrl-C to end.
^C
Logarithmic histogram for data length distribution (byte) for 196882 samples:
(min/avg/max: 0/22/4749)
value |-------------------------------------------------- count
0 | 1255
1 | 1272
2 |@ 3336
4 | 1481
8 |@@@@@@@@@@@@@ 50690
16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 113128
32 |@@@@@@ 23912
64 | 1341
128 | 419
256 | 30
512 | 12
1024 | 4
2048 | 0
4096 | 2
8192 | 0
16384 | 0
它也支持使用--arg utime=1,可以提高時(shí)間的準(zhǔn)確性,但某些平臺(tái)上可能不支持。它既支持Ngx_Lua的API,也支持lua-resty-core API
Found exact match for libpcre: /lib64/libpcre.so.0.0.1
Start tracing 18999 (/usr/local/nginx/sbin/nginx)
Hit Ctrl-C to end.
^C
Logarithmic histogram for data length distribution (byte) for 46247 samples:
(min/avg/max: 0/23/805)
value |-------------------------------------------------- count
0 | 215
1 | 214
2 |@ 715
4 | 349
8|@@@@@@@@@@@@@@@@@ 10117
16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 28346
32 |@@@@@@@@@ 5973
64 | 247
128 | 66
256 | 3
512 | 2
1024 | 0
2048 | 0
16.3.7找出CPU消耗高的指令
如果發(fā)現(xiàn)CPU使用上異?;蚴窍倪^高,可以利用lua-stacks.sxx,它可以獲取到Nginx worker進(jìn)程中占用CPU的各項(xiàng)指令的比例。
如果你是LuaJIT 2.1就使用下面的指令,你得到的數(shù)據(jù)將會(huì)如下:
./samples/lj-lua-stacks.sxx --arg time=10 --skip-badvars -x 48070
Found exact match for libluajit: /usr/local/lib/libluajit-5.1.so.2.1.0
WARNING: Start tracing 48070 (/usr/local/nginx/sbin/nginx)
WARNING: Please wait for 10 seconds...
WARNING: Time's up. Quitting now...match
builtin#88
@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:4
br/>@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:29<br/@/usr/local/nginx/conf/lua/log_jk/log_to_influxdb.lua:1131
match
builtin#84
@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:9
br/>@/usr/local/nginx/conf/lua/log_jk/log_to_influxdb.lua:1<br/114compile_regex
C:ngx_http_lua_ngx_re_find
@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:29
br/>75
match
C:ngx_http_lua_ngx_exit
26
lj_str_new
C:ngx_http_lua_var_get
@/usr/local/nginx/conf/lua/log_jk/log_to_influxdb.lua:1<br/21max_expand
builtin#88
@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:4
br/>@/usr/local/nginx/conf/lua/log_jk/utils/utils.lua:29<br/@/usr/local/nginx/conf/lua/log_jk/log_to_influxdb.lua:1
如果你是LuaJIT2.0或者Lua5.1就使用下面的指令,得到和上圖一樣的輸出
很顯然這種輸出方式是不便于我們觀察CPU的消耗情況的,就需要用到下面章節(jié)的FlameGraph。
16.3.8利于火焰圖展示數(shù)據(jù)和分析
FlameGraph是將采集的性能數(shù)據(jù)生成火焰圖的工具,讓數(shù)據(jù)更直觀,使用方式如下:
1.將16.3.7指令輸出的內(nèi)容存放到文件中:
2.使用openresty-systemtap-toolkit中的fix-lua-bt獲取具體的Lua代碼:
3.使用FlameGraph生成圖:
4.將a.svg拷貝出來,放到瀏覽器中打開,會(huì)看到如圖16-1所示的數(shù)據(jù)。
圖16-1 worker進(jìn)程火焰圖
對這個(gè)a.svg分析如下。
1.解讀火焰圖:
圖中垂直的數(shù)軸即y軸,它表示調(diào)用棧的深度。最下面是父函數(shù),依次向頂部。高度越高調(diào)用的層次越深。
圖中水平的數(shù)軸即x軸,它表示請求占用CPU的情況,越下面的請求代表次數(shù)越多,耗時(shí)占用也就越長。
一般最上面如果是平頂?shù)那闆r,就可能存在瓶頸,正常的火焰圖呈現(xiàn)的效果應(yīng)該是會(huì)有很多尖刺,而不應(yīng)該是平頂。
2.點(diǎn)擊圖中的一個(gè)CPU占比高的,就會(huì)看到是哪個(gè)函數(shù)執(zhí)行的。
如圖16-2中match采樣1144次,CPU占比8.75%,在火焰圖的頂端,它表示是這個(gè)函數(shù)最后執(zhí)行的一個(gè)命令,match是正則匹配操作。
圖16-2 CPU占用高的火焰圖
3.可以看出此火焰圖平頂過多,有優(yōu)化的空間,根據(jù)里面定位的函數(shù)進(jìn)行優(yōu)化即可。
4.圖16-3是OpenResty官網(wǎng)提供的一個(gè)正常的火焰圖。
圖16-3 正?;鹧鎴D模型
16.4 檢查全局變量
在前面的章節(jié)中曾多次提到過要避免使用全局變量,它會(huì)帶來很多不利的影響,通過下面的方式可以檢查出變量是全局還是局部的。
1.安裝檢查工具luacheck
--deps-mode=none 是可選參數(shù),如果你在安裝中出現(xiàn)報(bào)錯(cuò),就加上此參數(shù)再試試。
2.如果需要檢查目錄下所有的Lua腳本的變量,請安裝LuaFileSystem,luacheck依賴它。
3.執(zhí)行檢查,一般情況下代碼都是基于Ngx_Lua或者LuaJIT 2.0/2.1開發(fā),所以檢查時(shí)加入?yún)?shù)--std Ngx_Lua。如果是Lua5.1開發(fā)的,請使用--std lua51。--std的作用是設(shè)置使用指定格式的全局變量的環(huán)境。
如下發(fā)現(xiàn)version和xx可能存在問題的,請打開文件檢查吧。
Checking /tmp/ab_version.lua 2 warnings
/tmp/ab_version.lua:1:7: value assigned to variable version is unused
/tmp/ab_version.lua:2:1: setting non-standard global variable xx
Total: 2 warnings / 0 errors in 1 file, couldn't check 1 file
到此為止, 關(guān)于Nginx的性能優(yōu)化有了一個(gè)基礎(chǔ)的認(rèn)識(shí), 但是對于具體的使用方法還是需要多加鞏固和練習(xí),如果想了解更多相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。