記錄《Linux效能最佳化》課程實踐過程。
環境準備
- 兩臺虛擬機器(Ubuntu 18.04)
- 機器配置:2 CPU,8GB 記憶體
- 預先安裝 docker、sysstat、perf、ab 等工具,如 apt install docker.io sysstat linux-tools-common apache2-utils
操作和分析
其中一臺用作 Web 伺服器,來模擬效能問題;另一臺用作 Web 伺服器的客戶端,來給 Web 服務增加壓力請求。
開啟兩個終端,分別 SSH 登入到兩臺機器上,並安裝上面提到的工具。
預設以 root 使用者執行所有命令,先執行 sudo su root 命令切換到 root 使用者。
由於 Nginx 和 PHP 的配置比較麻煩, 課程提供了兩個Docker 映象,這樣只需要執行兩個容器,就可以得到模擬環境。
執行docker容器應用
首先,在第一個終端執行下面的命令來執行 Nginx 和 PHP 應用:
$ docker run --name nginx -p 10000:80 -itd feisky/nginx
$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm
下載過程可能比較緩慢…下載完成後,執行 docker ps -a ,如圖:
第二個終端使用 curl 訪問 http://[VM1 的 IP]:10000,確認 Nginx 已正常啟動。
# 192.168.139.139是第一臺虛擬機器的IP地址
$ curl http://192.168.139.139:10000/
如圖:
壓力測試一
在第二個終端執行下面的 ab 命令:
# 併發10個請求測試Nginx效能,總共測試100個請求
$ ab -c 10 -n 100 http://192.168.139.139:10000/
如圖:
從 ab 的輸出結果我們可以看到,Nginx 能承受的每秒平均請求數只有 11.47。這個資料實際是很差的,如果暫時感覺不到什麼,那嘗試用 top 和 pidstat 再做觀察。
壓力測試二
繼續在第二個終端,執行 ab 命令:
# 這次將測試的請求總數增加到10000
$ ab -c 10 -n 10000 http://192.168.139.139:10000/
回到第一個終端執行 top 命令,並按下數字 1 ,切換到每個 CPU 的使用率:
這裡可以看到,系統中有幾個 php-fpm 程式的 CPU 使用率加起來接近 100%;而 CPU 的使用者使用率(us)也已經超過了 99%,接近飽和。這裡猜測是使用者空間的 php-fpm 程式,導致 CPU 使用率驟升。
perf 分析 php-fpm 程式
那怎麼知道是 php-fpm 的哪個函式導致了 CPU 使用率升高呢?我們來用 perf 分析一下。
在第一個終端執行下面的 perf 命令(如果提示命令not found,按提示安裝即可):
# -g開啟呼叫關係分析,-p指定php-fpm的程式號2250
$ perf top -g -p 2250
如圖:
透過方向鍵移動到 php-fpm 程式,透過 enter 鍵展開 + 號位置的內容,如圖:
可以看到,呼叫關係最終到了 sqrt 和 add_function。
grep 查詢具體函式
嘗試將PHP原始碼複製出來,然後檢視是不是呼叫了這兩個函式,
# 從容器phpfpm中將PHP原始碼複製出來
$ docker cp phpfpm:/app .
# 使用grep查詢函式呼叫
$ grep sqrt -r app/ #找到了sqrt呼叫
$ grep add_function -r app/ #沒找到add_function呼叫,這其實是PHP內建函式
如圖:
到這裡可知,只有 sqrt 函式在 app/index.php 被呼叫。最後我們來看下這個檔案原始碼,
其實,這裡的本意,//test only 下的程式碼是不應該存在的,因為它造成多餘地消耗CPU。程式碼雖然簡單,但我們還是嘗試把測試程式碼刪除,再看看執行效果吧。
最佳化應用程式碼
課程提供了一個最佳化後的映象,可以如下操作:
# 停止原來的應用
$ docker rm -f nginx phpfpm
# 執行最佳化後的應用
$ docker run --name nginx -p 10000:80 -itd feisky/nginx:cpu-fix
$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:cpu-fix
不過,我想直接在現有容器上修改,修改已經複製出來的 index.php
然後覆蓋到php-fpm容器裡面,並驗證是否更新了程式碼,
壓力測試三
確保終端一正常執行 Nginx 和 PHP 應用,切換到終端二,首先 Ctrl+C 停止之前的 ab 命令後,再執行下面的命令:
ab -c 10 -n 10000 http://192.168.139.139:10000/
如圖:
可以看到,現在每秒的平均請求數,已經從原來的 11 變成了 1222。
結語
本案例程式碼設計較為簡單,工作中可能遇到更加複雜的問題,這裡只是分享下,一種查詢發現問題的方法。
同時,我會把更多實踐案例歸納在 Linux 效能最佳化筆記 文章底部,歡迎閱讀。
本作品採用《CC 協議》,轉載必須註明作者和本文連結