控Nginx:stub_status+UserParameter配置實(shí)戰(zhàn)指南)
Nginx 監(jiān)控這件事很多人一開始想復(fù)雜了。Zabbix 要拿到 Nginx 的運(yùn)行狀態(tài)并不需要裝額外探針也不一定非要解析訪問日志最穩(wěn)定的入口其實(shí)是 Nginx 自帶的 stub_status 狀態(tài)頁(yè)。只要把它打開再用 Zabbix Agent 把里面的幾個(gè)數(shù)字讀回來就能完成請(qǐng)求量、并發(fā)連接、讀寫狀態(tài)的監(jiān)控再配上觸發(fā)器和圖形連接數(shù)異常、請(qǐng)求速率突變這些情況都能直接看到。這篇內(nèi)容按實(shí)際落地順序來拆先講 Nginx 狀態(tài)頁(yè)每個(gè)字段是什么意思再講怎么讓 Zabbix Agent 把數(shù)據(jù)采回來然后是 Zabbix 前端里的監(jiān)控項(xiàng)、觸發(fā)器和圖形怎么配最后做一輪實(shí)測(cè)把請(qǐng)求打起來再去看統(tǒng)計(jì)結(jié)果怎么解讀。適合剛接觸 Zabbix 監(jiān)控 Nginx 的人也適合已經(jīng)在用 shell 腳本采集、但想轉(zhuǎn)成 Zabbix 規(guī)范化監(jiān)控的人。1. 先搞清楚 nginx 狀態(tài)頁(yè)Zabbix 監(jiān)控 Nginx 的數(shù)據(jù)從哪來1.1 stub_status 輸出字段對(duì)照Z(yǔ)abbix 監(jiān)控 Nginx底層數(shù)據(jù)源不是日志而是 Nginx 自己維護(hù)的計(jì)數(shù)器。只要在 Nginx 配置里啟用 stub_status訪問狀態(tài)頁(yè)就能看到一小段純文本Active connections: 291 server accepts handled requests 16630948 16630948 31070465 Reading: 6 Writing: 179 Waiting: 106這段文本雖然短但每個(gè)字段都有明確含義。字段含義類型Active connections當(dāng)前活動(dòng)連接數(shù)瞬時(shí)值acceptsNginx 啟動(dòng)以來累計(jì)接受的客戶端連接總數(shù)累計(jì)值handled成功處理的連接總數(shù)累計(jì)值requests累計(jì)處理的客戶端請(qǐng)求總數(shù)累計(jì)值Reading正在讀取請(qǐng)求頭的連接數(shù)瞬時(shí)值Writing正在讀取請(qǐng)求體、處理請(qǐng)求或?qū)戫憫?yīng)的連接數(shù)瞬時(shí)值Waiting空閑的 keep-alive 連接數(shù)瞬時(shí)值第一行Active connections是當(dāng)前活動(dòng)連接數(shù)。注意它包含后面 Reading、Writing、Waiting 三類的總和所以只要 Nginx 活著這個(gè)數(shù)值通常不會(huì)是 0。第二行是固定表頭server accepts handled requests。第三行的三個(gè)數(shù)字分別對(duì)應(yīng)表頭都是只增不減的累計(jì)計(jì)數(shù)器只有 Nginx 重啟才會(huì)歸零。第四行的 Reading、Writing、Waiting 是三個(gè)瞬時(shí)值。一個(gè)請(qǐng)求從進(jìn)入到結(jié)束通常會(huì)依次經(jīng)過 Reading、Writing 兩個(gè)階段最后進(jìn)入 Waiting或者直接關(guān)閉連接。這幾個(gè)字段之間的換算關(guān)系是Active connections Reading Writing Waiting。理解這個(gè)關(guān)系后面看圖形和觸發(fā)器才不會(huì)被數(shù)字騙到。1.2 哪些指標(biāo)值得接進(jìn) Zabbix不是每個(gè)字段都必須接進(jìn)來但下面這幾個(gè)我建議至少都要有。請(qǐng)求速率是最核心的指標(biāo)對(duì)應(yīng) requests 計(jì)數(shù)器看的是單位時(shí)間內(nèi)處理了多少請(qǐng)求也就是平時(shí)說的 QPS。只看累計(jì)值沒有意義必須換算成速率。新建連接速率對(duì)應(yīng) accepts 計(jì)數(shù)器看的是單位時(shí)間內(nèi)來了多少新連接。這個(gè)值和 QPS 的區(qū)別在于keep-alive 生效的情況下一個(gè)連接上可以連續(xù)發(fā)多個(gè)請(qǐng)求所以請(qǐng)求速率通常遠(yuǎn)大于連接速率。當(dāng)前并發(fā)連接數(shù)對(duì)應(yīng) Active connections是最直觀的負(fù)載指標(biāo)。但它不能單獨(dú)說明問題必須結(jié)合 Reading、Writing、Waiting 一起看。Reading 如果持續(xù)偏高說明有一些客戶端請(qǐng)求頭發(fā)得很慢或者請(qǐng)求頭一直沒發(fā)完。Writing 持續(xù)偏高說明 Nginx 正在大量往客戶端寫響應(yīng)這時(shí)候要關(guān)注帶寬和上游服務(wù)能不能跟上。Waiting 高反而是正?,F(xiàn)象說明大量連接是空閑 keep-alive對(duì)靜態(tài)資源或高并發(fā) Web 服務(wù)很常見。把這些字段全部接進(jìn) Zabbix才算真正把 Nginx 的運(yùn)行狀態(tài)看完整。2. 環(huán)境準(zhǔn)備與最小配置讓 Nginx 先吐出狀態(tài)數(shù)據(jù)2.1 確認(rèn) Nginx 是否支持 stub_statusstub_status 不是所有 Nginx 都默認(rèn)包含。編譯 Nginx 時(shí)如果沒有加--with-http_stub_status_module這個(gè)功能就不存在配置寫了也會(huì)報(bào)錯(cuò)。先檢查當(dāng)前 Nginx 有沒有這個(gè)模塊nginx -V 21 | grep -o http_stub_status_module如果輸出里有http_stub_status_module說明支持。如果沒有有兩個(gè)方向重新編譯 Nginx 時(shí)加上這個(gè)模塊或者換成已經(jīng)默認(rèn)包含該模塊的發(fā)行版軟件包。很多發(fā)行版和官方倉(cāng)庫(kù)自帶的 Nginx 都已經(jīng)開啟了這個(gè)模塊但自編譯版本一定要單獨(dú)確認(rèn)。這里提醒一下執(zhí)行nginx -V時(shí)編譯參數(shù)是在標(biāo)準(zhǔn)錯(cuò)誤輸出里所以我加了21把錯(cuò)誤輸出重定向到同一路。很多人第一次只看第一行 version以為不支持其實(shí)是沒看全。2.2 Nginx 狀態(tài)頁(yè)配置示例與安全限制確認(rèn)模塊存在后在 Nginx 的 server 配置里加一個(gè) location。以下是一份最小配置server { listen 80; server_name _; location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; } }這里最關(guān)鍵的是allow和deny。stub_status 本身沒有任何認(rèn)證機(jī)制任何人能訪問就能看到你的連接數(shù)、請(qǐng)求量和連接狀態(tài)。如果把狀態(tài)頁(yè)暴露到公網(wǎng)內(nèi)部運(yùn)行信息等于公開了。所以默認(rèn)只允許本機(jī)訪問是最穩(wěn)妥的做法。如果你的 Zabbix Agent 和 Nginx 不在同一臺(tái)機(jī)器上不要直接把deny all刪掉應(yīng)該改成只允許采集機(jī) IP 訪問location /nginx_status { stub_status on; access_log off; allow 192.168.1.100; deny all; }改完配置先檢查再重載nginx -t nginx -s reloadnginx -t這一步不能省。stub_status 的 location 如果配置在錯(cuò)誤的上下文里或者和已有配置沖突reload 會(huì)直接失敗。2.3 用 curl 驗(yàn)證狀態(tài)頁(yè)是否生效配置完成之后先在 Nginx 所在機(jī)器上驗(yàn)證curl -s http://127.0.0.1/nginx_status如果能看到開頭那段文本說明狀態(tài)頁(yè)已經(jīng)可以訪問了。如果返回 404說明 location 沒生效或者配置在了錯(cuò)誤的 server 塊里。如果返回 403大概率是deny all生效了而你的請(qǐng)求來源 IP 不在allow列表里。這里有個(gè)容易忽略的點(diǎn)如果你的 Nginx 不是監(jiān)聽 80 端口或者同時(shí)有 HTTPSURL 里要帶上實(shí)際協(xié)議和端口例如http://127.0.0.1:8080/nginx_status。先花一分鐘把 curl 這步跑通后面會(huì)省很多時(shí)間。3. Zabbix Agent 接入一條 UserParameter 和一個(gè)監(jiān)控項(xiàng)的關(guān)系3.1 安裝與基礎(chǔ)配置 Zabbix AgentZabbix Agent 是部署在 Nginx 所在機(jī)器上的采集程序。它的作用和 Nginx 狀態(tài)頁(yè)互補(bǔ)狀態(tài)頁(yè)負(fù)責(zé)提供數(shù)據(jù)Agent 負(fù)責(zé)把數(shù)據(jù)讀出來再交給 Zabbix Server。安裝方式要看你的系統(tǒng)和 Zabbix 版本直接使用官方倉(cāng)庫(kù)安裝 zabbix-agent 即可。裝完需要修改配置文件常見要確認(rèn)三個(gè)參數(shù)Server192.168.1.10 ServerActive192.168.1.10 Hostnameweb01Server是允許給這臺(tái) Agent 下發(fā)被動(dòng)采集請(qǐng)求的 Zabbix Server 地址。ServerActive是主動(dòng)上報(bào)要連接的 Server 地址。Hostname是 Agent 上報(bào)時(shí)使用的名字在 Zabbix 前端添加主機(jī)時(shí)要保持一致特別是主動(dòng)檢查時(shí)Hostname 對(duì)不上會(huì)直接導(dǎo)致數(shù)據(jù)丟失。這里解釋一下被動(dòng)檢查和主動(dòng)檢查的區(qū)別。被動(dòng)檢查是 Zabbix Server 主動(dòng)連接 Agent 的 10050 端口要數(shù)據(jù)主動(dòng)檢查是 Agent 主動(dòng)連接 Server 的 10051 端口上報(bào)數(shù)據(jù)。自定義 UserParameter 兩種方式都支持但排查問題時(shí)的思路不一樣后面會(huì)詳細(xì)說。改完配置啟動(dòng)服務(wù)systemctl restart zabbix-agent systemctl status zabbix-agent3.2 通過 UserParameter 把 nginx_status 轉(zhuǎn)成監(jiān)控項(xiàng)Zabbix Agent 默認(rèn)不認(rèn)識(shí) nginx 的 key需要通過 UserParameter 來定義。UserParameter 的格式很簡(jiǎn)單一個(gè) key一個(gè)命令A(yù)gent 執(zhí)行命令把標(biāo)準(zhǔn)輸出作為監(jiān)控值返回。在/etc/zabbix/zabbix_agentd.d/目錄下創(chuàng)建一個(gè) nginx.conf寫入以下內(nèi)容UserParameternginx.active,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk /Active connections/{print $3} UserParameternginx.accepts,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk NR3{print $1} UserParameternginx.handled,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk NR3{print $2} UserParameternginx.requests,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk NR3{print $3} UserParameternginx.reading,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk /Reading/{print $2} UserParameternginx.writing,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk /Writing/{print $4} UserParameternginx.waiting,/usr/bin/curl -s --max-time 3 http://127.0.0.1/nginx_status | awk /Waiting/{print $6}逐個(gè)拆一下。每行都是一個(gè) key例如nginx.active。后面的命令先用 curl 抓取狀態(tài)頁(yè)再用 awk 提取對(duì)應(yīng)字段。awk 的寫法要特別注意。第三行的 accepts、handled、requests 是三個(gè)連續(xù)數(shù)字所以分別用NR3定位到第三行再打印第 1、2、3 列。Reading、Writing、Waiting 在同一行里所以要先用正則匹配到這一行再打印對(duì)應(yīng)列。Writing 是第 4 列Waiting 是第 6 列這個(gè)順序很多人會(huì)弄錯(cuò)。命令里的--max-time 3不是隨便加的。如果狀態(tài)頁(yè)異常導(dǎo)致 curl 一直掛住Agent 執(zhí)行這個(gè) UserParameter 就會(huì)卡住嚴(yán)重時(shí)會(huì)占滿 Agent 的檢查線程影響這臺(tái)機(jī)器上的其他監(jiān)控項(xiàng)。加上超時(shí)時(shí)間最壞 3 秒也會(huì)退出。改完配置后重啟 Agentsystemctl restart zabbix-agent3.3 先用 zabbix_get 還是前端測(cè)試功能配置完 UserParameter不要急著去 Zabbix 前端創(chuàng)建主機(jī)先在命令行驗(yàn)證一遍 key 能不能查到值。在有 zabbix-get 工具的機(jī)器上執(zhí)行它通常在 Zabbix Server 或 Proxy 上zabbix_get -s 192.168.1.20 -k nginx.requests返回一個(gè)數(shù)字說明這條鏈路通了。如果提示 Not supported 或者沒有輸出先不要懷疑 Zabbix 配置回到 Nginx 機(jī)器上直接執(zhí)行那條 UserParameter 命令看有沒有結(jié)果。這里有個(gè)容易踩的坑你手動(dòng)執(zhí)行命令時(shí)用的是 root 用戶而 Zabbix Agent 運(yùn)行時(shí)的用戶通常是 zabbix兩個(gè)用戶的環(huán)境變量、權(quán)限、可執(zhí)行路徑可能都不一樣。比如 zabbix 用戶沒有權(quán)限訪問某個(gè)目錄或者 SELinux 攔截了 zabbix 用戶執(zhí)行 curl都會(huì)導(dǎo)致手動(dòng)執(zhí)行正常、Agent 執(zhí)行失敗。新版 Zabbix 前端在監(jiān)控項(xiàng)配置里也有一個(gè) Test 按鈕可以直接測(cè)試當(dāng)前主機(jī)上的 key返回結(jié)果和報(bào)錯(cuò)更直觀。實(shí)際排查時(shí)我一般按三個(gè)地方順序看Agent 所在機(jī)器手動(dòng)執(zhí)行命令、zabbix_get 從 Server 端測(cè)試、前端 Test 按鈕看報(bào)錯(cuò)。4. 創(chuàng)建主機(jī)、監(jiān)控項(xiàng)、觸發(fā)器數(shù)據(jù)到告警的完整鏈路4.1 在 Zabbix 前端添加主機(jī)與監(jiān)控項(xiàng)命令行驗(yàn)證通過后進(jìn)入 Zabbix Web 界面按照 配置 → 主機(jī) → 創(chuàng)建主機(jī) 的路徑添加一臺(tái)主機(jī)。填寫主機(jī)名時(shí)要注意Agent 配置文件里的 Hostname 和這里的主機(jī)名必須一致否則主動(dòng)檢查會(huì)失敗。接口配置里選擇 Agent填寫 Nginx 所在機(jī)器的 IP 和默認(rèn)端口 10050。添加監(jiān)控項(xiàng)有兩條路線。一條是直接鏈接模板Zabbix 模板庫(kù)里有 Nginx by HTTP、Nginx by Zabbix agent 2 這類現(xiàn)成模板不同版本的模板數(shù)量和名稱會(huì)有差異底層采集方式也是去讀狀態(tài)頁(yè)適合不想自己維護(hù) key 的人。另一條是手動(dòng)創(chuàng)建監(jiān)控項(xiàng)用剛才定義的 UserParameter 鍵值自由度更高也更容易理解每個(gè)數(shù)字怎么來的。如果你是第一次做我更建議先手動(dòng)創(chuàng)建。原因很簡(jiǎn)單自動(dòng)模板會(huì)隱藏很多細(xì)節(jié)一旦出了問題你很難判斷是狀態(tài)頁(yè)的問題、Agent 的問題還是模板映射的問題。手動(dòng)創(chuàng)建一遍等于把鏈路里的每個(gè)環(huán)節(jié)都摸清楚了。手動(dòng)創(chuàng)建監(jiān)控項(xiàng)時(shí)以nginx.requests為例名稱Nginx Requests類型Zabbix Agent鍵值nginx.requests信息類型數(shù)字無正負(fù)更新間隔1m 或 30s 都可以歷史數(shù)據(jù)保留7d趨勢(shì)數(shù)據(jù)保留365d其他幾個(gè) key 按同樣方法創(chuàng)建。4.2 請(qǐng)求速率、連接數(shù)怎么存儲(chǔ)和計(jì)算單位這里要解決一個(gè)關(guān)鍵問題accepts、handled、requests 這三個(gè)字段是累計(jì)值直接存進(jìn) Zabbix 只能看到一根一直向上的線很難判斷當(dāng)前請(qǐng)求量到底是多少。所以必須讓 Zabbix 把累計(jì)值換算成速率。在 Zabbix 監(jiān)控項(xiàng)配置里有一個(gè)字段叫“存儲(chǔ)值”可以選“原樣存儲(chǔ)”“增量簡(jiǎn)單變化”和“增量每秒速率”。存儲(chǔ)方式適用場(chǎng)景示例原樣存儲(chǔ)瞬時(shí)值當(dāng)前是多少就存多少active、reading、writing、waiting增量簡(jiǎn)單變化累計(jì)值的兩次差值accepts 每次變化量增量每秒速率累計(jì)值換算成每秒速率requests、accepts、handled對(duì) requests、accepts、handled 這三個(gè)累計(jì)計(jì)數(shù)器應(yīng)該選擇“增量每秒速率”單位寫成 req/s 或 conn/s。這樣 Zabbix 會(huì)在后臺(tái)自動(dòng)計(jì)算兩次采集之間的差值再除以時(shí)間間隔得到每秒速率。如果你不想在監(jiān)控項(xiàng)里改存儲(chǔ)方式也可以用預(yù)處理步驟里的“每秒更改量”來實(shí)現(xiàn)同樣效果。兩者本質(zhì)上是一樣的看你習(xí)慣哪種。唯一要注意的是如果 Nginx 在兩次采集之間重啟過計(jì)數(shù)器歸零速率可能會(huì)出現(xiàn)一次很大的負(fù)值或異常值統(tǒng)計(jì)圖形上會(huì)出現(xiàn)明顯的斷點(diǎn)這是正常現(xiàn)象不是系統(tǒng)崩潰。active、reading、writing、waiting 這四個(gè)瞬時(shí)值就保持“原樣存儲(chǔ)”它們的數(shù)值本身就是當(dāng)前狀態(tài)不需要做速率換算。4.3 觸發(fā)器和告警閾值怎么定監(jiān)控項(xiàng)建好后數(shù)據(jù)會(huì)不斷進(jìn)入 Zabbix但沒人盯著圖形的話異常還是發(fā)現(xiàn)不了。觸發(fā)器的意義就是自動(dòng)判斷數(shù)值是否超過預(yù)期。觸發(fā)器配置路徑是 配置 → 主機(jī) → 觸發(fā)器 → 創(chuàng)建觸發(fā)器。以活躍連接數(shù)為例一個(gè)簡(jiǎn)單表達(dá)式last(/web01/nginx.active)10000含義是當(dāng)前活躍連接數(shù)大于 10000 時(shí)觸發(fā)警告。再比如請(qǐng)求速率min(/web01/nginx.requests,5m)5000含義是最近 5 分鐘請(qǐng)求速率平均值超過 5000 req/s 時(shí)觸發(fā)。閾值定多少?zèng)]有標(biāo)準(zhǔn)答案取決于你的業(yè)務(wù)。我建議先讓 Zabbix 跑兩三天積累一段基線數(shù)據(jù)再根據(jù)圖形里的峰值來定警告和嚴(yán)重閾值不要憑感覺拍腦袋。第一次設(shè)置可以把閾值放寬一點(diǎn)確認(rèn)告警鏈路能正常觸發(fā)后再往回收。觸發(fā)器還可以設(shè)置恢復(fù)表達(dá)式也就是數(shù)值降到多少以下時(shí)自動(dòng)恢復(fù)為正常。這個(gè)最好一起配好否則每次數(shù)值震蕩都會(huì)反復(fù)觸發(fā)、恢復(fù)告警會(huì)很吵。要測(cè)試告警鏈路的完整效果除了觸發(fā)器還需要配置好動(dòng)作和通知方式。如果暫時(shí)沒配郵件或其他通知也可以先只做觸發(fā)器通過 Zabbix 首頁(yè)的告警記錄來確認(rèn)觸發(fā)是否成功。5. 實(shí)測(cè)一輪用請(qǐng)求壓一壓再去看統(tǒng)計(jì)結(jié)果和圖形5.1 制造流量curl 循環(huán)或 ab 簡(jiǎn)單壓測(cè)配置完成之后最關(guān)鍵的一步就是實(shí)測(cè)。沒有流量監(jiān)控圖形是一條平線你很難判斷數(shù)據(jù)到底有沒有采集成功。最簡(jiǎn)單的測(cè)試方法是用 curl 發(fā)一批請(qǐng)求。在 Nginx 機(jī)器上執(zhí)行for i in $(seq 1 1000); do curl -s -o /dev/null http://127.0.0.1/; done這個(gè)循環(huán)會(huì)向本機(jī) Nginx 發(fā)送 1000 次請(qǐng)求每次丟棄響應(yīng)內(nèi)容。優(yōu)點(diǎn)是環(huán)境干凈不需要額外工具。缺點(diǎn)是速度不夠快產(chǎn)生的請(qǐng)求速率不會(huì)特別高。如果你機(jī)器上有 ab也就是 ApacheBench可以壓得更明顯一些ab -n 5000 -c 100 -k http://127.0.0.1/這條命令的含義是總共發(fā)送 5000 個(gè)請(qǐng)求同時(shí)保持 100 個(gè)并發(fā)連接-k表示啟用 keep-alive。ab 在測(cè)試時(shí)會(huì)持續(xù)請(qǐng)求能把 Nginx 的請(qǐng)求速率和活躍連接數(shù)明顯拉起來。執(zhí)行的時(shí)候建議一次只跑一種跑完等一分鐘讓 Zabbix 完成幾個(gè)采集周期再去前端看數(shù)據(jù)。如果立刻去看采集周期還沒到可能什么都看不到。5.2 分析 Latest data 和 Graphs進(jìn)入 Zabbix 前端的“監(jiān)測(cè) → 最新數(shù)據(jù)”選擇剛才創(chuàng)建的主機(jī)就能看到每條監(jiān)控項(xiàng)的當(dāng)前值。這時(shí)候你看到的應(yīng)該是有具體數(shù)字的綠色狀態(tài)而不是“不支持”或“無數(shù)據(jù)”。以剛才 ab 壓測(cè)為例壓測(cè)過程中可以看到 requests 數(shù)值沖上去壓測(cè)結(jié)束后又會(huì)回落。如果配上圖形把請(qǐng)求速率、活躍連接、Reading、Writing、Waiting 放在同一張圖里觀察能很直觀地看到整個(gè)請(qǐng)求生命周期的變化。如果你沒有在監(jiān)控項(xiàng)里單獨(dú)創(chuàng)建圖形也可以在儀表盤中添加一個(gè)圖表組件數(shù)據(jù)源選擇對(duì)應(yīng)主機(jī)的監(jiān)控項(xiàng)。Zabbix 的圖表組件支持把多個(gè)監(jiān)控項(xiàng)疊加到同一張圖上非常適合對(duì)比 Active connections、Reading、Writing、Waiting 這幾個(gè)相關(guān)指標(biāo)。5.3 從數(shù)據(jù)反向判斷 Nginx 狀態(tài)是否健康數(shù)據(jù)有了接下來的重點(diǎn)是怎么讀這些數(shù)字。先看 active connections 和 waiting 的關(guān)系。如果活躍連接數(shù)很高但 waiting 也很高說明大量連接是空閑 keep-aliveNginx 實(shí)際壓力不大只是在維持長(zhǎng)連接。如果活躍連接數(shù)高waiting 卻很低說明連接都在真正干活這時(shí)候負(fù)載才是真的高。再看 accepts 和 handled 的對(duì)比。正常情況下這兩個(gè)數(shù)值應(yīng)該非常接近。如果 handled 長(zhǎng)期明顯小于 accepts說明有一部分連接沒有被 Nginx 成功處理可能原因是 worker_connections 配置過低連接數(shù)被系統(tǒng)層面拒絕了。通過 Zabbix 監(jiān)控這兩個(gè)值的曲線差值能比看錯(cuò)誤日志更早發(fā)現(xiàn)問題。再看請(qǐng)求速率和連接速率的關(guān)系。用 requests 速率除以 accepts 速率可以得到平均每個(gè)連接上的請(qǐng)求數(shù)。如果這個(gè)值接近 1說明 keep-alive 基本沒起作用客戶端每次請(qǐng)求都新建連接連接效率很低。如果明顯大于 1說明 keep-alive 生效良好一個(gè)連接上處理了多個(gè)請(qǐng)求。Reading 和 Writing 是更細(xì)的觀察點(diǎn)。靜態(tài)資源站點(diǎn)在壓測(cè)時(shí)Writing 會(huì)明顯升高因?yàn)?Nginx 正在往客戶端輸出響應(yīng)。如果 Writing 持續(xù)高位但 requests 并不高可能是網(wǎng)絡(luò)帶寬打滿了響應(yīng)寫不出去。Reading 持續(xù)高位則要小心可能是客戶端請(qǐng)求頭發(fā)送緩慢也可能是存在慢連接這種情況即使活躍連接數(shù)不高worker 也可能被拖住。這些判斷不能只看一兩個(gè)采樣點(diǎn)最好結(jié)合 5 分鐘、1 小時(shí)的時(shí)間窗口來看趨勢(shì)。這也是為什么前面建議把趨勢(shì)數(shù)據(jù)保留時(shí)間設(shè)長(zhǎng)一些。6. 常見問題排查與生產(chǎn)環(huán)境落地的邊界6.1 Agent 顯示 Not supported 時(shí)按什么順序查Zabbix Agent 返回 Not supported 是監(jiān)控 Nginx 時(shí)最常遇到的問題。很多人第一反應(yīng)是去改 Zabbix 配置其實(shí)大多數(shù)時(shí)候問題出在 Agent 側(cè)。我的排查順序是固定的。第一步直接手動(dòng)執(zhí)行那條 UserParameter 命令看有沒有輸出。如果命令本身就沒輸出說明狀態(tài)頁(yè)、curl、awk 里有一環(huán)斷了。第二步確認(rèn)執(zhí)行用戶。Zabbix Agent 通常以 zabbix 用戶運(yùn)行手動(dòng)用 root 執(zhí)行成功不代表 zabbix 用戶能執(zhí)行??梢杂胹u - zabbix -s /bin/bash -c 命令來模擬 Agent 的執(zhí)行環(huán)境。第三步看 Agent 日志默認(rèn)在 /var/log/zabbix/zabbix_agentd.log。日志里會(huì)記錄 key 對(duì)應(yīng)的錯(cuò)誤信息比如命令找不到、執(zhí)行超時(shí)、權(quán)限不足等。第四步改完 UserParameter 后確認(rèn)重啟了 Agent。UserParameter 是在 Agent 啟動(dòng)時(shí)讀取的不重啟不會(huì)生效。第五步從 Server 端用 zabbix_get 測(cè)試連通性。這一步能區(qū)分問題是出在 Agent 執(zhí)行命令還是 Server 與 Agent 之間的網(wǎng)絡(luò)、端口、密鑰配置上。還有一個(gè)常見問題Linux 有 SELinux 或 AppArmor 環(huán)境時(shí)zabbix 用戶執(zhí)行 curl 連接本機(jī)端口可能會(huì)被攔截。手動(dòng)執(zhí)行正常Agent 執(zhí)行就是失敗排查到這一步時(shí)要看安全審計(jì)日志確認(rèn)是不是被策略攔截了。6.2 狀態(tài)頁(yè)不能直接暴露在公網(wǎng)前面配置 Nginx 狀態(tài)頁(yè)時(shí)寫了 allow 和 deny這個(gè)限制在正式環(huán)境同樣重要。stub_status 只有數(shù)據(jù)輸出沒有認(rèn)證、沒有訪問控制任何人拿到狀態(tài)頁(yè)地址就能看到你所有虛擬主機(jī)的連接數(shù)、請(qǐng)求量等信息。這些數(shù)據(jù)單獨(dú)看不算機(jī)密但結(jié)合業(yè)務(wù)時(shí)序可能暴露促銷活動(dòng)、低谷期等運(yùn)營(yíng)信息。所以生產(chǎn)環(huán)境要遵守幾個(gè)原則狀態(tài)頁(yè)只監(jiān)聽內(nèi)網(wǎng)地址或只允許內(nèi)網(wǎng)訪問。Zabbix Agent 與 Nginx 部署在一起時(shí)直接限制為 127.0.0.1。如果需要遠(yuǎn)程采集優(yōu)先讓 Agent 本機(jī)讀取不要讓其他機(jī)器直接 HTTP 訪問狀態(tài)頁(yè)。Nginx 服務(wù)本身就開啟了公網(wǎng)監(jiān)聽時(shí)更要檢查 allow 列表不要把公網(wǎng)網(wǎng)段放進(jìn)去。另外狀態(tài)頁(yè)建議使用獨(dú)立 location不要放在一個(gè)會(huì)匹配大量路徑的通用規(guī)則里避免被掃描工具順帶發(fā)現(xiàn)。access_log off也要保留否則每個(gè)狀態(tài)頁(yè)請(qǐng)求都會(huì)寫一條訪問日志白白增加磁盤 IO。6.3 多實(shí)例和規(guī)范化模板、宏、命名規(guī)則如果只有一臺(tái)機(jī)器手動(dòng)創(chuàng)建監(jiān)控項(xiàng)沒什么問題。一旦機(jī)器多起來比如七八臺(tái) Nginx 都要監(jiān)控逐臺(tái)手動(dòng)創(chuàng)建就很痛苦而且容易漏配。這時(shí)候應(yīng)該把監(jiān)控項(xiàng)、觸發(fā)器、圖形整理成模板。在模板里創(chuàng)建好 nginx.active、nginx.requests 這些監(jiān)控項(xiàng)和對(duì)應(yīng)的觸發(fā)器再把模板鏈接到主機(jī)上所有主機(jī)自動(dòng)繼承配置。后續(xù)要加閾值、加圖形只需要改模板一處所有主機(jī)同步生效。模板里的閾值可以做成宏比如{$NGINX_ACTIVE_WARN}、{$NGINX_REQ_HIGH}。這樣在不同業(yè)務(wù)機(jī)器上可以差異化覆蓋不用復(fù)制整個(gè)模板。比如 A 機(jī)器請(qǐng)求量本來就大警告閾值定 8000B 機(jī)器是小業(yè)務(wù)閾值定 1000。用宏就能在同一套模板下按主機(jī)單獨(dú)調(diào)整。key 的命名也要規(guī)范。前面用的 nginx.active、nginx.requests 就是比較清晰的命名方式。如果一臺(tái)機(jī)器上有多個(gè) Nginx 實(shí)例建議在 key 里帶實(shí)例編號(hào)比如 nginx1.active、nginx2.active避免數(shù)據(jù)串臺(tái)。6.4 歷史數(shù)據(jù)保留和監(jiān)控頻率最后聊一下采集頻率和數(shù)據(jù)保留。對(duì) Nginx 監(jiān)控來說30 秒到 1 分鐘的采集間隔已經(jīng)足夠。不要看到別人用 1 秒間隔就覺得越快越好越短的間隔意味著越多的 Agent 執(zhí)行、越多的 Server 輪詢和越大的存儲(chǔ)開銷。尤其是自定義 UserParameter 每次都執(zhí)行 curl 命令如果一臺(tái)機(jī)器上有 7 個(gè) nginx key每個(gè)采集周期就有 7 次 curl。機(jī)器數(shù)量一多這個(gè)開銷會(huì)被明顯放大。如果想降低開銷有兩個(gè)方向。一個(gè)方向是把采集間隔統(tǒng)一調(diào)大成 1 分鐘。Nginx 的指標(biāo)本來就是慢變量1 分鐘內(nèi)的尖峰對(duì)告警影響不大。另一個(gè)方向是寫一個(gè)單獨(dú)的采集腳本一次抓取狀態(tài)頁(yè)把結(jié)果寫到臨時(shí)文件再由多個(gè) UserParameter 去讀文件避免每次都重新 curl。后一種方案適合機(jī)器多、又不愿意放寬采集間隔的場(chǎng)景但腳本邏輯和錯(cuò)誤處理要寫得更嚴(yán)謹(jǐn)否則一個(gè)腳本崩了所有 nginx key 都會(huì)失效。歷史數(shù)據(jù)保留方面原始監(jiān)控值保留 7 到 14 天足夠趨勢(shì)數(shù)據(jù)保留 365 天用于回顧容量。如果你發(fā)現(xiàn)自己經(jīng)常要回溯更久之前的 Nginx 指標(biāo)建議單獨(dú)導(dǎo)出到外部存儲(chǔ)不要無限拉長(zhǎng) Zabbix 的保留周期否則數(shù)據(jù)庫(kù)膨脹之后整個(gè)監(jiān)控系統(tǒng)的查詢速度都會(huì)受影響。我個(gè)人更建議按這個(gè)順序落地先把狀態(tài)頁(yè)和 curl 驗(yàn)證跑通再用 zabbix_get 確認(rèn) key 有數(shù)據(jù)然后創(chuàng)建主機(jī)和監(jiān)控項(xiàng)最后才是觸發(fā)器和圖形。看起來流程更長(zhǎng)但每一步都有明確的成功標(biāo)準(zhǔn)出了問題也知道在哪一段排查。真正跑過一輪測(cè)試之后你會(huì)發(fā)現(xiàn) Zabbix 監(jiān)控 Nginx 并不復(fù)雜難點(diǎn)反而不是工具而是你愿不愿意把一個(gè)累計(jì)計(jì)數(shù)器、一個(gè)狀態(tài)頁(yè)字段吃透。