PSI——壓力阻塞信息
當CPU、memory或IO設備處于競爭狀態,業務負載會遭受時延毛刺、吞吐量降低,
及面臨OOM的風險。
如果沒有一種準確的方法度量系統競爭程度,則有兩種后果:一種是用戶過于節制,
未充分利用系統資源;另一種是過度使用,經常性面臨業務中斷的風險。
psi特性能夠識別和量化資源競爭導致的業務中斷,及其對復雜負載乃至整個系統在
時間上的影響。
準確度量因資源不足造成的生產力損失,有助于用戶基于硬件調整業務負載,或基
于業務負載配置硬件。
psi能夠實時的提供相關信息,因此系統可基于psi實現動態的負載管理。如實施
卸載、遷移、策略性的停止或殺死低優先級或可重啟的批處理任務。
psi幫助用戶實現硬件資源利用率的最大化。同時無需犧牲業務負載健康度,也無需
面臨OOM等造成業務中斷的風險。
壓力接口
壓力信息可通過/proc/pressure/ --cpu、memory、io文件分別獲取。
CPU相關信息格式如下:
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
內存和IO相關信息如下:
some avg10=0.00 avg60=0.00 avg300=0.00 total=0full avg10=0.00 avg60=0.00 avg300=0.00 total=0
some行代表至少有一個任務阻塞于特定資源的時間占比。
full行代表所有非idle任務同時阻塞于特定資源的時間占比。在這種狀態下CPU資源
完全被浪費,相對于正常運行,業務負載由于耗費更多時間等待而受到嚴重影響。
由于此情況嚴重影響系統性能,因此清楚的識別本情況并與some行所代表的情況區分開,
將有助于分析及提升系統性能。這就是full獨立于some行的原因。
avg代表阻塞時間占比(百分比),為最近10秒、60秒、300秒內的均值。這樣我們
既可觀察到短期事件的影響,也可看到中等及長時間內的趨勢。total代表總阻塞
時間(單位微秒),可用于觀察時延毛刺,這種毛刺可能在均值中無法體現。
監控壓力門限
用戶可注冊觸發器,通過poll()監控資源壓力是否超過門限。
觸發器定義:指定時間窗口期內累積阻塞時間的最大值。比如可定義500ms內積累
100ms阻塞,即觸發一次喚醒事件。
觸發器注冊方法:用戶打開代表特定資源的psi接口文件,寫入門限、時間窗口的值。
所打開的文件描述符用于等待事件,可使用select()、poll()、epoll()。
寫入信息的格式如下:
<some|full> <stall amount in us> <time window in us>
示例:向/proc/pressure/memory寫入"some 150000 1000000"將新增觸發器,將在
1秒內至少一個任務阻塞于內存的總時間超過150ms時觸發。向/proc/pressure/io寫入
"full 50000 1000000"將新增觸發器,將在1秒內所有任務都阻塞于io的總時間超過50ms時觸發。
觸發器可針對多個psi度量值設置,同一個psi度量值可設置多個觸發器。每個觸發器需要
單獨的文件描述符用于輪詢,以區分于其他觸發器。所以即使對于同一個psi接口文件,
每個觸發器也需要單獨的調用open()。
監控器在被監控資源進入阻塞狀態時啟動,在系統退出阻塞狀態后停用。系統進入阻塞
狀態后,監控psi增長的頻率為每監控窗口刷新10次。
內核接受的窗口為500ms10s,所以監控間隔為50ms1s。設置窗口下限目的是為了
防止過于頻繁的輪詢。設置窗口上限的目的是因為窗口過長則無意義,此時查看
psi接口提供的均值即可。
監控器在激活后,至少在跟蹤窗口期間將保持活動狀態。以避免隨著系統進入和退出
阻塞狀態,監控器過于頻繁的進入和退出活動狀態。
用戶態通知在監控窗口內會受到速率限制。當對應的文件描述符關閉,觸發器會自動注銷。
用戶態監控器使用示例
::
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
/* 監控內存部分阻塞,監控時間窗口為1秒、阻塞門限為150毫秒。*/
int main() {
const char trig[] = “some 150000 1000000”;
struct pollfd fds;
int n;
fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);if (fds.fd < 0) {printf("/proc/pressure/memory open error: %s\n",strerror(errno));return 1;}fds.events = POLLPRI;if (write(fds.fd, trig, strlen(trig) + 1) < 0) {printf("/proc/pressure/memory write error: %s\n",strerror(errno));return 1;}printf("waiting for events...\n");while (1) {n = poll(&fds, 1, -1);if (n < 0) {printf("poll error: %s\n", strerror(errno));return 1;}if (fds.revents & POLLERR) {printf("got POLLERR, event source is gone\n");return 0;}if (fds.revents & POLLPRI) {printf("event triggered!\n");} else {printf("unknown event received: 0x%x\n", fds.revents);return 1;}}return 0;
}
Cgroup2接口
對于CONFIG_CGROUP=y及掛載了cgroup2文件系統的系統,能夠獲取cgroups內任務的psi。
此場景下cgroupfs掛載點的子目錄包含cpu.pressure、memory.pressure、io.pressure文件,
內容格式與/proc/pressure/下的文件相同。
可設置基于cgroup的psi監控器,方法與系統級psi監控器相同。