上一節,咱們一塊兒學習了怎麼使用動態追蹤來觀察應用程序和內核的行爲。先簡單來回顧一下。所謂動態追蹤,就是在系統或者應用程序還在正常運行的時候,經過內核中提供的探針,來動態
追蹤它們的行爲,從而輔助排查出性能問題的瓶頸。php
使用動態追蹤,即可以在不修改代碼也不重啓服務的狀況下,動態瞭解應用程序或者內核的行爲。這對排查線上的問題、特別是不容易重現的問題尤爲有效。linux
在 Linux 系統中,常見的動態追蹤方法包括 ftrace、perf、eBPF/BCC 以及 SystemTap 等。nginx
在 網絡請求延遲變大 的案例中,我帶你一塊兒分析了一個網絡請求延遲增大的問題。當時咱們分析知道,那是因爲服務器端開啓 TCP 的 Nagle 算法,而客戶端卻開啓了延遲確認所致使的。git
其實,除了延遲問題外,網絡請求的吞吐量降低,是另外一個常見的性能問題。那麼,針對這種吞吐量降低問題,咱們又該如何進行分析呢?github
接下來,我就以最經常使用的反向代理服務器 Nginx 爲例,帶你一塊兒看看,如何分析服務吞吐量降低的問題。算法
今天的案例須要用到兩臺虛擬機,仍是基於 Ubuntu 18.04,一樣適用於其餘的 Linux 系統。我使用的案例環境以下所示:docker
# 安裝必備 docker、curl 和 perf $ apt-get install -y docker.io curl build-essential linux-tools-common # 安裝火焰圖工具 $ git clone https://github.com/brendangregg/FlameGraph # 安裝 wrk $ git clone https://github.com/wg/wrk $ cd wrk && make && sudo cp wrk /usr/local/bin/
這些工具,咱們在前面的案例中已經屢次使用,這兒就再也不重複。你能夠打開兩個終端,分別登陸到這兩臺虛擬機中,並安裝上述工具。瀏覽器
注意,如下全部命令都默認以 root 用戶運行,若是你用普通用戶身份登錄系統,請運行 sudo su root 命令切換到 root 用戶。性能優化
到這裏,準備工做就完成了。接下來,咱們正式進入操做環節。bash
咱們今天要分析的案例是一個 Nginx + PHP 應用,它們的關係以下圖所示:
其中,wrk 和 curl 是 Nginx 的客戶端,而 PHP 應用則是一個簡單的 Hello World:
<?php echo "Hello World!" ?>
爲了方便你運行,我已經把案例應用打包成了兩個 Docker 鏡像,並推送到 Docker Hub 中。你能夠直接按照下面的步驟來運行它。
同時,爲了分析方便,這兩個容器都將運行在 host network 模式中。這樣,咱們就不用切換到容器的網絡命名空間,而能夠直接觀察它們的套接字狀態。
咱們先在終端一中,執行下面的命令,啓動 Nginx 應用,並監聽在 80 端口。若是一切正常,你應該能夠看到以下的輸出:
docker run --name nginx --network host --privileged -itd feisky/nginx-tp 6477c607c13b37943234755a14987ffb3a31c33a7f04f75bb1c190e710bce19e $ docker run --name phpfpm --network host --privileged -itd feisky/php-fpm-tp 09e0255159f0c8a647e22cd68bd097bec7efc48b21e5d91618ff29b882fa7c1f
而後,執行 docker ps 命令,查詢容器的狀態,你會發現,容器已經處於運行狀態(Up)了:
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 09e0255159f0 feisky/php-fpm-tp "php-fpm -F --pid /o…" 28 seconds ago Up 27 seconds phpfpm 6477c607c13b feisky/nginx-tp "/init.sh" 29 seconds ago Up 28 seconds nginx
不過,從 docker ps 的輸出,咱們只能知道容器處於運行狀態。至於 Nginx 能不能正常處理外部的請求,還須要咱們進一步確認。
接着,切換到終端二中,執行下面的 curl 命令,進一步驗證 Nginx 可否正常訪問。若是你看到「Hello World!」 的輸出,說明 Nginx+PHP 的應用已經正常啓動了:
curl http://192.168.0.30 Hello World!
提示:若是你看到不同的結果,能夠再次執行 docker ps -a 確認容器的狀態,並執行 docker logs < 容器名 > 來查看容器日誌,從而找出緣由
接下來,咱們就來測試一下,案例中 Nginx 的吞吐量。
咱們繼續在終端二中,執行 wrk 命令,來測試 Nginx 的性能:
# 默認測試時間爲 10s,請求超時 2s $ wrk --latency -c 1000 http://192.168.0.30 Running 10s test @ http://192.168.0.30 2 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 14.82ms 42.47ms 874.96ms 98.43% Req/Sec 550.55 1.36k 5.70k 93.10% Latency Distribution 50% 11.03ms 75% 15.90ms 90% 23.65ms 99% 215.03ms 1910 requests in 10.10s, 573.56KB read Non-2xx or 3xx responses: 1910 Requests/sec: 189.10 Transfer/sec: 56.78KB
從 wrk 的結果中,你能夠看到吞吐量(也就是每秒請求數)只有 189,而且全部 1910 個請求收到的都是異常響應(非 2xx 或 3xx)。這些數據顯然代表,吞吐量過低了,而且請求處理都失敗了。這是怎麼回事呢?
根據 wrk 輸出的統計結果,咱們能夠看到,總共傳輸的數據量只有 573 KB,那就確定不會是帶寬受限致使的。因此,咱們應該從請求數的角度來分析。
分析請求數,特別是 HTTP 的請求數,有什麼好思路嗎?固然就要從 TCP 鏈接數入手。
要查看 TCP 鏈接數的彙總狀況,首選工具天然是 ss 命令。爲了觀察 wrk 測試時發生的問題,咱們在終端二中再次啓動 wrk,而且把總的測試時間延長到 30 分鐘:
# 測試時間 30 分鐘 $ wrk --latency -c 1000 -d 1800 http://192.168.0.30
而後,回到終端一中,觀察 TCP 鏈接數:
ss -s Total: 177 (kernel 1565) TCP: 1193 (estab 5, closed 1178, orphaned 0, synrecv 0, timewait 1178/0), ports 0 Transport Total IP IPv6 * 1565 - - RAW 1 0 1 UDP 2 2 0 TCP 15 12 3 INET 18 14 4 FRAG 0 0 0
從這裏看出,wrk 併發 1000 請求時,創建鏈接數只有 5,而 closed 和 timewait 狀態的鏈接則有 1100 多 。其實從這兒你就能夠發現兩個問題:
分析問題,天然要先從相對簡單的下手。咱們先來看第二個關於 timewait 的問題。在以前的NAT 案例中,我已經提到過,內核中的鏈接跟蹤模塊,有可能會致使 timewait 問題。咱們今天
的案例仍是基於 Docker 運行,而 Docker 使用的 iptables ,就會使用鏈接跟蹤模塊來管理NAT。那麼,怎麼確認是否是鏈接跟蹤致使的問題呢?
其實,最簡單的方法,就是經過 dmesg 查看系統日誌,若是有鏈接跟蹤出了問題,應該會看到nf_conntrack 相關的日誌。
咱們能夠繼續在終端一中,運行下面的命令,查看系統日誌:
dmesg | tail [88356.354329] nf_conntrack: nf_conntrack: table full, dropping packet [88356.354374] nf_conntrack: nf_conntrack: table full, dropping packet
從日誌中,你能夠看到 nf_conntrack: table full, dropping packet 的錯誤日誌。這說明,正是鏈接跟蹤致使的問題。
這種狀況下,咱們應該想起前面學過的兩個內核選項——鏈接跟蹤數的最大限制nf_conntrack_max ,以及當前的鏈接跟蹤數 nf_conntrack_count。執行下面的命令,你就能夠
查詢這兩個選項:
sysctl net.netfilter.nf_conntrack_max net.netfilter.nf_conntrack_max = 200 $ sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_count = 200
此次的輸出中,你能夠看到最大的鏈接跟蹤限制只有 200,而且所有被佔用了。200 的限制顯然過小,不過相應的優化也很簡單,調大就能夠了。
咱們執行下面的命令,將 nf_conntrack_max 增大:
# 將鏈接跟蹤限制增大到 1048576 $ sysctl -w net.netfilter.nf_conntrack_max=1048576
鏈接跟蹤限制增大後,對 Nginx 吞吐量的優化效果如何呢?咱們不妨再來測試一下。你能夠切換到終端二中,按下 Ctrl+C ;而後執行下面的 wrk 命令,從新測試 Nginx 的性能:
# 默認測試時間爲 10s,請求超時 2s $ wrk --latency -c 1000 http://192.168.0.30 ... 54221 requests in 10.07s, 15.16MB read Socket errors: connect 0, read 7, write 0, timeout 110 Non-2xx or 3xx responses: 45577 Requests/sec: 5382.21 Transfer/sec: 1.50MB
從 wrk 的輸出中,你能夠看到,鏈接跟蹤的優化效果很是好,吞吐量已經從剛纔的 189 增大到了 5382。看起來性能提高了將近 30 倍,
不過,這是否是就能說明,咱們已經把 Nginx 的性能優化好了呢?
別急,咱們再來看看 wrk 彙報的其餘數據。果真,10s 內的總請求數雖然增大到了 5 萬,可是有4 萬多響應異常,說白了,真正成功的只有 8000 多個(54221-45577=8644)。
很明顯,大部分請求的響應都是異常的。那麼,該怎麼分析響應異常的問題呢?
因爲這些響應並不是 Socket error,說明 Nginx 已經收到了請求,只不過,響應的狀態碼並非咱們指望的 2xx (表示成功)或 3xx(表示重定向)。因此,這種狀況下,搞清楚 Nginx 真正
的響應就很重要了。
不過這也不難,咱們切換回終端一,執行下面的 docker 命令,查詢 Nginx 容器日誌就知道了:
docker logs nginx --tail 3 192.168.0.2 - - [15/Mar/2019:2243:27 +0000] "GET / HTTP/1.1" 499 0 "-" "-" "-" 192.168.0.2 - - [15/Mar/2019:22:43:27 +0000] "GET / HTTP/1.1" 499 0 "-" "-" "-" 192.168.0.2 - - [15/Mar/2019:22:43:27 +0000] "GET / HTTP/1.1" 499 0 "-" "-" "-"
從 Nginx 的日誌中,咱們能夠看到,響應狀態碼爲 499。
499 並不是標準的 HTTP 狀態碼,而是由 Nginx 擴展而來,表示服務器端還沒來得及響應時,客戶端就已經關閉鏈接了。換句話說,問題在於服務器端處理太慢,客戶端由於超時(wrk 超時時
間爲 2s),主動斷開了鏈接。
既然問題出在了服務器端處理慢,而案例自己是 Nginx+PHP 的應用,那是否是能夠猜想,是由於 PHP 處理過慢呢?
我麼能夠在終端中,執行下面的 docker 命令,查詢 PHP 容器日誌:
docker logs phpfpm --tail 5 [15-Mar-2019 22:28:56] WARNING: [pool www] server reached max_children setting (5), consider raising it [15-Mar-2019 22:43:17] WARNING: [pool www] server reached max_children setting (5), consider raising it
從這個日誌中,咱們能夠看到兩條警告信息,server reached max_children setting (5),並建議增大 max_children。
max_children 表示 php-fpm 子進程的最大數量,固然是數值越大,能夠同時處理的請求數就越多。不過因爲這是進程問題,數量增大,也會致使更多的內存和 CPU 佔用。因此,咱們還不能
設置得過大。
通常來講,每一個 php-fpm 子進程可能會佔用 20 MB 左右的內存。因此,你能夠根據內存和CPU 個數,估算一個合理的值。這兒我把它設置成了 20,並將優化後的配置從新打包成了
Docker 鏡像。你能夠執行下面的命令來執行它:
# 中止舊的容器 $ docker rm -f nginx phpfpm # 使用新鏡像啓動 Nginx 和 PHP $ docker run --name nginx --network host --privileged -itd feisky/nginx-tp:1 $ docker run --name phpfpm --network host --privileged -itd feisky/php-fpm-tp:1
而後咱們切換到終端二,再次執行下面的 wrk 命令,從新測試 Nginx 的性能:
# 默認測試時間爲 10s,請求超時 2s $ wrk --latency -c 1000 http://192.168.0.30 ... 47210 requests in 10.08s, 12.51MB read Socket errors: connect 0, read 4, write 0, timeout 91 Non-2xx or 3xx responses: 31692 Requests/sec: 4683.82 Transfer/sec: 1.24MB
從 wrk 的輸出中,能夠看到,雖然吞吐量只有 4683,比剛纔的 5382 少了一些;可是測試期間成功的請求數卻多了很多,從原來的 8000,增加到了 15000(47210-31692=15518)。
不過,雖然性能有所提高,可 4000 多的吞吐量顯然仍是比較差的,而且大部分請求的響應依然仍是異常。接下來,該怎麼去進一步提高 Nginx 的吞吐量呢?
回想一下網絡性能的分析套路,以及 Linux 協議棧的原理,咱們能夠從從套接字、TCP 協議等逐層分析。而分析的第一步,天然仍是要觀察有沒有發生丟包現象。
咱們切換到終端二中,從新運行測試,此次仍是要用 -d 參數延長測試時間,以便模擬性能瓶頸的現場:
# 測試時間 30 分鐘 $ wrk --latency -c 1000 -d 1800 http://192.168.0.30
而後回到終端一中,觀察有沒有發生套接字的丟包現象:
# 只關注套接字統計 $ netstat -s | grep socket 73 resets received for embryonic SYN_RECV sockets 308582 TCP sockets finished time wait in fast timer 8 delayed acks further delayed because of locked socket 290566 times the listen queue of a socket overflowed 290566 SYNs to LISTEN sockets dropped # 稍等一會,再次運行 $ netstat -s | grep socket 73 resets received for embryonic SYN_RECV sockets 314722 TCP sockets finished time wait in fast timer 8 delayed acks further delayed because of locked socket 344440 times the listen queue of a socket overflowed 344440 SYNs to LISTEN sockets dropped
根據兩次統計結果中 socket overflowed 和 sockets dropped 的變化,你能夠看到,有大量的套接字丟包,而且丟包都是套接字隊列溢出致使的。因此,接下來,咱們應該分析鏈接隊列的大
小是否是有異常。
你能夠執行下面的命令,查看套接字的隊列大小:
ss -ltnp State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 10 10 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=10491,fd=6),("nginx",pid=10490,fd=6),("nginx",pid=10487,fd=6)) LISTEN 7 10 *:9000 *:* users:(("php-fpm",pid=11084,fd=9),...,("php-fpm",pid=10529,fd=7))
此次能夠看到,Nginx 和 php-fpm 的監聽隊列 (Send-Q)只有 10,而 nginx 的當前監聽隊列長度 (Recv-Q)已經達到了最大值,php-fpm 也已經接近了最大值。很明顯,套接字監聽隊
列的長度過小了,須要增大。
關於套接字監聽隊列長度的設置,既能夠在應用程序中,經過套接字接口調整,也支持經過內核選項來配置。咱們繼續在終端一中,執行下面的命令,分別查詢 Nginx 和內核選項對監聽隊列長
度的配置:
# 查詢 nginx 監聽隊列長度配置 $ docker exec nginx cat /etc/nginx/nginx.conf | grep backlog listen 80 backlog=10; # 查詢 php-fpm 監聽隊列長度 $ docker exec phpfpm cat /opt/bitnami/php/etc/php-fpm.d/www.conf | grep backlog ; Set listen(2) backlog. ;listen.backlog = 511 # somaxconn 是系統級套接字監聽隊列上限 $ sysctl net.core.somaxconn net.core.somaxconn = 10
從輸出中能夠看到,Nginx 和 somaxconn 的配置都是 10,而 php-fpm 的配置也只有 511,顯然都過小了。那麼,優化方法就是增大這三個配置,好比,能夠把 Nginx 和 php-fpm 的隊列
長度增大到 8192,而把 somaxconn 增大到 65536。
一樣地,我也把這些優化後的 Nginx ,從新打包成了兩個 Docker 鏡像,你能夠執行下面的命令來運行它:
# 中止舊的容器 $ docker rm -f nginx phpfpm # 使用新鏡像啓動 Nginx 和 PHP $ docker run --name nginx --network host --privileged -itd feisky/nginx-tp:2 $ docker run --name phpfpm --network host --privileged -itd feisky/php-fpm-tp:2
而後,切換到終端二中,從新測試 Nginx 的性能:
wrk --latency -c 1000 http://192.168.0.30 ... 62247 requests in 10.06s, 18.25MB read Non-2xx or 3xx responses: 62247 Requests/sec: 6185.65 Transfer/sec: 1.81MB
如今的吞吐量已經增大到了 6185,而且在測試的時候,若是你在終端一中從新執行 netstat -s |grep socket,還會發現,如今已經沒有套接字丟包問題了。
不過,此次 Nginx 的響應,再一次所有失敗了,都是 Non-2xx or 3xx。這是怎麼回事呢?咱們再去終端一中,查看 Nginx 日誌:
docker logs nginx --tail 10 2019/03/15 16:52:39 [crit] 15#15: *999779 connect() to 127.0.0.1:9000 failed (99: Cannot assign requested address) while connecting to upstream, client: 192.168.0.2, server: localhost, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "192.168.0.30"
你能夠看到,Nginx 報出了沒法鏈接 fastcgi 的錯誤,錯誤消息是 Connect 時, Cannot assignrequested address。這個錯誤消息對應的錯誤代碼爲 EADDRNOTAVAIL,表示 IP 地址或者端
口號不可用。在這裏,顯然只能是端口號的問題。接下來,咱們就來分析端口號的狀況。
根據網絡套接字的原理,當客戶端鏈接服務器端時,須要分配一個臨時端口號,而 Nginx 正是PHP-FPM 的客戶端。端口號的範圍並非無限的,最多也只有 6 萬多。
咱們執行下面的命令,就能夠查詢系統配置的臨時端口號範圍:
sysctl net.ipv4.ip_local_port_range net.ipv4.ip_local_port_range=20000 20050
根據網絡套接字的原理,當客戶端鏈接服務器端時,須要分配一個臨時端口號,而 Nginx 正是PHP-FPM 的客戶端。端口號的範圍並非無限的,最多也只有 6 萬多。
咱們執行下面的命令,就能夠查詢系統配置的臨時端口號範圍:
sysctl -w net.ipv4.ip_local_port_range="10000 65535" net.ipv4.ip_local_port_range = 10000 65535
優化完成後,咱們再次切換到終端二中,測試性能:
wrk --latency -c 1000 http://192.168.0.30/ ... 32308 requests in 10.07s, 6.71MB read Socket errors: connect 0, read 2027, write 0, timeout 433 Non-2xx or 3xx responses: 30 Requests/sec: 3208.58 Transfer/sec: 682.15KB
此次,異常的響應少多了 ,不過,吞吐量也降低到了 3208。而且,此次還出現了不少 Socketread errors。顯然,還得進一步優化。
前面咱們已經優化了不少配置。這些配置在優化網絡的同時,卻也會帶來其餘資源使用的上升。
這樣來看,是否是說明其餘資源遇到瓶頸了呢?
咱們不妨在終端二中,執行下面的命令,從新啓動長時間測試:
# 測試時間 30 分鐘 $ wrk --latency -c 1000 -d 1800 http://192.168.0.30
而後,切換回終端一中,執行 top ,觀察 CPU 和內存的使用:
top ... %Cpu0 : 30.7 us, 48.7 sy, 0.0 ni, 2.3 id, 0.0 wa, 0.0 hi, 18.3 si, 0.0 st %Cpu1 : 28.2 us, 46.5 sy, 0.0 ni, 2.0 id, 0.0 wa, 0.0 hi, 23.3 si, 0.0 st KiB Mem : 8167020 total, 5867788 free, 490400 used, 1808832 buff/cache KiB Swap: 0 total, 0 free, 0 used. 7361172 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20379 systemd+ 20 0 38068 8692 2392 R 36.1 0.1 0:28.86 nginx 20381 systemd+ 20 0 38024 8700 2392 S 33.8 0.1 0:29.29 nginx 1558 root 20 0 1118172 85868 39044 S 32.8 1.1 22:55.79 dockerd 20313 root 20 0 11024 5968 3956 S 27.2 0.1 0:22.78 docker-containe 13730 root 20 0 0 0 0 I 4.0 0.0 0:10.07 kworker/u4:0-ev
從 top 的結果中能夠看到,可用內存仍是很充足的,但系統 CPU 使用率(sy)比較高,兩個CPU 的系統 CPU 使用率都接近 50%,且空閒 CPU 使用率只有 2%。再看進程部分,CPU 主要
被兩個 Nginx 進程和兩個 docker 相關的進程佔用,使用率都是 30% 左右。
CPU 使用率上升了,該怎麼進行分析呢?我想,你已經還記得咱們屢次用到的 perf,再配合前兩節講過的火焰圖,很容易就能找到系統中的熱點函數。
咱們保持終端二中的 wrk 繼續運行;在終端一中,執行 perf 和 flamegraph 腳本,生成火焰圖:
# 執行 perf 記錄事件 $ perf record -g # 切換到 FlameGraph 安裝路徑執行下面的命令生成火焰圖 $ perf script -i ~/perf.data | ./stackcollapse-perf.pl --all | ./flamegraph.pl > nginx.svg
而後,使用瀏覽器打開生成的 nginx.svg ,你就能夠看到下面的火焰圖:
根據咱們講過的火焰圖原理,這個圖應該從下往上、沿着調用棧中最寬的函數,來分析執行次數最多的函數。
這兒中間的 do_syscall_6四、tcp_v4_connect、inet_hash_connect 這個堆棧,很明顯就是最須要關注的地方。inet_hash_connect() 是 Linux 內核中負責分配臨時端口號的函數。因此,這個
瓶頸應該還在臨時端口的分配上。
在上一步的「端口號」優化中,臨時端口號的範圍,已經優化成了 「10000 65535」。這顯然是一個很是大的範圍,那麼,端口號的分配爲何又成了瓶頸呢?
一時想不到也不要緊,咱們能夠暫且放下,先看看其餘因素的影響。再順着 inet_hash_connect往堆棧上面查看,下一個熱點是 __init_check_established 函數。而這個函數的目的,是檢查端
口號是否可用。結合這一點,你應該能夠想到,若是有大量鏈接佔用着端口,那麼檢查端口號可用的函數,不就會消耗更多的 CPU 嗎?
實際是否如此呢?咱們能夠繼續在終端一中運行 ss 命令, 查看鏈接狀態統計:
ss -s TCP: 32775 (estab 1, closed 32768, orphaned 0, synrecv 0, timewait 32768/0), ports 0 ...
這回能夠看到,有大量鏈接(這兒是 32768)處於 timewait 狀態,而 timewait 狀態的鏈接,自己會繼續佔用端口號。若是這些端口號能夠重用,那麼天然就能夠縮短
__init_check_established 的過程。而 Linux 內核中,剛好有一個 tcp_tw_reuse 選項,用來控制端口號的重用。
咱們在終端一中,運行下面的命令,查詢它的配置:
sysctl net.ipv4.tcp_tw_reuse net.ipv4.tcp_tw_reuse = 0
你能夠看到,tcp_tw_reuse 是 0,也就是禁止狀態。其實看到這裏,咱們就能理解,爲何臨時端口號的分配會是系統運行的熱點了。固然,優化方法也很容易,把它設置成 1 就能夠開啓了。
我把優化後的應用,也打包成了兩個 Docker 鏡像,你能夠執行下面的命令來運行:
# 中止舊的容器 $ docker rm -f nginx phpfpm # 使用新鏡像啓動 Nginx 和 PHP $ docker run --name nginx --network host --privileged -itd feisky/nginx-tp:3 $ docker run --name phpfpm --network host --privileged -itd feisky/php-fpm-tp:3
容器啓動後,切換到終端二中,再次測試優化後的效果:
wrk --latency -c 1000 http://192.168.0.30/ ... 52119 requests in 10.06s, 10.81MB read Socket errors: connect 0, read 850, write 0, timeout 0 Requests/sec: 5180.48 Transfer/sec: 1.07MB
如今的吞吐量已經達到了 5000 多,而且只有少許的 Socket errors,也再也不有 Non-2xx or 3xx的響應了。說明一切終於正常了。
案例的最後,不要忘記執行下面的命令,刪除案例應用:
# 中止 nginx 和 phpfpm 容器 $ docker rm -f nginx phpfpm
今天,我帶你一塊兒學習了服務吞吐量降低後的分析方法。其實,從這個案例你也能夠看出,性能問題的分析,老是離不開系統和應用程序的原理。
實際上,分析性能瓶頸,最核心的也正是掌握運用這些原理。
首先,利用各類性能工具,收集想要的性能指標,從而清楚系統和應用程序的運行狀態;
其次,拿目前狀態跟系統原理進行比較,不一致的地方,就是咱們要重點分析的對象。
從這個角度出發,再進一步藉助 perf、火焰圖、bcc 等動態追蹤工具,找出熱點函數,就能夠定位瓶頸的來源,肯定相應的優化方法。