流弊666,Java應(yīng)用之性能測試瓶頸調(diào)優(yōu)
點擊上方藍色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達
引言:性能瓶頸調(diào)優(yōu)
性能調(diào)優(yōu)步驟
確定問題:根據(jù)性能監(jiān)控的數(shù)據(jù)和性能分析的結(jié)果,確定性能存在的問題。 確定原因:確定問題之后,對問題進行分析,找出問題的原因。 確定解決方案(改服務(wù)器參數(shù)配置/增加硬件資源配置/修改代碼)。 驗證解決方案,分析調(diào)優(yōu)結(jié)果。
性能瓶頸概率分布
數(shù)據(jù)庫服務(wù)器 CPU 使用率高(慢查詢、SQL 過多、連接數(shù)過多) 拋出連接數(shù)過多(連接池設(shè)置太小,導(dǎo)致連接排隊) 數(shù)據(jù)庫出現(xiàn)死鎖
應(yīng)用出現(xiàn)內(nèi)存泄露 應(yīng)用出現(xiàn)線程競爭/死鎖 程序代碼的算法復(fù)雜度 中間件、第三方應(yīng)用出現(xiàn)異常 計算密集型任務(wù)引起 CPU 負載高 I/O 密集型任務(wù)引起 I/O 負載高
JMeter 單機負載能力有限,如果需要模擬的用戶請求數(shù)超過其負載極限,也會導(dǎo)致 TPS 壓不上去
Linux 可用內(nèi)存無法回收(開銷速率大于回收速率)
系統(tǒng)資源

CPU 監(jiān)控內(nèi)容:CPU 使用率、CPU 使用類型(用戶進程、內(nèi)核進程) 瓶頸分析:CPU已壓滿(接近 100%),需要再看其他指標(biāo)的拐點所出現(xiàn)的時刻是否與 CPU 壓滿的時刻基本一致。 內(nèi)存 監(jiān)控內(nèi)容:實際內(nèi)存、虛擬內(nèi)存 瓶頸分析:內(nèi)存不足時,操作系統(tǒng)會使用虛擬內(nèi)存,從虛擬內(nèi)存讀取數(shù)據(jù),影響處理速度。 磁盤 I/O 監(jiān)控內(nèi)容:I/O 速度、磁盤等待隊列 瓶頸分析:磁盤 I/O 成為瓶頸時,會出現(xiàn)磁盤I/O繁忙,導(dǎo)致交易執(zhí)行時在 I/O 處等待。 網(wǎng)絡(luò) 監(jiān)控內(nèi)容:網(wǎng)絡(luò)流量(帶寬使用率)、網(wǎng)絡(luò)連接狀態(tài) 瓶頸分析:如果接口傳遞的數(shù)據(jù)包過大,超過了帶寬的傳輸能力,就會造成網(wǎng)絡(luò)資源競爭, 導(dǎo)致 TPS 上不去。
CPU 瓶頸:增加 CPU 資源。 內(nèi)存瓶頸:增加內(nèi)存、釋放緩存。 磁盤 I/O 瓶頸:更換性能更高的磁盤(如固態(tài) SSD)。 網(wǎng)絡(luò)帶寬瓶頸;增加網(wǎng)絡(luò)帶寬。
CPU
top 參數(shù)詳解

us(user):運行(未調(diào)整優(yōu)先級的)用戶進程所消耗的 CPU 時間的百分比。 像 shell 程序、各種語言的編譯器、數(shù)據(jù)庫應(yīng)用、web 服務(wù)器和各種桌面應(yīng)用都算是運行在用戶地址空間的進程。 這些程序如果不是處于 idle 狀態(tài),那么絕大多數(shù)的 CPU 時間都是運行在用戶態(tài)。 sy(system):運行內(nèi)核進程所消耗的 CPU 時間的百分比。 所有進程要使用的系統(tǒng)資源都是由 Linux 內(nèi)核處理的。當(dāng)處于用戶態(tài)(用戶地址空間)的進程需要使用系統(tǒng)的資源時,比如需要分配一些內(nèi)存、或是執(zhí)行 I/O 操作、再或者是去創(chuàng)建一個子進程,此時就會進入內(nèi)核態(tài)(內(nèi)核地址空間)運行。事實上,決定進程在下一時刻是否會被運行的進程調(diào)度程序就運行在內(nèi)核態(tài)。 對于操作系統(tǒng)的設(shè)計來說,消耗在內(nèi)核態(tài)的時間應(yīng)該是越少越好。通常 sy 比例過高意味著被測服務(wù)在用戶態(tài)和系統(tǒng)態(tài)之間切換比較頻繁,此時系統(tǒng)整體性能會有一定下降。 在實踐中有一類典型的情況會使 sy 變大,那就是大量的 I/O 操作,因此在調(diào)查 I/O 相關(guān)的問題時需要著重關(guān)注它。 大部分后臺服務(wù)使用的 CPU 時間片中 us 和 sy 的占用比例是最高的。同時這兩個指標(biāo)又是互相影響的,us 的比例高了,sy 的比例就低,反之亦然。 另外,在使用多核 CPU 的服務(wù)器上,CPU 0 負責(zé) CPU 各核間的調(diào)度,CPU 0 上的使用率過高會導(dǎo)致其他 CPU 核心之間的調(diào)度效率變低。因此測試過程中需要重點關(guān)注 CPU 0。 ni(niced):用做 nice 加權(quán)的進程分配的用戶態(tài) CPU 時間百分比。 每個 Linux 進程都有個優(yōu)先級,優(yōu)先級高的進程有優(yōu)先執(zhí)行的權(quán)利,這個叫做 pri。進程除了優(yōu)先級外,還有個優(yōu)先級的修正值。這個修正值就叫做進程的 nice 值。 這里顯示的 ni 表示調(diào)整過 nice 值的進程消耗掉的 CPU 時間。如果系統(tǒng)中沒有進程被調(diào)整過 nice 值,那么 ni 就顯示為 0。 一般來說,被測服務(wù)和服務(wù)器整體的 ni 值不會很高。如果測試過程中 ni 的值比較高,需要從服務(wù)器 Linux 系統(tǒng)配置、被測服務(wù)運行參數(shù)查找原因。 id(idle):空閑的 CPU 時間百分比。 一般情況下, us + ni + id 應(yīng)該接近 100%。 線上服務(wù)運行過程中,需要保留一定的 id 冗余來應(yīng)對突發(fā)的流量激增。 在性能測試過程中,如果 id 一直很低,吞吐量上不去,需要檢查被測服務(wù)線程/進程配置、服務(wù)器系統(tǒng)配置等。 wa(I/O wait):CPU 等待 I/O 完成時間百分比。 和 CPU 的處理速度相比,磁盤 I/O 操作是非常慢的。有很多這樣的操作,比如:CPU 在啟動一個磁盤讀寫操作后,需要等待磁盤讀寫操作的結(jié)果。在磁盤讀寫操作完成前,CPU 只能處于空閑狀態(tài)。 Linux 系統(tǒng)在計算系統(tǒng)平均負載時會把 CPU 等待 I/O 操作的時間也計算進去,所以在我們看到系統(tǒng)平均負載過高時,可以通過 wa 來判斷系統(tǒng)的性能瓶頸是不是過多的 I/O 操作造成的。 磁盤、網(wǎng)絡(luò)等 I/O 操作會導(dǎo)致 CPU 的 wa 指標(biāo)提高。通常情況下,網(wǎng)絡(luò) I/O 占用的 wa 資源不會很高,而頻繁的磁盤讀寫會導(dǎo)致 wa 激增。 如果被測服務(wù)不是 I/O 密集型的服務(wù),那需要檢查被測服務(wù)的日志量、數(shù)據(jù)載入頻率等。 如果 wa 高于 10% 則系統(tǒng)開始出現(xiàn)卡頓;若高于 20% 則系統(tǒng)幾乎動不了;若高于 50% 則很可能磁盤出現(xiàn)故障。 hi:硬中斷消耗時間百分比。 si:軟中斷消耗時間百分比。 硬中斷是外設(shè)對 CPU 的中斷,即外圍硬件發(fā)給 CPU 或者內(nèi)存的異步信號就是硬中斷信號;軟中斷由軟件本身發(fā)給操作系統(tǒng)內(nèi)核的中斷信號。 通常是由硬中斷處理程序或進程調(diào)度程序?qū)Σ僮飨到y(tǒng)內(nèi)核的中斷,也就是我們常說的系統(tǒng)調(diào)用(System Call)。 在性能測試過程中,hi 會有一定的 CPU 占用率,但不會太高。對于 I/O 密集型的服務(wù),si 的 CPU 占用率會高一些。 st:虛擬機等待 CPU 資源的時間。 只有 Linux 在作為虛擬機運行時 st 才是有意義的。它表示虛機等待 CPU 資源的時間(虛機分到的是虛擬 CPU,當(dāng)需要真實的 CPU 時,可能真實的 CPU 正在運行其它虛機的任務(wù),所以需要等待)。
性能分析思路
wa(IO wait)的值過高,表示硬盤存在 I/O 瓶頸。 id(idle)值高,表示 CPU 較空閑。 如果 id 值高但系統(tǒng)響應(yīng)慢時,有可能是 CPU 等待分配內(nèi)存,此時應(yīng)加大內(nèi)存容量。 如果 id 值持續(xù)低于 10,那么系統(tǒng)的 CPU 處理能力相對較低,表明系統(tǒng)中最需要解決的資源是 CPU。
案例分析
服務(wù)對磁盤讀寫的業(yè)務(wù)邏輯有問題,讀寫頻率過高,寫入數(shù)據(jù)量過大,如不合理的數(shù)據(jù)載入策略、log 過多等,都有可能導(dǎo)致這種問題。 服務(wù)器內(nèi)存不足,服務(wù)在 swap 分區(qū)不停的換入換出。
LOAD


/proc/cpuinfo 中的 processors 的最大值不一定是 CPU 的核數(shù),有可能該 CPU 支持超線程技術(shù),從而 processors 是物理核數(shù)的 2 倍。 這里我們需要準(zhǔn)確的核數(shù),具體方法為:找到 /proc/cpuinfo 文件中所有的 physical id 后的數(shù)值,取得最大的數(shù)值,加一后就是實際的 CPU 個數(shù)。然后查找任意一個 processors 下的 cpu cores,即是該顆 CPU 的核數(shù),實際 CPU 個數(shù)乘以核數(shù)即為 CPU 的物理總核數(shù)。
[root@localhost home]# cat /proc/cpuinfo |grep "physical id"
physical id : 0
physical id : 0
[root@localhost home]# cat /proc/cpuinfo |grep "cpu cores"
cpu cores : 2
cpu cores : 2
負載測試時:系統(tǒng)負載應(yīng)接近但不能超過閾值。 并發(fā)測試時:系統(tǒng)負載最高不能超過閾值的 80%。 穩(wěn)定性測試時:系統(tǒng)負載應(yīng)在閾值的 50% 左右。
如果 1 分鐘 load 很高,5 分鐘 load 較高,15 分鐘 load 起伏不大的情況下,說明該次高 load 為突發(fā)情況,可以容忍。 如果高 load 持續(xù),導(dǎo)致 5 分鐘和 15 分鐘 load 都已經(jīng)超過報警值,這時候需要考慮進行處理。 如果 15 分鐘 load 高于 1 分鐘 load,說明高 load 情況已經(jīng)得到緩解。
內(nèi)存
top 參數(shù)詳解

VIRT:進程所使用的虛擬內(nèi)存的總數(shù)。它包括所有的代碼,數(shù)據(jù)和共享庫,加上已換出的頁面,所有已申請的總內(nèi)存空間。 RES:進程正在使用的沒有交換的物理內(nèi)存(棧、堆)。申請內(nèi)存后該內(nèi)存段已被重新賦值。 SHR:進程使用共享內(nèi)存的總數(shù)。該數(shù)值只是反映可能與其它進程共享的內(nèi)存,不代表這段內(nèi)存當(dāng)前正被其他進程使用。 SWAP:進程使用的虛擬內(nèi)存中被換出的大小。交換的是已經(jīng)申請但沒有使用的空間(包括棧、堆、共享內(nèi)存)。 DATA:進程除可執(zhí)行代碼以外的物理內(nèi)存總量,即進程棧、堆申請的總空間。
free 參數(shù)詳解

Mem 行:物理內(nèi)存的使用情況。 Swap 行:交換空間的使用情況。 swap space 是磁盤上的一塊區(qū)域,可以是一個分區(qū),也可以是一個文件,所以具體的實現(xiàn)可以是 swap 分區(qū)也可以是 swap 文件。當(dāng)系統(tǒng)物理內(nèi)存吃緊時,Linux 會將內(nèi)存中不常訪問的數(shù)據(jù)保存到 swap 上,這樣系統(tǒng)就有更多的物理內(nèi)存為各個進程服務(wù),而當(dāng)系統(tǒng)需要訪問 swap 上存儲的內(nèi)容時,再將 swap 上的數(shù)據(jù)加載到內(nèi)存中,這就是常說的換出和換入。 交換空間可以在一定程度上緩解內(nèi)存不足的情況,但是它需要讀寫磁盤數(shù)據(jù),所以性能不是很高。因此當(dāng)交換空間內(nèi)存開始使用,則表明內(nèi)存嚴(yán)重不足。 如果系統(tǒng)內(nèi)存充足或是做性能壓測的機器,可以使用 swapoff -a 關(guān)閉交換空間,或在 /etc/sysctl.conf 文件中設(shè)置 swappiness 值。如果系統(tǒng)內(nèi)存不富余,則需要根據(jù)物理內(nèi)存的大小來設(shè)置交換空間的大小,具體的策略網(wǎng)上有很豐富的資料。 total 列:系統(tǒng)總的可用物理內(nèi)存和交換空間大小。 used 列:已經(jīng)被使用的物理內(nèi)存和交換空間大小。 free 列:還有多少物理內(nèi)存和交換空間可用使用(真正尚未被使用的物理內(nèi)存數(shù)量)。 在吞吐量固定的前提下,如果內(nèi)存持續(xù)上漲,那么很有可能是被測服務(wù)存在明顯的內(nèi)存泄漏,需要使用 valgrind 等內(nèi)存檢查工具進行定位。 shared 列:被共享使用的物理內(nèi)存大小。 buffer/cache 列:被 buffer 和 cache 使用了的物理內(nèi)存大小。 Linux 內(nèi)核為了提升磁盤操作的性能,會消耗一部分空閑內(nèi)存去緩存磁盤數(shù)據(jù),就是 buffer 和 cache。 如果給所有應(yīng)用分配足夠內(nèi)存后,物理內(nèi)存還有剩余,linux 會盡量再利用這些空閑內(nèi)存,以提高整體 I/O 效率,其方法是把這部分剩余內(nèi)存再劃分為 cache 及 buffer 兩部分加以利用。 所以,空閑物理內(nèi)存不多,不一定表示系統(tǒng)運行狀態(tài)很差,因為內(nèi)存的 cache 及 buffer 部分可以隨時被重用,在某種意義上,這兩部分內(nèi)存也可以看作是額外的空閑內(nèi)存。 available 列:還可以被應(yīng)用程序使用的物理內(nèi)存大小。 從應(yīng)用程序的角度來說,available = free + buffer + cache。請注意,這只是一個很理想的計算方式,實際中的數(shù)據(jù)往往有較大的誤差。
snyc
echo 3 > /proc/sys/vm/drop_caches
free -m
/proc/sys/vm/drop_caches 這個值的 0 改為 1
磁盤 I/O

tps:該設(shè)備每秒的傳輸次數(shù)?!耙淮蝹鬏敗币馑际恰耙淮?I/O 請求”。多個邏輯請求可能會被合并為“一次 I/O 請求”?!耙淮蝹鬏敗闭埱蟮拇笮∈俏粗?。 kB_read/s:每秒從設(shè)備(driveexpressed)讀取的數(shù)據(jù)量,單位為 Kilobytes。 kB_wrtn/s:每秒向設(shè)備(driveexpressed)寫入的數(shù)據(jù)量,單位為 Kilobytes。 kB_read:讀取的總數(shù)據(jù)量,單位為 Kilobytes。 kB_wrtn:寫入的總數(shù)量數(shù)據(jù)量,單位為 Kilobytes。

rrqm/s:每秒這個設(shè)備相關(guān)的讀取請求有多少被 Merge 了。 當(dāng)系統(tǒng)調(diào)用需要讀取數(shù)據(jù)的時候,VFS 將請求發(fā)到各個 FS,如果 FS 發(fā)現(xiàn)不同的讀取請求讀取的是相同 Block 的數(shù)據(jù),F(xiàn)S 會將這個請求合并 Merge。 wrqm/s:每秒這個設(shè)備相關(guān)的寫入請求有多少被 Merge 了。 await:每一個 I/O 請求的處理的平均時間(單位:毫秒)。 await 的大小一般取決于服務(wù)時間(svtcm)以及 I/O 隊列的長度和 I/O 請求的發(fā)出模式。假設(shè) svtcm 比較接近 await,說明 I/O 差點沒有等待時間。 假設(shè) await 遠大于 svctm(如大于 5),就要考慮 I/O 有壓力瓶頸,說明 I/O 隊列太長,應(yīng)用得到的響應(yīng)時間變慢。假設(shè)響應(yīng)時間超過了用戶能夠容許的范圍,這時可以考慮更換更快的磁盤。 svctm:I/O 平均服務(wù)時間。 %util:在統(tǒng)計時間內(nèi)有百分之多少用于 I/O 操作。 例如,如果統(tǒng)計間隔 1 秒,該設(shè)備有 0.8 秒在處理 I/O,而 0.2 秒閑置,那么該設(shè)備的 %util = 0.8/1 = 80%,該參數(shù)暗示了設(shè)備的繁忙程度。 %util 接近100% 表明 I/O 請求太多,I/O 系統(tǒng)繁忙,磁盤可能存在瓶頸。
iostat -x 完整參數(shù)如下:
- rrqm/s: 每秒進行 merge 的讀操作數(shù)目。即 delta(rerge)/s
- wrqm/s: 每秒進行 merge 的寫操作數(shù)目。即 delta(wmerge)/s
- t/s: 每秒完成的讀 I/O 設(shè)備次數(shù)。即 delta(rioVs
- w/s: 每秒完成的寫 1/O 設(shè)備次數(shù)。即 delta(wio)/s
- rsec/s: 每秒讀扇區(qū)數(shù)。即 delta(rsect)/s
- ws0c/s: 每秒寫扇區(qū)數(shù)。即 deita(wsect)/s
- rkB/s: 每秒讀 K 字節(jié)數(shù)。是 rsect/s 的一半,因為每扇區(qū)大小為 512 字節(jié)。(需要計算)
- wkB/s: 每秒寫 K 字節(jié)數(shù)。是 wsect/s 的一半。(需要計算)
- avgrq+sz: 平均每次設(shè)備 I/O 操作的數(shù)據(jù)大?。ㄉ葏^(qū))。delta(rsect+wsect)/delta(rio+wio)
- avgqu-sz: 平均I/O隊列長度,即delta(avea)/s/1000(因為 aveq 的單位為毫秒)。
- await: 平均每次設(shè)備 I/O 操作的等待時間(毫秒)。即 delta(ruse+wuse)/delta(rio+wio)
- svctm: 平均每次設(shè)備 I/O 操作的服務(wù)時間(毫秒)。即 delta(use)/delta(rio+wio)
- %util:一秒中有百分之多少的時間用于 I/O 操作,或者說一秒中有多少時間 I/O 隊列是非空的。即 delta(use)/s/1000(因為 use 的單位為毫秒)
網(wǎng)絡(luò)
網(wǎng)絡(luò)流量監(jiān)控

看視頻看新聞使用帶寬:客戶端的下載、服務(wù)端的上行帶寬。 服務(wù)端接收客戶端的數(shù)據(jù)使用帶寬:客戶端的上傳、服務(wù)端的下行帶寬。
1 Mb/s 帶寬速度為 128 KB/s(1024Kb / 8KB) 100 Mb/s 帶寬速度為 12.5 Mb/s(考慮網(wǎng)絡(luò)損耗通常按 10M/s 或 1280KB/s 算)
10M 帶寬約 20 秒:耗時 = 流量 / 速率 = 20MB / (10Mb/8) = 20 / 1.25 = 16 秒(按 1MB/s=128KB/s 速度算即 20 秒) 100M 帶寬約 2 秒:耗時 = 流量 / 速率 = 20MB / (100Mb/8) = 20 / 12.5 = 1.6 秒(按 10MB/s=128KB/s 速度算即 2 秒) 1000M 帶寬約 0.2 秒:耗時 = 流量 / 速率 = 20MB / (1000Mb/8) = 20 / 125 = 0.16 秒(按 100MB/s=128KB/s 速度算即 0.2 秒)

硬件解決:增加帶寬(帶寬便宜)。 軟件解決:分析對應(yīng)業(yè)務(wù)操作的數(shù)據(jù)傳送內(nèi)容是否可精簡;是否可以異步傳送。
網(wǎng)絡(luò)連接狀態(tài)監(jiān)控
對于使用 TCP 協(xié)議的服務(wù),需要監(jiān)控服務(wù)已建立連接的變化情況(即 ESTABLISHED 狀態(tài)的 TCP 連接)。 對于 HTTP 協(xié)議的服務(wù),需要監(jiān)控被測服務(wù)對應(yīng)進程的網(wǎng)絡(luò)緩沖區(qū)的狀態(tài)、TIME_WAIT 狀態(tài)的連接數(shù)等。


數(shù)據(jù)庫
慢查詢
更具體的慢 SQL 分析優(yōu)化,可參見《MySQL 慢 SQL & 優(yōu)化方案》。
show variables like "slow%";
mysql -uroot -p123456 -h127.0.0.1 -p3307 -e "show full processlist" |grep dbname |grep -v NULL
分析 SQL 是否加載了不必要的字段/數(shù)據(jù)。 分析 SQL 是否命中索引。 如果 SQL 很復(fù)雜,優(yōu)化 SQL 結(jié)構(gòu)。 如果表數(shù)據(jù)量太大,考慮分表。 ……
連接數(shù)
當(dāng)數(shù)據(jù)庫連接池被占滿時,如果有新的 SQL 語句要執(zhí)行,只能排隊等待,等待連接池中的連接被釋放(等待之前的 SQL 語句執(zhí)行完成)。 如果監(jiān)控發(fā)現(xiàn)數(shù)據(jù)庫連接池的使用率過高,甚至是經(jīng)常出現(xiàn)排隊的情況,則需要進行調(diào)優(yōu)。
-- 查看最大連接數(shù) -- 查看最大連接數(shù)
mysql> show variables like '%max_connection%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| extra_max_connections | |
| max_connections | 2512 |
+-----------------------+-------+
2 rows in set (0.00 sec)
-- 重新設(shè)置最大連接數(shù)
set global max_connections=1000;
[mysqld]
max_connections = 1000
mysql> show status like 'Threads%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_cached | 32 |
| Threads_connected | 10 |
| Threads_created | 50 |
| Threads_rejected | 0 |
| Threads_running | 1 |
+-------------------+-------+
5 rows in set (0.00 sec)
Threads_connected:表示當(dāng)前連接數(shù)。跟 show processlist 結(jié)果相同。準(zhǔn)確的來說,Threads_running 代表的是當(dāng)前并發(fā)數(shù)。 Threads_running:表示激活的連接數(shù)。一般遠低于 connected 數(shù)值。 Threads_created:表示創(chuàng)建過的線程數(shù)。 如果我們在 MySQL 服務(wù)器配置文件中設(shè)置了 thread_cache_size,那么當(dāng)客戶端斷開之后,服務(wù)器處理此客戶的線程將會緩存起來以響應(yīng)下一個客戶而不是銷毀(前提是緩存數(shù)未達上限)。 如果發(fā)現(xiàn) Threads_created 值過大的話,表明 MySQL 服務(wù)器一直在創(chuàng)建線程,這也是比較耗資源,因此可以適當(dāng)增加配置文件中 thread_cache_size 值。
mysql> show variables like 'thread_cache_size';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| thread_cache_size | 100 |
+-------------------+-------+
1 row in set (0.00 sec)
鎖
緩存命中率
通常,SQL 查詢是從磁盤中的數(shù)據(jù)庫文件中讀取數(shù)據(jù)。 若當(dāng)某一個 SQL 查詢語句之前執(zhí)行過,則該 SQL 語句及查詢結(jié)果都會被緩存下來,下次再查詢相同的 SQL 語句時,就會直接從數(shù)據(jù)庫緩存中讀取。(注意,MySQL 8 開始已廢棄查詢緩存功能。)

業(yè)務(wù)執(zhí)行過程中 SQL 查詢時的緩存命中率(查詢語句讀取緩存的次數(shù)占總查詢次數(shù)的比例)。 如果緩存命中率過低,需要優(yōu)化對應(yīng)的代碼和 SQL 查詢語句,以提高緩存命中率。
案例分析

使用 top 命令觀察,確定是 mysqld 導(dǎo)致還是其他原因。 CPU 分為用戶 CPU 和內(nèi)核 CPU。綜合其他的各項資源指標(biāo)來分析,發(fā)現(xiàn)內(nèi)存、磁盤IO、網(wǎng)絡(luò)等指標(biāo)無任何異常,因此判斷此處不是內(nèi)核 CPU 占用高,主要原因是用戶進程占用的 CPU 高。 確認目前 CPU 占用高的為 mysqld 進程。 分析數(shù)據(jù)庫服務(wù)器 CPU 高的可能原因:慢 SQL、SQL 語句過多、連接數(shù)過多等。 使用show full processlist查看當(dāng)前數(shù)據(jù)庫中正在執(zhí)行的 SQL 語句及連接池的狀態(tài),發(fā)現(xiàn)大量 SQL 在等待執(zhí)行。 再結(jié)合操作過程中的系統(tǒng)日志進行分析,發(fā)現(xiàn)每進入一次商城首頁,就需要在數(shù)據(jù)庫中執(zhí)行 19 條查詢 SQL。 查看慢查詢?nèi)罩荆纯词欠裼谐^預(yù)期指標(biāo)的 SQL 語句,并分析排查:看看執(zhí)行計劃是否準(zhǔn)確、索引是否缺失、數(shù)據(jù)量是否太大等。 目前案例經(jīng)過慢查詢?nèi)罩镜姆治觯创嬖诼樵儭?/span> 確認是否存在慢 SQL: 確認是否 SQL 語句過多或連接數(shù)過多:
硬件解決:增加 CPU。 軟件解決:為減少一次性加載過多 SQL,可考慮使用分批次、異步加載的方式(展示到什么位置,就查詢什么位置的數(shù)據(jù))。
JAVA 應(yīng)用
JVM



垃圾回收機制
垃圾回收指將內(nèi)存中已申請并使用完成的那部分內(nèi)存空間回收,供新申請使用。 垃圾回收機制都是針對堆區(qū)的內(nèi)存進行的。
系統(tǒng)在做垃圾回收時,不能夠處理任何用戶業(yè)務(wù)的。如果垃圾回收過于頻繁,導(dǎo)致系統(tǒng)業(yè)務(wù)處理能力下降。 由于 Full GC 內(nèi)存比較大,垃圾回收一次時間比較長,那么這段時間內(nèi)都不能處理業(yè)務(wù),對系統(tǒng)影響比較大,因此我們需要關(guān)注Full GC 頻率。

新程序執(zhí)行時需要先申請內(nèi)存空間,會先從年輕代中申請。 在年輕代滿了以后,就會進行垃圾回收Young GC。 回收時檢查年輕代中的內(nèi)存,是否還在使用。還在使用的部分會移存到生存區(qū) 2 中;不使用的部分則釋放,此時年輕代內(nèi)存空間被清空。 新程序執(zhí)行申請內(nèi)存空間,再從年輕代申請。 年輕代又滿了,就會進行垃圾回收Young GC。還在使用的內(nèi)存移存到生存區(qū) 1 中,并把生存區(qū) 2 中的內(nèi)存也都存到生存區(qū) 1 中。此時就會清空年輕代和生存區(qū) 2。 循環(huán)上述 1-5 步。 如果部分內(nèi)存在生存區(qū)中存活很久(內(nèi)存在生存區(qū)中移動了 10 次左右),則將這部分內(nèi)存放入到老年代中。 循環(huán)上述 1-7 步,直到老年代內(nèi)存空間全部占滿,此時就要進行垃圾回收Full GC。
作者 | Juno3550
來源 | cnblogs.com/juno3550/p/15212546.html

評論
圖片
表情
