先說結論:專案遇到的主要瓶頸在cpu和uwsgi的listen引數。下面以時間順序記錄排查過程。
應用伺服器中uwsgi
部分配置如下:
[uwsgi]
strict = true
single-interpreter = true
die-on-term = true
socket=0.0.0.0:5001
pidfile=/tmp/uwsgi-exp-flask.pid
vacuum=true
# python 虛擬環境目錄:
home=/root/.local/share/virtualenvs/expression-flask-p9tmtecw
pythonpath=/var/www/expression-flask
# web 應用python主程式:
uid=root
gid=root
chdir=/var/www/expression-flask
max-fd=65535
# socket監聽佇列大小,預設100
listen=100
# 2程序,每個程序1執行緒
processes=2
# threads=1
# apscheduler requires enable-threads, if no worker threads are used
enable-threads=true
master=true
# 無master時自動結束worker
no-orphans=true
# 設定master程序名稱
procname-master=uwsgi master (%p)
# 平滑重啟最長等待時間(秒)
reload-mercy=6
此外/etc/sysctl.conf
部分配置如下:
net.ipv4.tcp_keepalive_time=1800
net.ipv4.tcp_keepalive_probes=3
net.ipv4.tcp_keepalive_intvl=15
net.ipv4.tcp_max_tw_buckets=25000
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=10
net.ipv4.tcp_syncookies=0
net.core.somaxconn=65535
發現效能問題後,首先需要定位慢在什麼地方。
# nginx配置(部分)
這樣可以看到如下這種時間記錄:
conn(upstream_connect_time)是nginx連線uwsgi花費的時間。這個圖是後來擷取的,最初req超5秒,conn超2秒。conn過大是uwsgi的listen引數過小造成的。listen佇列大小預設是100,滿了之後就會拒絕請求,這時候任務會被堆積在nginx端,記錄的conn就比較大。
通過把listen引數大小改成65535(不可超過net.core.somaxconn,否則uwsgi拒絕啟動),可以讓uwsgi接受更多請求放入backlog,所以降低了upstream_connect_time:
上面通過調整listen讓uwsgi一股腦地接受所有請求,並不能讓整體速度提高(請求失敗的都是499錯誤):
所以,還需要確認一下uwsgi和flask**到底是誰慢。
檢視uwsgi的日誌可看出耗時最長的請求執行了不到1秒:
所以**執行速度還可以,鍋是uwsgi的。
uwsgi處理很慢,是不是worker數量太少?所以嘗試把2程序增大到4/8/16/64程序,但是效能並沒有變好,4程序的時候似乎快了一點,8程序似乎又慢了一點,16/64程序反而導致效能再次下降。猜測是cpu效能不夠。prometheus和vps自帶監控精度都太低,不能看到瞬發的cpu佔用率,於是開htop肉眼觀察,發現請求到達時cpu占用可以到達88%上下,是挺高的。
(可能有人問為什麼要500併發瞬發而不連續壓測,因為連續壓測測試的是吞吐量而不是響應時間)
於是臨時搭個4核4g的伺服器部署nginx、uwsgi、flask**,redis和mongodb仍在原來的2核8g伺服器上,配置hosts通過內網訪問。
這下提公升很明顯:
只有第2、3個介面的最大響應時間超過3秒:
此時cpu峰值占用情況(上面是4核4g的應用伺服器,下面是2核8g的資料伺服器):
如何解決:
按預設的兩台4核4g應用伺服器,第2個介面ok。第三個介面時間過長是因為邏輯過於複雜,獲取題目之前先進行了試卷初始化工作。把這個介面拆分為兩個介面,ok。
單台4核4g應用伺服器+單台2核8g資料伺服器的情況下,把listen改回100看看對結果有多大影響:
此外uwsgi日誌中可查詢到佇列滿的告警資訊。
根據結果看listen的影響還是比較明顯的,數值過小和nginx的bargain太多而且不能充分調動每個worker的積極性。
記一次除錯
這是我最近幾個月來遇到的最棘手的乙個問題 昨天花了4個小時找出第一層次的原因 這個糾結啊,本來和老婆說好準時下班回家吃飯的,結果被這個問題拖了老久。這是乙個gradle的plugin,用來resolve公司內部的dependency的,弄完了跑測試專案的,拋乙個npe,而且npe還不在自己的 裡面。...
記一次除錯
這是我最近幾個月來遇到的最棘手的乙個問題 昨天花了4個小時找出第一層次的原因 這個糾結啊,本來和老婆說好準時下班回家吃飯的,結果被這個問題拖了老久。這是乙個gradle的plugin,用來resolve公司內部的dependency的,弄完了跑測試專案的,拋乙個npe,而且npe還不在自己的 裡面。...
記一次nginx module 除錯
參考了 先進入nginx工作目錄 usr local nginx sbin 使用gdb q tui q選項是以安靜模式啟動,不顯示gdb版本等資訊。tui選項可以顯示 介面 然後在gdb中啟動nginx shell nginx 啟動之後,可以檢視當前nginx中的程序號 shell pidof ng...