CPU使用率高的問題
問題描述
操作系統的CPU頻繁達到70%或以上,操作系統響應慢或無響應,導致數據庫運行異常,如活躍連接數增加,大量SQL處理active或Lock狀態,SQL執行變慢或長時間執行中。
可能影響
- 操作系統響應慢或無響應;
- 數據庫運行異常,如活躍連接數增加,大量SQL處理active或Lock狀態,SQL執行變慢或長時間執行中。
解決步驟
- 操作系統層面檢查cpu使用情況,如執行top命令,觀察CPU整體情況;
- %Cpu(s): ?0.8 us, ?0.8 sy, ?0.0 ni, 98.1 id, ?0.3 wa, ?0.0 hi, ?0.0 si, ?0.0 st
- CPU屬性值說明:
- %user:CPU處在用戶模式下的時間百分比。
- %nice:CPU處在帶NICE值的用戶模式下的時間百分比。
- %system:CPU處在系統模式下的時間百分比。
- %iowait:CPU等待輸入輸出完成時間的百分比。
- %steal:管理程序維護另一個虛擬處理器時,虛擬CPU的無意識等待時間百分比。
- %idle:CPU空閑時間百分比。
?
說明如果%iowait的值過高,表示硬盤存在I/O瓶頸,%idle值高,表示CPU較空閑,如果%idle值高但系統響應慢時,有可能是CPU等待分配內存,此時應加大內存容量。%idle值如果持續低于10,那么系統的CPU處理能力相對較低,表明系統中最需要解決的資源是CPU。
您也可以使用perf,通過sudo perf top -s comm,可以查看當前系統運行進程占比。
這里不像top一樣區分idle、system、user,這里的占比是各個進程在總運行時間里面占比。
通過sudo perf record記錄采樣信息,然后通過sudo perf report -s comm。
通過perf 可以從總體上查看CPU使用占比,結合數據庫源碼分析問題瓶頸。
- 如上一步驟中,top查看到的都是postgres的進程,那么可以確定是由數據庫引起的cpu問題,如果是其它進程,則需要確認進程對應的具體應用,另做分析,此處不再展示;
- 對于由于大量postgres進程占用CPU導致的問題,可以通過postgres進程的pid找到對應哪個實例節點,進一步連接節點,通過查詢會話表,查看運行的SQL情況。
如,查詢運行時長超過10秒的SQL:
SELECT now() - query_start as "runtime", usename,application_name, client_hostname, datname, state, query
FROM pg_stat_activity
WHERE now() - query_start > '10 seconds'::interval and state!='idle'
ORDER BY runtime DESC;
查詢花費時間最多的SQL TOP10:
SELECT round(total_time*1000)/1000 AS total_time,query
FROM pg_stat_statements
ORDER BY total_time DESC limit 10;
查看鎖阻塞情況:
select pid, usename, pg_blocking_pids(pid) as blocked_by, query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
根據收集到慢SQL或阻塞會話,進一步進行分析優化,通常策略有
1)優化SQL語句,尤其是并發量大、高頻的SQL語句,通常通過創建索引減少大表全表掃描,改寫SQL關聯邏輯等方式優化;
2)根據業務需要,評估是否可降低并發量;
3)根據瓶頸,橫向擴容節點組,調大節點資源配置;
4)提高硬件配置,提升CPU、磁盤性能;
磁盤空間使用率問題
問題描述
磁盤空間占用率高,觸發告警,或磁盤空間使用100%,導致數據庫運行出錯。
可能影響
- 磁盤空間使用率達到100%,會導致數據庫運行可能出現異常,新寫入或更新文件被置空,數據庫無法啟動;
- SQL執行報錯。
解決步驟
- 執行以下命令檢查磁盤空間占用情況
df -h ?查看磁盤空間占用,實際上是查看磁盤塊占用的文件(block)
df -ih ?查看索引節點的占用(Inodes)
磁盤塊和索引節點其中之一滿,都會導致無法創建文件,提示磁盤空間已滿。
所以請注意,查看磁盤還有空間,但是創建文件提示空間滿,可能是inodes節點已滿。
- 磁盤空間滿/過高的問題,可以進入問題目錄,執行du -sh * | sort -h命令逐層目錄檢查,找到占用空間高的目錄和文件,根據需要進行清理;
結合find / -size +100M |xargs ls -lh命令,查找系統中內大于100M的文件,根據需要進行清理;
- 索引節點滿/過高的問題,可以進入問題目錄,執行 find */ ! -type l | cut -d / -f 1 | uniq -c 逐層找出文件最多目錄,定位出哪個目錄占用inodes最多(通常inodes是因為小文件太多);
- TeleDB數據庫常見磁盤占用空間滿/過高的問題及解決辦法:
1)xlog(wal)日志積壓過多
解決辦法:可以參照本文中xlog堆積類問題處理;
2)大量更新導致WAL日志快速增長,日志歸檔速度低于增長速率,導致積壓;
解決辦法:
a、分析寫入/更新邏輯,排查WAL日志寫入占比,通過優化寫入/更新邏輯,降低WAL日志寫入量;
b、操作系統CPU充足的情況下,可設置WAL日志壓縮策略
c、提升日志歸檔速度,如批量提交,提高并發等;
3)查詢操作含有大數據量的排序、連接等操作,處理過程中產生臨時表并溢出到磁盤,短時間內造成大量空間占用;
解決辦法:
a、檢查SQL關聯邏輯是否錯誤導致的數據量暴增,優化SQL寫法;
b、避免大數據量的排序操作;
c、針對SQL語句會話級調大參數work_mem,減少或規避臨時表溢出到磁盤問題;
d、通過設置參數temp_file_limit來限制SQL語句用于指定每個查詢可以使用的臨時表空間上限(單位為KB),單個查詢生成的臨時表空間達到上限就會報錯;
4)數據庫觸發異常,產生大量core文件;
解決辦法:保留最近幾個完整的core文件,聯系TeleDB運維工程師分析,通常可通過改寫SQL等方式暫時規避,或升級版本解決。
磁盤I/O使用率高的問題
問題描述
磁盤I/O使用率高或100%。
可能原因
- SQL執行慢或無響應;
- 數據庫運行異常。
解決步驟
- 可以通過iostat命令查看磁盤IO情況,重點關注until和svctm這兩個值
- svctm:The average service time (in milliseconds) for I/O requests that were issued to the device. Warning! Do not trust this field any more. ?This field will be removed in a future sysstat version.
- %util:Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%.
執行命令:
iostat -x -k -d 1
返回結果示例:

其中每列說明如下:
- rrqm/s: 每秒進行 merge 的讀操作數目。即 rmerge/s
- wrqm/s: 每秒進行 merge 的寫操作數目。即 wmerge/s
- r/s: 每秒完成的讀 I/O 設備次數。即 rio/s
- w/s: 每秒完成的寫 I/O 設備次數。即 wio/s
- rkB/s: 每秒讀K字節數。是 rsect/s 的一半,因為每扇區大小為512字節。
- wkB/s: 每秒寫K字節數。是 wsect/s 的一半。
- avgrq-sz: 平均每次設備I/O操作的數據大小 (扇區)。
- avgqu-sz: 平均I/O隊列長度。
- rsec/s: 每秒讀扇區數。即 rsect/s
- wsec/s: 每秒寫扇區數。即 wsect/s
- r_await:每個讀操作平均所需的時間,不僅包括硬盤設備讀操作的時間,還包括了在kernel隊列中等待的時間。
- w_await:每個寫操作平均所需的時間,不僅包括硬盤設備寫操作的時間,還包括了在kernel隊列中等待的時間。
- await: 平均每次設備I/O操作的等待時間 (毫秒)。
- svctm: 平均每次設備I/O操作的服務時間 (毫秒)。
- %util: 一秒中有百分之多少的時間用于 I/O 操作,即被io消耗的cpu百分比
返回結果分析:
如果 svctm 比較接近 await,說明 I/O 幾乎沒有等待時間;如果 await 遠大于 svctm,說明I/O 隊列太長,io響應太慢,則需要進行必要優化。如果avgqu-sz比較大,也表示有大量io在等待。
注意iostat 中的 %util 基本已經沒有任何作用了,svctm也沒什么參考意義,%util表示該設備有I/O(即非空閑)的時間比率,不考慮I/O有多少,只考慮有沒有。
由于現代硬盤設備都有并行處理多個I/O請求的能力,所以%util即使達到100%也不意味著設備飽和了。
舉個簡化的例子:某硬盤處理單個I/O需要0.1秒,有能力同時處理10個I/O請求,那么當10個I/O請求依次順序提交的時候,需要1秒才能全部完成,在1秒的采樣周期里%util達到100%;而如果10個I/O請求一次性提交的話,0.1秒就全部完成,在1秒的采樣周期里%util只有10%。可見,即使%util高達100%,硬盤也仍然有可能還有余力處理更多的I/O請求,即沒有達到飽和狀態。
- 可以通過nmon工具分析,具體參見//nmon.sourceforge.io/pmwiki.php
nmon返回結果中,關注Disk I/O中 Busy列判斷磁盤是否達到飽和狀態;
- 或者通過dstat、sar來查看磁盤I/O情況
- TeleDB數據庫常見磁盤I/O使用率高的問題及解決辦法:
1)大批量寫入/更新操作,占用大量磁盤I/O;
解決辦法:
a、分析寫入/更新邏輯,排查WAL日志寫入占比,通過優化寫入/更新邏輯,降低WAL日志寫入量;
b、操作系統CPU充足的情況下,可設置WAL日志壓縮策略;
2)高并發SQL語句執行效率低,產生大量I/O,導致磁盤I/O、CPU升高;
解決辦法:優化SQL語句,尤其是并發量大、高頻的SQL語句,通常通過創建索引減少大表全表掃描,改寫SQL關聯邏輯等方式優化;
3)磁盤性能不足
解決辦法:不使用HDD機械盤,推薦使用NVMe SSD盤,并做raid,提升磁盤性能;
4)shard_buffer、操作系統內存不足,導致頻繁的磁盤I/O;
解決辦法:操作系統應該保持充足的內存,有更多可用緩存(shard_buffer、操作系統cache),同時調整相關參數,適當拉長checkpoint頻率,減少磁盤I/O。
內存不足問題
問題描述
操作系統內存不足,導致數據庫運行異常。
可能影響
- 可能會導致執行的SQL因申請不到內存報錯;
- 可能會導致新建連接無法建立;
- 可能會導致操作系統主動KILL掉數據庫進程,導致數據庫異常重啟。
解決步驟
- 執行shell命令 free -h,查看內存整體使用情況
free命令輸出結果示例:
total used free shared buff/cache available
Mem: 14G 2.3G 195M 5.7G 12G 6.6G
Swap: 0B 0B 0B
Linux操作系統的內存主要看內存大小,剩余內存是否足夠。在Linux中經常發現空閑內存很少,似乎所有的內存都被系統占用了,表面感覺是內存不夠用了:Linux系統默認的設置傾向于把內存盡可能的用于文件cache,所以在一臺大內存機器上,往往我們可能發現沒有多少剩余內存。
對于操作系統,free命令顯示出的空閑內存,應該更多關注-/+ buffers/cache: 這表明了你的系統可能還剩余的空閑內存。對于應用程序來說,buffers/cached占有的內存是可用的,因為buffers/cached是為了提高文件讀取的性能,當應用程序需要用到內存的時候,buffers/cached會很快地被回收,以供應用程序使用。
同時,我們應關注是否用到了swap,當前服務器內存配置足夠,通常在數據庫服務器上需要關閉swap使用,避免因使用到swap導致性能下降。
- 通過top -o %MEM查看內存使用情況,及內存使用排名TOP的進程
top命令輸出結果示例:

這里是按%MEM內存使用TOP排名的結果,可以查看對應的命令和進程ID,進一步分析原因,并進行針對性優化。
- 或者,通過ps aux|sort -rnk 4|head -5 查看內存使用排名TOP5的進程
ps aux命令輸出結果示例:

- TeleDB數據庫常見內存不足問題及解決辦法:
1)非數據庫進程占用較大內存,如已知的在多個項目中遇到麒麟V10系統auditd服務占用大量內存問題,導致數據庫實例運行異常
解決辦法:
a、麒麟V10系統已有補丁,可聯系麒麟廠商升級補丁解決;
b、在更新操作系統補丁前,需要關閉操作系統的auditd服務,并設置為服務不自動啟動。如有安全要求,不能關閉audited服務,則必須有方案來定期重啟auditd服務。
a)關閉audited服務方法:
用root用戶執行以下命令來關閉auditd服務:
systemctl stop auditd
systemctl disable auditd
b)或者root用戶下配置定時任務來自動重啟auditd服務,例如,每天凌晨1點重啟:
crontab -e
0 1 * * * systemctl restart auditd > /dev/null 2>&1 &
需要確保root用戶可重啟auditd服務,驗證定時任務已生效。
如重啟服務有如下提示:
Failed to restart auditd.service: Operation refused, unit auditd.service may be requested by dependency only (it is configured to refuse manual start/stop).
See system logs and 'systemctl status auditd.service' for details.
可通過注釋/usr/lib/systemd/system/auditd.service文件中RefuseManualStop=yes,然后執行 systemctl daemon-reload 重新加載生效。
2)分區表過多,分區的catalog cache占用大量內存,特別需要注意并不是explain里面已經裁減了就代表relcache也裁剪了;
解決辦法:
a、控制分區表使用數量,表分區的目的主要拆分大表,降低維護成本,TeleDB分布式數據庫,可通過多組DN節點,達到同樣的目的,在部分情況下可以不使用分區表,或者減少分區數量;
b、分區表的SQL語句應該盡量使用分布鍵+分區鍵條件,盡量縮減訪問范圍,避免因未使用分布式鍵、未使用分區鍵導致的SQL重分布問題、讀取全部分區的問題;
3)業務使用了大量長連接, 并且沒有設置連接的生命周期, 或者生命周期很長. 連接時間越長, 訪問的元數據積累越多, 導致每個會話的私有內存較大。
解決辦法:
a、降低應用到數據庫的總連接數, 并且設置連接的生命周期(例如, 一個連接最多使用15分鐘后自動釋放);
b、業務側做好連接管理,通過連接池限制連接數上限;
c、數據庫層面做好連接管理,定期清理空閑連接、長時間未執行結束的SQL;
4)設置了較大的work_mem或hash_mem_multiplier, 并且有大量SQL使用了hash agg或hash join, 導致內存消耗過多;
解決辦法:調小work_mem或hash_mem_multiplier. 業務層減少此類請求的并發量。此類SQL使用PG HINT把hash agg\hash join改成group agg或merge join等。
5)數據庫有性能問題, 高峰期引起了雪崩, 并且應用程序配置的連接池上限較大, 導致向數據庫請求了大量連接, 最終耗費大量內存引起OOM;
解決辦法:
a、降低應用到數據庫的總連接數, 并且設置連接的生命周期(例如一個連接最多使用15分鐘后自動釋放);
b、設置數據庫或USER的connection limit, 限制用戶或數據庫級別的連接數上限;
c、收集SQL并分析優化。
6)業務量未預期突增,服務器內存規劃不足
解決辦法:調整部署策略,如:
a、更換配置更高的服務器,提供更多的內存;
b、提供更多的服務器,將CN、DN節點擴容或調整到更多服務器上,降低單臺服務器負載;
c、可能原規劃單能服務器上有主、備節點混部情況,在發生切換時,有服務器上存在多個主節點,主節點有業務流入,需要更多的內存,導致高峰期內存不足;建議重新規劃部署,充分考慮此類情況下的服務器資源使用情況;
7)開啟資源隔離,實例節點分配內存資源預估不足,導致OOM
解決辦法:優先嘗試優化;在資源需求充分評估后,擴容實例資源;
8)操作系統內存相關參數配置不合理,導致操作系統內存無法充分利用
解決辦法:原因可能是vm.overcommit_memory配置為2,同時overcommit_ratio配置較小,導致操作系統有足夠的內存,但無法使用;
例如:
sysctl -a | grep -i vm.overcommit_memory 看到為2,也就是關閉了overcommmit
overcommit_ratio 配置為50%,這樣只能用系統一半的內存
通常推薦不要關閉overcommit,vm.overcommit_memory應配置為0。
操作系統負載過高問題
問題描述
操作系統負載較平時升高,操作系統層面的shell命令響應變慢或無響應。
可能影響
- 平時正常的SQL語句,出現執行慢或一直處理執行中的現象,導致業務受影響;
- 操作系統響應慢,可能導致節點狀態監測失敗,觸發告警;
- 可能導致節點狀態監測失敗,觸發主備自動切換。
解決步驟
- 可以通過shell命令top、htop、w、uptime等命令查看負載情況。
關于負載的理解:
理想情況下,每個CPU 應該滿負荷工作,并且沒有等待進程,此時,平均負載 = CPU 邏輯核數。
但是,在實際生產系統中,不建議系統滿負荷運行。通用的經驗法則是:平均負載= 0.7 * CPU 邏輯核數。
1.當平均負載持續大于 0.7 * CPU 邏輯核數,就需要開始調查原因,防止系統惡化;
2.當平均負載持續大于 1.0 * CPU 邏輯核數,必須尋找解決辦法,降低平均負載;
3.當平均負載持續大于 5.0 * CPU 邏輯核數,表明系統已出現嚴重問題,長時間未響應,或者接近死機。
除了關注平均負載值本身,我們也應關注平均負載的變化趨勢,這包含兩層含義。一是load1、load5、load15 之間的變化趨勢;二是歷史的變化趨勢。
當load1、load5、load15 三個值非常接近,表明短期內系統負載比較平穩。此時,應該將其與昨天或上周同時段的歷史負載進行比對,觀察是否有顯著上升。
當load1 遠小于 load5 或 load15 時,表明系統最近 1 分鐘的負載在降低,而過去 5 分鐘或 15 分鐘的平均負載卻很高。
當load1 遠大于 load5 或 load15 時,表明系統負載在急劇升高,如果不是臨時性抖動,而是持續升高,特別是當 load5 都已超過 0.7 * CPU 邏輯核數 時,應調查原因,降低系統負載。
CPU 使用率是單位時間內 CPU 繁忙程度的統計。而平均負載不僅包括正在使用 CPU 的進程,還包括等待 CPU 或 I/O 的進程。因此,兩者不能等同,有兩種常見的場景如下所述:
CPU 密集型應用,大量進程在等待或使用 CPU,此時 CPU 使用率與平均負載呈正相關狀態。
I/O 密集型應用,大量進程在等待 I/O,此時平均負載會升高,但 CPU 使用率不一定很高。
- TeleDB數據庫常見操作系統負載高的問題及解決辦法:
評估負載是否符合預期,業務SQL是否有明顯的響應變慢,是否對業務造成影響,是否可控;根據評估結果,如需進行調整,通常調整策略有:
1)針對CPU密集型應用,此時CPU是瓶頸,表現為CPU 100%或接近100%
解決辦法:以減少CPU或提升總CPU數據為主入手
a、抓取消耗CPU的高頻高并發SQL,進行優化;
b、擴容節點組,將業務分散到更多的服務器上,使用更多的CPU資源;
a、高CPU資源的批量業務錯峰執行,避免多個任務互相影響;
c、控制業務并發度。
2)針對I/O密集型應用,此時磁盤I/O是瓶頸,表現為磁盤I/O使用率100%或接近100%
解決辦法:
a、以減少I/O操作為主入手
b、如優化業務邏輯,以COPY批量導入方式代替單行insert;
c、優化SQL語句,盡量避免大表全表掃描情況;
d、擴容節點組,將業務分散到更多的服務器上;
e、提高磁盤IO性能,更換更好的磁盤;
f、高I/O的批量業務錯峰執行,避免多個任務互相影響;
g、降低高I/O的任務的并發度。
3)可能因為服務器內存不足,操作系統響應變慢引起的高負載
解決辦法:參考內存不足問題處理。
網絡問題
問題描述
實例節點之間、應用與CN節點之前出現網絡延遲、擁塞、丟包等問題。
可能影響
- 應用連接CN節點失敗;
- 執行SQL失敗;
- 節點通信異常,導致觸發主備節點自動切換;
- 主備復制可能會因網絡丟包導致失敗。
解決步驟
- 網絡狀況,可以使用ifstat或dstat查看,示例:
iftop、nmon也可以查看網絡狀態
- 針對包延遲、丟包的場景,可以使用ping、traceroute以及tcpdump抓包的方式進一步分析,此處不展開討論;
- TeleDB數據庫常見網絡問題及解決辦法:
1)網絡帶寬存在瓶頸
在性能壓測、業務高峰期等場景,可能出現服務器的網絡帶寬被打滿的情況。
解決辦法:
a、分布式數據庫在SQL執行時,CN、DN節點之間通信和數據交互需要消耗較多的網絡資源,對帶寬有較高的要求,在部署規劃前期,應該確保集群內服務器網絡是萬兆帶寬;
b、定期抓取消耗資源高的SQL語句,尤其多表關聯的復雜SQL,返回結果集大SQL,進行優化,目標拆分簡化復雜SQL寫法,減少SQL重分布;針對返回結果集大的SQL,檢查SQL邏輯,減少和去除不必要的排序操作,減少不必要的返回數據列。
2)節點之間有網絡斷開、丟包情況
綜合服務器連接數情況,服務器負載情況,分析評估是否因業務量過大,服務器配置不足導致的服務器響應慢或無響應,從而導致節點間出現網絡異常斷開、丟包情況;
解決辦法:
a、優先優化解決業務量中高頻且效率不高的SQL;
b、避免后續此類問題出現,應該把控好新上線業務的SQL質量;
c、數據庫服務器資源做適當預留,應充分考慮業務業務高峰期的資源使用情況,根據評估需要,橫向或縱向擴容數據庫;
d、也有其它原因可能導致節點之間網絡斷開,如服務器資源不足,操作系統主動kill數據庫進程;或人力kill會話;觸發異常導致節點crash并重啟。這些異常需要聯系運維工程師進一步分析處理。