리눅스 서버에 대해서 제대로 된 관측을 위해서는 어떻게 동작하는지 이해해야 한다.
모던 리눅스 교과서를 읽으면서 간단하게 리눅스에 대해서 알아보았다.
만약 특정 서비스에 대해서 I/O가 밀린다면 어떤 부분을 분석해야 할까?
정확한 분석을 위해서는 해당 서비스가 어떻게 동작하는지, 어떤 리소스들을 사용하고 있는지를 이해해야 한다.
-> 커널부터 사용자영역까지의 스택에서 어떤 일이 일어나고 있는지를 알아야 한다.
프로젝트를 진행하면서 수많은 서버들이 통신하는데, 각 서버들이 어떻게 유기적으로 소통하는지를 몰라 장애 지점을 제대로 분석하지 못했던 경험이 있다.
이번 장에서 어떤 관측 전략들이 있는지 파악하고 특정 상황에서의 트레이싱 방법을 고민해보고자 한다.
[리눅스 성능 관측 도구]

관측가능성 전략
옵저빌리티에 대해 널리 확립된 전략 중 하나가 우다 루프(OODA 관찰-observe, 방향설정-orient, 결정-decide, 실행-act) 루프다.
이는 관측된 데이터를 기반으로 가설을 테스트하고 이에 따라 조치를 취하는 구조화된 방법, 시그널로부터 실행 가능한 통찰력을 얻는 방법을 제공한다.
예시로 애플리케이션이 느리다고 가정하면 느려진 원인으로 여러 후보 원인을 지목한다.
- 메모리 부족, CPU 주기 부족, 네트워크 I/O 부족
- 각 리소스가 얼마나 소비되는지부터 측정
- 각 리소스의 할당을 개별적으로 변경하고 결과를 측정해 본다.
앱에 더 많은 RAM을 제공했더니 성능이 향상됐는가? 그렇다면 이유를 찾은 것이다.
그렇지 않으면 다른 리소스를 연이어 사용해 보면서, 소비량을 측정하고 이를 그 상황에서 관측된 영향과 연결하려 항상 노력해야 한다.
용어 정리
관측가능성(옵저빌리티)
- 외부 정보를 측정하여 시스템(리눅스)의 내부 상태를 평가하는 것.
- 일반적으로는 후속 조치를 취한다.
예를 들어 시스템이 느리게 반응하는 것을 느껴 사용 가능한 주 메모리 양을 측정했다면, 특정 앱이 모든 메모리를 독차지하는 상황을 발견했을 수 있다.
- 이때 우리는 그 상황을 해결하기 위해 해당 앱을 종료하기로 결정할 수 있다.
소스
- 시그널을 생성하는 곳. 해당 시그널의 유형은 다양할 수 있다.
- 소스는 리눅스 운영체제일 수도, 애플리케이션일 수도 있다.
목적지
- 시그널을 소비, 저장, 추가적으로 처리하는 곳이다.
- GUI를 노출하는 목적지를 프런트엔드라고 한다.
- 예를 들어 로그 뷰어, 시계열을 표시하는 대시보드는 프런트엔드인 반면 S3 버킷은 아니다.
텔레메트리
- 소스에서 시그널을 추출하고 시그널을 목적지로 전송하는 프로세스로, 시그널을 수집 및 전처리하는 에이전트를 사용하는 경우가 많다.
시그널 유형
시그널은 추가 처리나 해석을 위해 시스템 상태를 전달하는 방법으로서, 크게 텍스트 페이로드와 숫자 페이로드로 구분한다.
살펴볼 시그널은 로그, 지표(메트릭), 추적(트레이스)이다.
로그
- 로그는 거의 모든 시스템이 생성하는 기본 시그널 유형
- 로그란 사람이 사용할 수 있는 텍스트 페이로드가 있는 개별 이벤트로서 일반적으로 이런 이벤트에는 타임스탬프가 지정된다.
- 로그는 메시지의 각 부분마다 명확한 의미가 정의되도록 구성하는 것이 이상적이다.
- 유효성 검사가 자동으로 수행될 수 있도록 형식 스키마를 통해 표현될 때가 많음
- 모든 로그가 일종의 구조를 지님에도 실무에서는 구조화된 로깅이라는 용어를 자주 듣는다.
- 로그가 JSON을 이용해 구성된다는 의미
지표(메트릭)
- 지표는 (대부분 정기적으로) 샘플링된 숫자 데이터 포인트로서, 시계열을 형성한다.
- 각각의 데이터 포인트는 차원이나 식별 메타데이터의 형태로 추가 콘텍스트를 가질 수 있다.
- 일반적으로는 원시(raw) 지표를 직접 사용하지 않는다.
- 대신 일종의 집계(aggregation)나 그래픽 표현을 사용하고, 특정 조건이 충족되면 알림을 받기도 한다.
- 지표는 운영 작업에도 유용하며, 앱이 완료한 트랜잭션 수나 특정 작업에 소요된 시간과 같은 질문에 답하기 위한 문제 해결에도 유용하다.
메트릭은 아래와 같이 다양한 유형으로 분류한다.
- 카운터 (올라가기만 함)
- 게이지 (올라가고 내려감)
- 히스토그램 (값의 분포를 보여줌)
추적(트레이스)
- 추적은 런타임 정보의 동적 모음으로서, 디버깅뿐만 아니라 성능 평가에도 자주 사용된다.
- 특정 원인에 대해 프로세스가 사용하는 시스템 콜에 대한 정보나 커널의 이벤트 시퀀스
로깅
로그란 사람이 사용하기에 최적화된 텍스트 페이로드가 있는 개별 이벤트다.
개별 이벤트
- 로그 항목을 사용해 코드에서 진행 중인 작업에 대한 정보를 공유하고 싶다고 가정.
- 예시: 데이터베이스 연결이 성공적으로 설정되었다는 로그행 출력
- 로그 메시지의 범위를 적고 구체적으로 유지하면 메시지를 사용하는 사람이 코드에서 해당 위치를 더 쉽게 찾을 수 있다.
텍스트 페이로드
- 로그 메시지의 페이로드는 텍스트고 기본 소비자는 사람이다.
- 커맨드라인에서 로그 뷰어를 사용하든 GUI가 있는 로그 처리 시스템을 사용하든, 사람이 로그 메시지의 내용을 읽고 해석하고 그에 따라 조치를 결정하는 것
구조적 관점에서 보면 전체적으로 로그는 다음과 같이 구성
- 로그 항목, 메시지, 행의 모음: 개별 이벤트에 대한 정보를 캡처
- 메타데이터, 콘텍스트: 전역범위뿐만 아니라 메시지 단위로도 존재할 수도 있다.
- 개별 로그 메시지를 해석하는 방법을 보여주는 형식: 로그의 부분과 의미를 정의. 공백으로 구분된 행 중심 메시지나 JSON 스키마를 예로 들 수 있다.
로그로 인한 오버헤드는 피하는 편이 좋다.
- logrotate를 이용한 로그 순환을 사용하는 경우가 있다.
- 데이터 온도라는 고급 개념도 유용할 수 있으며, 오래된 로그 파일을 더 저렴하고 느린 스토리지로 옮길 수도 있음
로그 항목의 중요성이나 의도된 대상 소비자를 알려주기 위해 대부분의 로그는 레벨을 정의해 둔다.
Syslog
Syslog는 커널부터 데몬, 사용자 공간까지 이르는 다양한 소스의 로깅 표준이다.
네트워크 환경에 근간을 두고 있으며 최근의 프로토콜은 배포 시나리오 및 보안 고려사항과 함께 RFC 5424에 정의된 텍스트 형식으로 구성된다.

systemd가 모든 주요 리눅스 배포판에서 사용되는 init 시스템의 사실상 표준이 되면서 로깅에 대한 새로운 방법이 나타났는데 그것이 바로 systemd 저널이다.
journalctl
systemd 에코시스템의 일부이며 로그 관리를 담당하는 구성 요소인 journalctl을 간략하게 다룬 적이 있다.
Syslog 등 지금까지 사용한 시스템들과 달리 journalctl은 바이너리 형식을 사용해 로그 항목을 저장한다.
이를 통해 더 빠르게 접근할 수 있으며 저장 공간도 더 많이 확보할 수 있다.
- 특정 서비스 데몬 로그 보기
- # journalctl -u sshd
모니터링
모니터링이란 다양한 이유로 시스템과 애플리케이션 지표를 캡처하는 것이다. 모니터링과 관련해 가장 자주 수행하게 될 두 가지 유형의 활동은 다음과 같다.
- 하나 이상의 지표 추적
- 조건에 근거한 알림
uptime, free -h, vmstat, iostat, ss, lsof, top 등을 사용해 모니터링 실습 진행

- 시스템 실행시간
- 접속한 사용자 수
- load average 섹션 (1분, 5분, 15분의 평균)
- 해당 평균값은 큐에 있거나 디스크 I/O를 기다리는 작업의 수

- 전체/사용/여유/공유 메모리 정보이며 buff/cache 영역이 1.2G이지만 언제든 반환할 수 있는 버퍼캐시영역은 available에 포함된다 (free + buff/cache(반환가능한))

- r은 실행 중이거나 CPU를 기다리는 프로세스 수 (보유한 CPU보다 작거나 같아야 함)
- in은 초당 인터럽트 수, cs는 초당 콘텍스트 스위칭 수 us는 사용자 공간, sy는 커널, id는 유휴, wa는 cpu가 활성상태임에도 불구하고 wait 한 시간, st는 CPU를 사용할 수 없었던 시간 (CPU 사용 시간 중 30%가 다른 VM 또는 호스트의 작업에 사용)

- 특정 작업에 걸리는 시간

- I/O 디바이스 지표 (-z 옵션은 활동이 있는 디바이스만 출력)

- 소켓을 확인 -a (모든) -t(TCP) -u (UDP) -p(Process ID)
- Recv-Queue와 Send-Q가 0이면 유휴상태임을 의미

- TCP포트를 나열
- -p {PID} 옵션을 사용하면 해당 프로세스가 열고 있는 파일을 나열

- 프로세스 별 세부 정보를 포함한 동적 프로세스 목록
- CPU 사용량 통계 등..
eBPF(Extended Berkeley Packet Filter)
리눅스 커널의 확장된 기능으로, 프로세스나 네트워크의 동작을 관찰하거나 조작할 수 있는 고성능, 유연한 실행 환경
네트워크 패킷 처리를 위해 만들어졌지만, 현재는 보안, 성능 모니터링, 디버깅 등 다양한 분야에서 활용
커널영역에 코드를 삽입하여 특정 이벤트를 감지할 수 있음


파이썬을 사용 하여 eBPF 코드를 삽입하여 이벤트 탐지
from bcc import BPF
# eBPF 프로그램 정의
bpf_program = """
#include <linux/sched.h>
int hello_world(void *ctx) {
char comm[16];
bpf_get_current_comm(&comm, sizeof(comm));
bpf_trace_printk("안녕하세요! 프로세스: %s\\\\\\\\n", comm);
return 0;
}
"""
# BPF 객체 생성 및 프로그램 로드
b = BPF(text=bpf_program)
# sys_clone 시스템 콜에 kprobe 연결
b.attach_kprobe(event="__x64_sys_clone", fn_name="hello_world")
# 출력 표시
print("sys_clone 호출 추적 중... 종료하려면 Ctrl+C를 누르세요")
b.trace_print()
고급 주제
- eBPF 맵: eBPF 프로그램은 커널과 사용자 공간 간에 데이터를 공유하기 위해 맵을 사용할 수 있습니다. eBPF 맵을 사용하여 시스템 호출을 카운트하는 프로그램을 구현해 보세요.
- XDP(eXpress Data Path): 네트워크 드라이버 수준에서 고성능 패킷 처리를 위한 XDP를 탐험해 보세요.
- 보안을 위한 eBPF: 시스템 호출을 모니터링하는 간단한 침입 탐지 시스템을 eBPF를 사용하여 구현해 보세요.
- 사용자 공간 프로그램 추적: uprobes를 사용하여 사용자 공간 애플리케이션의 함수를 추적해 보세요.
- 트레이스포인트와 eBPF: kprobes와 비교하여 더 안정적인 계측 지점을 위해 트레이스포인트 사용을 탐험해 보세요.
- eBPF와 컨테이너: Docker 컨테이너 내부의 프로세스를 모니터링하는 eBPF 프로그램을 개발해 보세요.
- 네트워크 성능 모니터링: TCP 연결의 지연 시간과 처리량을 모니터링하는 eBPF 프로그램을 만들어 보세요.
- 커널 함수 후킹: 특정 커널 함수의 동작을 수정하는 eBPF 프로그램을 작성해 보세요.
-> 자주 발생하는 문제로 네트워크, 메모리, CPU, 디스크 I/O를 확인해야 할 때 활용해 볼 방법이 있을지..
커널에 코드를 삽입하여 이벤트를 모니터링하여 프로파일링 하기.
References
eBPF 프로그램 테스트를 위한 리눅스 가상 환경 설정 가이드
eBPF 프로그램 테스트를 위한 리눅스 가상 환경 설정 가이드
medium.com
eBPF가 우리가 알고 있는 관찰 가능성을 어떻게 변화시키는가
eBPF가 우리가 알고 있는 관찰 가능성을 어떻게 변화시키는가 🕵️♀️🐝 | HackerNoon
eBPF를 살펴보겠습니다. 기술은 무엇입니까? 관측 가능성에 어떤 영향을 미치며 기존 관측 가능성 관행과 어떻게 비교됩니까?
hackernoon.com
'Study' 카테고리의 다른 글
[리눅스마스터 1급] 리눅스 시스템의 이해 오답 [2] (0) | 2025.02.01 |
---|---|
[리눅스마스터 1급] 리눅스 시스템의 이해 오답 [1] (0) | 2025.01.30 |
[Linux] 모던 리눅스 교과서 6장 - 애플리케이션, 패키지관리,컨테이너 (1) | 2024.12.15 |
[Linux] 모던 리눅스 교과서 5장 - 파일시스템 (0) | 2024.12.01 |
[Linux] 모던 리눅스 교과서 4장 - 접근제어 (0) | 2024.11.24 |