PSI 지표 대시보드 구축기

TaekJun Jeong·2026년 8월 5일

Monitoring

목록 보기
2/2
post-thumbnail

자빅스와 그라파나, 앤서블을 사용해 PSI 대시보드를 구성하여 알림 룰까지 설정하는 문서입니다.


PSI 기반 메모리 관측 파이프라인 구축기 — Zabbix + Ansible + Grafana

들어가며

낭만인프라는 온프레미스 서버와 물리 SBC(라즈베리파이, LattePanda 등)가 섞인 이기종 fleet입니다.
여기에 PSI(Pressure Stall Information) 기반 메모리 관측 파이프라인을 붙인 과정을 정리했습니다.

기존 스택은 Zabbix(수집·저장) + Grafana(시각화·알림) 이고, 여기에 다음을 더했습니다.

  • PSI 수집: Zabbix agent 2 UserParameter로 /proc/pressure/memory 파싱
  • Fleet 배포: Ansible / AWX
  • 표준화: Zabbix Template
  • 시각화·알림: Grafana Dashboard + Alert Rule

왜 PSI였을까요?

전통적인 메모리 사용률 지표는 "얼마나 찼는가"만 알려줍니다.
하지만 리눅스에서 메모리 사용률이 높은 것은 대부분 page cache 때문이라 정상이고, 오히려 오탐의 원인이 됩니다.

PSI는 "리소스를 기다리느라 태스크가 정지한 시간의 비율(%)" 을 직접 측정합니다. 즉 사용률(utilization)이 아니라 압박(pressure) 을 봅니다.

핵심은 "사용률 90%"가 아니라 "지금 실제로 아픈가"를 보는 것입니다.
이 관점이 이 프로젝트 전체를 관통합니다.



아키텍처


1. 수집 — Zabbix agent 2 UserParameter

PSI는 Zabbix 기본 아이템이 없어서, UserParameter로 직접 수집하도록 만들었습니다. /proc/pressure/memory를 awk로 파싱하는 스크립트와 UserParameter 정의입니다.

# /usr/local/bin/psi_mem.sh
#!/bin/sh
# $1 = some|full,  $2 = avg10|avg60|avg300|total
awk -v line="$1" -v field="$2" \
  '$0 ~ "^"line {for(i=1;i<=NF;i++){split($i,a,"=");if(a[1]==field)print a[2]}}' \
  /proc/pressure/memory
# /etc/zabbix/zabbix_agent2.d/psi.conf
UserParameter=psi.memory[*], /usr/local/bin/psi_mem.sh "$1" "$2"

파라미터화([*]) 덕분에 some/full × avg10/avg60/avg300 6개 지표를 UserParameter 하나로 뽑을 수 있습니다.
먼저 한 호스트에서 검증했습니다.



2. 자동화 — Ansible / AWX

한 호스트에서 검증한 뒤, 전 fleet에 Ansible로 배포했습니다.

플레이북 설계

이기종 fleet를 안전하게 다루기 위해 세 가지를 신경 썼습니다.

  • stat 가드: /proc/pressure/memory(PSI)와 /etc/zabbix/zabbix_agent2.d(agent 2)가 모두 있는 호스트에만 배포합니다.
    없는 호스트(OPNsense, PSI 미지원 등)는 자동으로 건너뜁니다.
  • 멱등성: copy로 배포하고, 설정이 바뀔 때만 notify로 agent를 재시작합니다.
  • Check 모드 분리: not ansible_check_mode 조건으로, dry-run 시 검증 태스크는 건너뜁니다.
- name: PSI 메모리 수집 배포 (Zabbix Agent 2 UserParameter)
  hosts: all
  become: yes
  gather_facts: yes
  tasks:
    - name: PSI 지원 여부 확인
      ansible.builtin.stat: { path: /proc/pressure/memory }
      register: psi_stat
    - name: Zabbix agent 2 설치 여부 확인
      ansible.builtin.stat: { path: /etc/zabbix/zabbix_agent2.d }
      register: agent2_stat
    - name: 배포 대상 아님 알림 (건너뜀)
      ansible.builtin.debug:
        msg: "건너뜀: {{ inventory_hostname }} (PSI={{ psi_stat.stat.exists }}, agent2={{ agent2_stat.stat.exists }})"
      when: not (psi_stat.stat.exists and agent2_stat.stat.exists)
    # psi_mem.sh / psi.conf copy — when: psi_stat and agent2_stat
    # 검증 태스크 — when: ... and not ansible_check_mode
  handlers:
    - name: Zabbix Agent 2 재시작
      ansible.builtin.service: { name: zabbix-agent2, state: restarted }

AWX로 단계적 롤아웃

무작정 전체에 밀지 않았습니다. 검증된 그룹 → Check(dry-run) → Run → 다음 그룹 순으로 확장했습니다.

Check 모드로 대상/건너뛸 호스트와 변경 예정 사항을 먼저 확인한 뒤 실제 배포했습니다.

멱등성이 눈으로 확인되더라고요.

이미 수동으로 설정해 둔 호스트는 changed=1, 신규 호스트는 changed=3으로 나왔습니다.
이미 적용된 것은 다시 건드리지 않는다는 뜻입니다.



3. 표준화 — Zabbix Template

호스트마다 아이템을 따로 만들지 않고, 4개 아이템(full/some × avg60/avg300)을 담은 Template를 만들어 호스트 그룹에 링크했습니다.

  • Type of information: **Numeric (float)** — PSI 값은 0.00 같은 소수라, 정수형으로 두면 잘립니다.
  • 단위 %, 태그 component: memory



4. 시각화 — Grafana Dashboard

Memory Utilization 패널 바로 옆에 PSI 패널을 배치했습니다.
의도가 있었습니다.

사용률 vs 압박. 사용률이 높아도 PSI가 0이면 page cache로 찬 정상 상태이고, PSI가 오르는 순간이 실제로 "아픈" 순간입니다. 두 지표를 나란히 두면 이 차이가 한눈에 보입니다.

full avg60 기준으로, 평상시 0(초록)이고 압박 시 주황·빨강으로 변하도록 임계값을 구성했습니다.



5. 알림 — Grafana Alert Rule

full avg300 > 5% 조건으로 알림을 만들었습니다.
여기서도 기준은 사용률이 아니라 압박입니다.

  • Reduce(Last) + Threshold 표현식으로 구성 (B=Reduce, C=Threshold)
  • Pending 1m / Keep firing 2m — flapping(발동↔해제 반복) 방지
  • NoData 분기 — 수집이 끊겼을 때 오탐 방지 (기존 알림 운영 패턴 재사용)
  • Labels severity: warning, Annotations에 summary/description

알림 메시지에는 호스트·값·확인 항목을 넣었습니다.



6. 검증 — stress-ng

stress-ng로 실제 메모리 압박을 만들어 파이프라인 전 구간을 검증했습니다.

stress-ng --vm 1 --vm-bytes 3G --vm-keep --timeout 240s

RAM을 넘겨 swap까지 밀어붙이자 PSI가 상승했고, 대시보드 셀이 빨강으로 바뀌었으며, 임계값 초과로 Mattermost 알림이 발동했습니다.

압박이 풀린 뒤 복구 알림까지 확인했습니다.



트러블슈팅 — 겪으면서 배운 것들

구축하면서 마주친 함정들이, 오히려 이 시스템이 어떻게 동작하는지를 알려줬습니다.

문제원인대응
SBC 배포 건너뜀PSI는 있으나 agent 미설치Zabbix agent 2 선행 설치
Grafana 패널 NaN·깜빡임수집 초기 데이터 희소 + Last reduceLast *(non-null)로 변경
라벨이 아이템명으로 표시단일 호스트라 시리즈에 host 접두어 없음fleet 확장 시 자동 해결
Zabbix 아이템 NaN템플릿을 미배포 호스트에 링크배포 범위 = 모니터링 범위 원칙
알림 값이 [no value]classic condition은 값을 노출하지 않음Reduce+Threshold로 전환 → {{ $values.B.Value }}

관측 대상 범위와 수집기 배포 범위는 반드시 일치시켜야 합니다.

그리고 아키텍처·OS·에이전트 버전이 섞인 fleet에서는, 가드로 "준비되지 않은 호스트"를 걸러내는 것이 안전한 자동화의 핵심이라고 느꼈습니다.


마치며

  • 관측부터 알림까지 닫힌 파이프라인을, 이기종 fleet 위에 자동화로 표준 배포했습니다.
  • 단순히 "모니터링을 붙였다"가 아니라, 사용률이 아닌 압박(PSI) 을 지표·알림의 기준으로 삼아 오탐을 줄이는 관측 설계를 적용했습니다.

감사합니다.




정택준
Team: https://nangman.cloud/ko
E-mail: taekjunnnn@gmail.com

0개의 댓글