재형이의 성장통 일지
  • 리눅스 시스템 성능 분석
    2024년 02월 04일 18시 46분 03초에 업로드 된 글입니다.
    작성자: 재형이
    반응형
    • 쿠버네티스 환경을 운영하거나 서버를 운영할 때, 가장 많이 사용하는 운영체제가 리눅스이기 때문에 성능을 분석할 줄 알고 문제가 발생했을 때 빠르게 대처하는 것이 중요하다고 생각합니다.
    • 그리고 클라우드를 사용한다고 하더라도 호스트 환경의 장애나 노이지 네이버 등의 이슈들로 여전히 하드웨어 자원에 대한 분석이 필요합니다.
    • 그래서 이번에는 리눅스 성능을 분석하고 최적화하는 방법에 대해서 정리를 해보겠습니다.

     

     

    BPF 기반 리눅스 성능 분석

    이전에 리눅스 성능 분석을 포스팅하면서 나왔던 eBPF에 대해서 정리하려고 한다 1. eBPF란? BPF란 The BSD Packet Filter: A New Architecture for User-level Packet Capture1993, Usenix라는 논문이다 기존 네트워크 모니

    jaehyeong.tistory.com

     

     


     

     

    1. 성능 분석 방법론

    1-1. USE (Utilization Saturation Error) 방법론

    • 모든 자원에 대해, 사용률/포화도/오류를 확인
    • 인프라 레벨의 성능 분석에 적합
      • Utilization (사용률)
        • 자원을 바쁘게 사용한 시간
          ex) CPU 하나가 90% 사용률로 동작
      • Saturation (포화도)
        • 처리되지 못한 자원이 있는 수준 (대기 큐의 길이로 확인)
          ex) CPU의 대기열의 평균 길이가 4
      • Errors (오류)
        • 발생한 오류의 횟수
          ex) 디스크 컨트롤러에서 오류가 발생

    1-2. RED (request Rate, request Error, request Duration) 방법론 + Saturation

    • USE 방법론은 서비스 단위로는 맞지 않음
    • 분산, MSA 환경에 맞는 방법론
    • 해당 지표들을 기반으로 alert 생성 및 대시보드 생성
      • request Rate (사용률)
        • 처리하고 있는 초당 요청의 개수
      • request Errors (오류)
        • 초당 요청이 실패한 개수
      • request Duration (지속시간)
        • 요청을 처리하는데 걸린 시간
      • + Saturation (포화상태)
        • 요청을 처리하지 못하고 대기하는 상태
        • 클라우드 환경에서는 모든 자원에 제한이 있음

    AWS CloudWatch

    1-3. 과학적 접근 방법

    • 가설을 수립하고 검증하면서 분석
    • 질문 → 가설 → 예측 → 테스트 → 분석
    • ex) 질문: 데이터베이스의 질의를 느리게 만드는 원인은?
      • 가설: 파일시스템 I/O의 성능이 문제?
      • 예측: 파일 시스템 I/O의 지연시간을 질의 중간에 측정해 본다면,
        느린 파일 시스템이 질의 속도를 느리게 하는 원인임을 알 수 있을 것이다
      • 테스트: 파일 시스템 지연시간을 질의 지연시간으로 나누어 보니 전체 시간의 5%가 안됨
      • 분석: 파일 시스템이나 디스크가 원인은 아님
        → 새로운 가설을 세우고 추가적인 실험을 지속적으로 진행

    1-4. 지연시간 분석

    • 어떤 연산을 완료하기까지 걸린 시간을 분석
    • 그 후, 근본원인을 식별할 수 있을 때까지 더 작은 요소로 나눠서 파악
      ex) 전체 지연시간(2s)
      → A 지연시간 (1.5) + B 지연시간 (0.5)
      → C 지연시간(1) + D 지연시간(0.5) + B 지연시간(0.5) ※ C+D=A
    • 소프트웨어 스택의 각 단계를 조사
      → 어플케이션에서 운영체제, 라이브러리, 시스템콜, 커널, 드라이버
    • ex) MySQL 질의 지연시간
      • CPU 시간 vs CPU 외 시간
      • CPU 외 시간의 주 대기시간? → 파일 I/O 시간
      • 파일 I/O 시간 → 디스크 I/O? 락 획득 시간?
      • 디스크 I/O 시간 → 데이터 전송 시간? 임의 접근 시간?

    1-5. 리눅스 성능 분석

    • 이 외에도 다양한 접근 방법이 존재
    • 드릴다운 분석: 문제를 좀 더 높은 수준으로 보고, 관심 대상을 깊이 파고드는 방식
    • 이벤트 추적: 통계적 정보가 아닌 개별적으로 이벤트를 분석하여 문제를 해결
      ex) 네트워크 이슈 tcpdump 이용
    • 워크로드 특성 평가: 시스템에 가해진 입력 내용에 초점.
      ex) 타임시리즈 데이터베이스 성능이슈 → 조회 워크로드 패턴을 조정하여 해결

    • 다양한 리눅스 성능 관측 도구가 있으며, 목적에 맞게 적절하게 사용하는 것이 중요
    • 최근에는 유저 스페이스가 아니라 커널 스페이스에서 동작하여 적은 오버헤드를 발생시키는 eBPF 기반 도구들이 추세
       ex) DataDog도 eBPF를 사용

    2. CPU 관련 주요 개념 및 분석

    • CPU는 모든 소프트웨어 실행을 담당 → 성능 분석 시 가장 먼저 봐야하는 대상
    • CPU는 모든 실행이 필요한 프로세스가 사용
    • CPU 코어 개수보다 Process 개수가 많을 경우 대기열에 들어가서 자신의 순서를 기다려야 함
      → 프로세스 스케줄러가 순서를 정함

    2-1. 프로세스 스케줄러

    2-1-1. O(1) 스케줄러

    • 여기서 O는 시간 복잡도를 의미한다.
    • 리눅스 2.4까지는 하나의 큐를 사용하는 방식이었다
    • 이는 큐가 존재하고 프로세서가 있을 때, 모든 프로세스 목록을 탐색해 가장 우선순위가 높은 프로세스를 실행하는 방식으로 시간 복잡도가 O(N)이었다. 많은 프로세스가 실행되는 시스템에서 성능 저하의 문제로 2.6부터는 멀티큐 방식을 사용하는 O(1) 스케줄러가 등장하였다.
    • O(1) 스케줄러는 Active 큐와 Expired 큐를 가지고 있다.
    • 액티브 큐의 정해진 시간 (time slice) 동안 프로세스가 실행이 되고 남은 작업은 만료 큐로 이동이 된다.

    • 액티브 큐 수행 완료 후에는 만료 큐를 액티브 큐로 변경하고 다시 정해진 시간에 따라 프로세스가 실행이 된다.

    • 우선순위는 140까지 있으며 빠른 탐색을 위해 bitmap을 사용하고 있다. bit가 1이면 존재, 0이면 존재하지 않는 것으로 해당 우선순위에 프로세스가 있는지 알 수 있다.

    • 각 우선순위에는 동일한 우선순위를 가지는 Task가 배치되며 라운드 로빈 방식으로 실행이 된다.
    • 우선순위가 높은 Task를 찾기 위해 bitmap으로 최대 140까지 탐색을 해야하므로 항상 상수 시간만큼 시간이 소요된다. 그래서 O(1) 시간 복잡도를 가진다.

    2-1-2. CFS 스케줄러

    • 리눅스 커널 2.6.23 버전부터는 CFS 스케줄러를 사용하게 된다.
    • 가상 런타임이 가장 적은 프로세스를 정해진 시간(time slice)동안 실행하는 것이 기본 개념이다.
    • 여기서 가상 런타임은 실행시간에 비례해서 커지기 때문에 프로세스가 CPU를 오랫동안 기다리면 높은 우선순위가 부여된다. 즉, 프로세스가 CPU를 기다리는 시간을 계산하여 동적으로 우선순위를 부여한다.

    • CFS는 가상 런타임이 낮은 프로세스를 찾기 위해 레드블랙트리(red-black tree)알고리즘을 사용합니다.

    • 우선순위가 높은 프로세스를 먼저 실행시키고 더 많은 타임 슬라이스를 부여한다
      - 0~99 : RT(실시간) 프로세스
      (실시간 프로세스는 숫자가 클수록 우선순위가 높고 일반 프로세스보다 높음)
      - 100~139 : 일반 프로세스
      (-20 ~ +19 까지의 값을 가지며 기본값은 0입니다. 이 값은 커널 공간에서 100~139 사이 값으로 변환되어 관리)

    • 각 프로세스의 타임 슬라이스는 위 공식으로 계산된다. 스케줄링 레이턴시란 CFS 런큐에서 실행 대기 상태로 기다리는 프로세스들의 타임 슬라이스를 합한 값이다. 위 식에 의해서 각 프로세스는 load weight 비율만큼의 타임 슬라이스를 얻게 된다. 프로세스가 많아지면 CFS 런큐 전체 가중치 합이 많아지게 되므로 타임 슬라이스가 0에 가까워지는 것이 아니냐할 수도 있지만 최소 타임 슬라이스 값이 정해져있다.

    가중치는 우선순위에 따라 부여됨

    • 예시)
      • 문서 편집기와 동영상 인코더 두 가지 작업이 있는 시스템
      • 문서 편집기는 대부분의 시간을 사용자 키 입력을 기다리는데 사용
        → I/O 중심 프로세스
      • 동영상 인코더는 데이터 로드와 저장을 제외하고는 대부분의 시간을 프로세서를 사용
        → CPU 중심
      • 매뉴얼한 해결 방법: 문서 편집기에 더 높은 우선순위 및 긴 타임슬라이스 할당
        하지만, 리눅스에서는 일반적으로 사용자 프로세스에 동일한 우선순위를 부여한다.
      • CFS 스케줄러 정책에서는 가중치와 이전 실행시간을 고려해 다음 실행 시간을 산정하여 공평하게 실행 시간을 나눈다.
        → 가중치(=우선순위)가 같아도 이전 실행시간이 다름
        → 동영상 인코더는 쉬지 않고 CPU를 사용했기 때문에 큰 vruntime
        → 문서 편집기는 대부분의 시간을 I/O 요청을 대기하고 있었기 때문에 작은 vruntime
        → 문서 편집기의 반응성을 유지할 수 있음

    2-2. CPU 주요 개념

    2-2-1. 클럭 속도

    • CPU는 클럭 속도에 따라 명령을 실행
    • 전력 소모를 위해 클럭 속도를 조정할 수 있음
    • CPU의 전력은 P-states(performance states)와 C-state(operating states) 2가지 상태값으로 제어가 된다
    • P-state는 CPU 사용량이 적을때 CPU 코어의 주파수를 떨어뜨려서 적은 전압으로 CPU를 동작할 수 있게 하기 위해 사용되는 상태인데, 미리 정의된 CPU 코어 주파수와 전압의 셋팅 값을 가지고, 바쁠때는 최대 주파수로, 한가할 때는 낮은 주파수로 동작하게 한다
    • C-state는 CPU 내부 컴포넌트의 사용을 중단시켜서 전력 소모를 줄이는데 사용된다.
    • C-states 레벨에 따라 코어 내부 클럭이 중단되거나 L1/L2 캐시 Flush 및 Off 시키는 등의 동작이 발생하고, 레벨이 높아질수록 많은 컴포넌트들이 꺼짐으로써 전력 소모량은 줄지만, 그에 비례해서 정상 상태(C0)로 복귀하는데 더 많은 리소스와 시간이 소요되는 문제가 있다

    2-2-2. 하이퍼쓰레딩

    • 각 물리코어에 둘 이상의 스레드를 실행하도록 지원하는 기술
    • 더 많은 작업을 병렬로 수행 가능 (최대 30% 성능 개선)
    • 단, 프로세서 구조에 최적화되지 않은 코드의 경우 성능이 떨어질 수 있음

    2-2-3. CPU의 한계

    • 물리적인 한계와 전력 효율 등의 원인으로 클럭 속도 증가의 한계에 있음
      → 수직적 확장이 아닌 수평적 확장으로 해당 한계 극복

    2-2-4. 스케줄링 클래스

    • 리얼타임 프로세스
      • 실시간 부하를 위해 고정된 높은 우선순위 제공
      • 스케줄링 정책: 라운드로빈, 선입선출(FIFO)
    • 일반 프로세스
      • CFS 스케줄러에 적용할 우선순위를 조정
      • Completely Fair 지만 우선순위에 따라 실행 시간을 더 할당 받을 수 있음
      • 스케줄링 정책: 일반(NORMAL), 일괄(BATCH)
    • 우선순위 정보 확인 ps -el
    • 사용자 프로세스는 일반 클래스, 대부분 동일한 우선순위 (NICE 0)

    2-2-5. 사용률

    • 특정 기간동안 CPU 인스턴스가 작업을 수행한 전체 시간의 백분율
      → 어떤 CPU가 프로세스를 실행하거나 인터럽트를 처리하는데 걸리는 시간을 측정
      * 인터럽트: 하드웨어가 프로세서에 신호를 보내서 적합한 처리를 하도록 요청 (폴링 X)
      (예, 키보드 입력, 디스크에서 데이터 읽기, 네트워크 패킷 도착)
    • 높은 CPU 사용률이 꼭 문제가 되지는 않음
      → 낮은 CPU 사용률은 자원 낭비

    2-2-6. 사용자 시간 / 커널 시간

    • 사용자 공간 코드를 실행하는데 CPU가 소비한 시간 → 사용자 시간
    • 커널 공간 코드를 실행하는데 CPU가 소비한 시간 → 커널 시간
    • 계산 중심 애플리케이션은 사용자/커널 시간은 99/1 비율에 가까움
    • I/O 중심 애플리케이션은 커널 시간의 비중이 높음 (예, 웹 서버는 70/30)

    2-3. CPU 성능 분석 도구

    2-3-1. 기본 설치

    • top : 프로세스/스레드별로 CPU 사용 정보를 확인
      • 가장 많이 실행 중인 프로세스를 표시 → CPU 사용률 내림차순
      • 시스템 전체 요약 내용 표시 중 CPU 관련 내용
        • us : 사용자 모드에서 실행한 시간
        • sy : 커널 모드에서 실행 시간
        • nice : 우선순위가 조정된 사용자 프로세스 실행시간
        • id : idle 시간
        • wa : I/O 완료를 기다리며 아무것도 실행하지 않은 시간
        • hi : 하드웨어 인터럽트 처리에 사용된 시간
        • si : 소프트웨어 인터럽트 처리에 사용된 시간 트랩 또는 예외
          → 예, 존재하지 않은 메모리 주소 접근, 0 으로 나누기
        • st : 하이퍼바이저에 의해 빼앗긴 시간
      • 단점
        • 오버헤드가 높음 (/proc의 모든 프로세스 노드에 대해 open,read,close 수행)
        • 단기간만 짧게 실행되는 프로세스는 표시 안될 수 있음 (기본 3초, d키 눌러서 delay 조정 가능)
    • ps : 프로세스 상태 확인
    • uptime : 부하 평균 표시
      • 시스템 부하 평균을 표시하는 도구
      • CPU 자원의 1분, 5분, 15분 평균 부하를 표시
        → 15분 동안의 평균 부하의 경향을 볼 수 있음
        (top는 정보가 계속 갱신 → 현재 상태 확인)
        * 부하 : 실행중 / 인터럽트불가능 상태의 프로세스의 평균 개수
      • 단점
        • 인터럽트 불가능 상태(예, disk I/O 기다림)를 포함 → CPU 수요와 디스크 부하를 구분하기 힘듦
    • vmstat : 가상 메모리 통계 표시 (시스템 전체 CPU 사용률 평균을 포함)
      • 가상 메모리 통계 표시하는 도구
      • 시스템 전체 CPU 사용률을 같이 표시
      • uptime 대비 인터럽트 불가능 상태의 프로세스 정보도 포함
      • r: 실행/대기 중인 프로세스 개수, b: 인터럽트 불가능 상태의 프로세스 개수
      • us: 사용자 시간, sy : 시스템(커널)시간, id: 유휴, wa: I/O 대기, st: 하이퍼바이저가 뺏어간 시간
      • 단점
        • 프로세스 전체 평균만을 표시 → mpstat 은 CPU별 통계를 표시
    • pidstat : 프로세스/스레드별로 CPU 사용을 구분해 표시
      • 프로세스 / 스레드별로 CPU 사용을 구분해 사용률을 표시 ← uptime, vmstat은 cpu별 정보표시
      • CPU에서 실행중인 프로세스를 매초 표시
    • time : 명령 실행에 걸린 시간을 측정, CPU 사용 시간도 별도로 표시

    2-3-2. 추가 패키지 설치

    • mpstat : CPU별 통계
    • sar : 과거 통계
    • DTrace : CPU 프로파일링과 트레이싱
    • perf : CPU 성능 카운터 분석
     

    Flame graph (Profiling)

    Flame Graph ? show the CPU time spent in Java methods, system libraries, and the kernel, all in one visualization. 해석하기 각 사각형은 stack frame을 나타낸다(즉, 함수). 사각형의 가로(width)는 현재 프로파일에 얼마나 존재

    binux.tistory.com

    2-3-3. CPU 분석 도구 정리

    •  툴이 대응하는 시나리오가 존재
    • top은 현 시점의 사용량 정보 확인
    • uptime은 최근 15분간 CPU사용률의 경향성을 파악
    • vmstat은 시스템 전체의 CPU사용률을 파악
    • pidstat은 프로세스/스레드별로 CPU 사용률을 파악

    → 도구들 조합해서 사용해야 함

    3. 메모리 관련 주요 개념 및 분석

    3-1. 물리 메모리 vs. 가상 메모리

    • 물리 메모리 : 실질적으로 사용할 수 있는 메모리 공간
    • 가상 메모리 : 프로세스가 바라보는 물리 메모리를 추상화한 메모리 공간

    3-2. 페이징

    • 가상 메모리, 물리 메모리 공간을 일정한 조각으로 나누어서 관리
      : 가상 메모리 조각 → 페이지
      : 물리 메모리 조각 → 페이지 프레임
    • 페이지의 크기
      4KB, 8KB, ← 아키텍처(x86, amd64, arm 등)에 따라 다름
      인텔은 4KB
    • 가상 메모리의 페이지를 물리 메모리의 페이지에 적재/해제
      → 매핑 정보는 페이지 테이블에 유지

    3-3. 요구 페이징 (Demand Paging)

    • 물리 메모리보다 큰 앱을 구동해야할 경우에 모든 데이터를 메모리에 로드하지 않고 필요할 때 디스크 페이지를 로드
      ex)
      1. 2GB 물리메모리에 8GB 크기를 사용하는 온라인 게임 실행
      2. 2GB 물리메모리에 4GB 동영상 재생
    • 물리 메모리의 프로그램의 페이지가 없더라도 프로그램을 실행 가능
    • 제한된 메모리 공간을 최대한 효율적으로 사용
    • 프로세스가 존재하지 않는 페이지에 접근하면 페이지 폴트를 발생
      → 스토리지에서 메모리로 데이터를 로드 후 페이지 테이블 갱신
    • 디스크에 저장된 데이터가 아니라, 프로그램이 malloc으로 메모리 공간을 할당하는 경우?
      • heap 메모리 영역 크기만 증가시키고, 실제로 물리 메모리 공간을 사용하지는 않음
      • 추후, 프로세스가 가상메모리 영역에 접근하는 경우 페이지 폴트 발생 후 페이지를 할당

    3-4. 페이지 테이블

    • 프로세스의 페이지 맵핑 정보를 저장하고 있는 테이블
      → 페이지 넘버와 페이지 프레임 넘버의 맵핑 정보 저장
    • 프로세스마다 별도의 페이지 테이블을 유지
      → 프로세스 별로 메모리 공간이 분리
      → 하지만 프로세스별로 페이지 테이블을 유지하면 상당한 크기를 차지하게 되므로 관리 효율을 위해 다중 계층의 구조를 가짐, 실제 사용하는 메모리에 대해서만 페이지 테이블 엔트리를 할당
    • 매번 주소 조회 시 페이지 테이블을 확인하지 않고 TLB (Translation Lookahead Buffer) 캐싱 사용
      → perf 툴로 TLB 상태 확인 가능

    3-5. 페이지 교체 알고리즘

    • 요구 페이징을 하더라도, 물리 메모리가 부족한 상황이 발생하게 됨
    • 페이지가 부족하게 되면 새로운 페이지를 할당하기 위해 현재 할당된 페이지 중 어느 것과 교체할지를 결정하는 방법
    • LRU (Least Recently Used) 알고리즘을 사용
    • Active, Inactive 리스트를 관리 (/proc/meminfo 에서 확인 가능)
    • file : 파일로 존재하는 페이지 → 페이지 회수
    • anon : 파일로 존재하지 않는 페이지 (예, stack, heap) → 스와핑

    3-6. 스와핑

    • 전체 프로세스를 주 메모리와 물리적 swap 장치/파일 사이에 이동
    • 프로세스가 사용하는 모든 데이터를 swap 장치에 기록
      → anonymous page 포함
      → file page의 경우 변경되지 않은 것은 제외, 필요시 원위치에서 읽어옴
    • 성능 저하 이슈로 성능이 중요한 앱에서는 잘 사용하지 않음
      → 클라우드에서도 잘 사용하지 않음
    • swap 비활성화된 리눅스 머신 (EC2의 경우, 기본 비활성화)
      1. cat /proc/swaps
      2. cat /proc/meminfo
    • 스와핑이 없는 시스템에서 앱에 메모리 누수가 발생하게 되면 OOM Killer가 강제로 프로세스를 Kill 한다
      • 회수가 불가능한 메모리를 지속적으로 증가시켜서 OOM Killer 동작을 테스트할 수 있다
      • stress-ng --bigheap 10 (Heap 공간을 지속적으로 할당)
      • Out Of Memory 킬러 동작과 관련한 커널 메시지 (/var/log/syslog)
      • OOM 킬러의 프로세스 종료 기준은 가장 높은 oom score를 가진 프로세스가 종료된다
        → /proc/PID/oom_score
      • score 범위: 0 ~ 1000
      • score를 높이는 경우?
        • 메모리를 많이 사용하는 경우 (예, rss, pagetable 크기가 큰 경우)
        • oom_score_adj 가 높은 경우
      • 메모리를 많이 사용하더라도 종료될 확률을 낮추려면 oom_score_adj를 낮게 설정하면 된다
      • 특정 프로세스가 OOM 킬러에 의해 종료되지 않게 하려면 oom_score_adj를 -1000으로 설정하면 된다
      • oom_kill.c 에 해당 코드가 구현되어 있는 부분을 살펴보면
        adj == OOM_SCORE_ADJ_MIN return 해버리는 구문이 있다. 참고로 OOM_SCORE_ADJ_MIN 은 -1000 이다

    3-7. 메모리 분석 도구

    3-7-1. vmstat

    • 가상 메모리 통계 확인 (현재 가용 메모리, 페이지 통계 등)
    • free: idle 메모리 양
    • buff: 버퍼 용도로 사용된 메모리 양 (쓰기)
    • cache: 캐시 용도로 사용된 메모리 양 (읽기)
    • active: active 메모리 양 (-a) ← active 메모리 : buff +cache 메모리 중 최근 사용된 메모리
    • inact: inactive 메모리 양 (-a) ← inactive 메모리: buff +cache 메모리 중 회수 가능한 메모리
    • swpd: 사용중인 swap 공간
    • si: 디스크에서 swap in된 메모리 양 (/s)
    • so:디스크에 swap out된 메모리 양(/s) ← 메모리 부족 상황

     

    3-7-2. ps

    • 프로세스 상태를 확인하는 명령 → 프로세스별 메모리 정보도 포함
    • %MEM : 주 메모리 사용량(RSS)의 전체 주 메모리 크기 비율
    • RSS : 주 메모리에 상주해 있는 크기, VSZ : 가상 메모리 크기

    3-7-3. top

    • 실행중인 프로세스 정보를 표시 → 메모리 사용량 순으로 정렬, top -o
    • %MEM . Mem, Swap 은 total, used, free 정보를 표시
    • %MEM : 주 메모리 사용량(RSS)의 전체 주 메모리 크기 비율
    • VIRT : 가상 메모리 크기
    • RES : 주 메모리에 상주해 있는 크기

     

    3-7-4. pmap

    • 프로세스의 메모리 맵 정보를 표시
    • 매핑된 메모리 정보 확인 가능: 크기, 권한, 실제 사용량 등
    • sudo pmap $PID

    • sudo pmap -x `pidof containerd` | sort -k 3 -n -r

    3-8. 메모리 성능 튜닝

    • 메모리 관련해 변경가능한 커널 설정 항목
      https://www.kernel.org/doc/Documentation/sysctl/vm.txt
    • min_free_kbytes
      • 최소 free 영역의 크기를 지정
      • 페이지 교체를 담당하는 kswapd의 동작 시점을 조정 가능
        • 동작 시점 :
          • low_pages: 페이지 회수를 시작하는 시점
          • high_pages: 페이지 회수를 중지하는 시점
          • min_pages: 동기적으로 페이지 회수 진행 시점
      • min_free_kbytes 설정에 따라 low_pages, high_pages 조정
      • 조절 방법 :
        • echo 30000 > /proc/sys/vm/min_free_kbytes
        • sysctl -w vm.min_free_kbytes = 30000
        • 부팅 후에도 적용 위해선 /etc/sysctl.conf 수정
      • min_pages 설정이 낮을 때,
        → 애플리케이션이 조금 더 메모리를 사용 가능
        메모리 사용이 급증할 때 여유 공간 확보가 어려움
        → OOM 발생 가능성 높음
      • min_pages 설정이 높을 때,
        → 매개 변수를 너무 높은 값 (총 시스템 메모리의 5-10%)으로 설정하면 시스템 메모리 부족을 초래할 수 있음
        → 시스템이 메모리를 회수하는데 많은 시간을 소모
      • 기본 min_free_kbytes 값
        → 부팅 시 물리 메모리 기준으로 셋팅 됨

    → Ad-Hoc한 워크로드 아닌 이상, 기본 설정값으로 충분한 경우가 많음

    → 변경에 따른 효과가 극적인 경우가 많지는 않기 때문에, 변경에 따른 영향도를 잘 확인하고 수정

    4. 파일시스템 관련 주요 개념 및 분석

    • Ubuntu 22.04 기본 파일시스템: EXT4
    • Amazon Linux 2 기본 파일시스템: XFS

    4-1. 파일 시스템에 따른 성능 차이

    • MariaDB :
      F2FS > XFS > EXT4 > Btrfs

    • Flexible IO Tester 벤치마크 :
      XFS > EXT4 >>> F2FS >> Btrfs
    • XFS, EXT4의 경우 성능차이가 크지 않음
      → 다양한 워크로드에 이미 최적화
      → 일반적이지 않은 I/O 바운드 워크로드를 제외하고는 , 파일시스템이 파일 I/O 성능 관련한 지배적인 요소는 아닌 경우가 많음
      → 하지만 , 커널 버전에 따른 성능 이슈는 한번 확인 필요, 여전히 관련 commit 은 진행 됨

    4-1-1. 참고) FIO (flexible I/O tester)

    • I/O 퍼포먼스 벤치마크
    • sudo apt install -y fio
    • 사용 예시 1)
      1 MB 크기 연속 쓰기
      sudo fio --name=write_test \ --filename=/dev/xvdb --filesize=100G \ --time_based --ramp_time=2s --runtime=1m \ --ioengine=libaio --direct=1 --verify=0 --randrepeat=0 \ --bs=1M --iodepth=64 --rw=write --numjobs=10 --offset_increment=10G
    • 사용 예시 2)
      4 KB 크기 랜덤 읽기
      sudo fio --name=read_test \ --filename=/dev/xvdb --filesize=100G \ --time_based --ramp_time=2s --runtime=1m \ --ioengine=libaio --direct=1 --verify=0 --randrepeat=0 \ --bs=4K --iodepth=256 --rw=randread

    4-2. 페이지 캐시 (읽기 성능 개선)

    • 디스크 성능 개선은 최대한 캐시를 사용하도록 최적화
    • 디스크 입출력을 최소화 하기 위해 디스크 접근이 필요한 데이터를 물리 메모리에 저장
    • 페이지 캐시의 크기는 동적으로 변함
      → 가용 메모리가 있는 경우 증가
      → 가용 메모리가 없는 경우 감소
    • 페이지에 읽으려는 데이터가 있는 경우를 캐시 히트, 없는 경우를 캐시 미스라고 칭함
      → 캐시 히트 비율에 따라 성능 크게 영향

    4-3. 버퍼 캐시 (쓰기 성능 개선)

    • 최대한 디스크 I/O가 적게 일어나도록 캐시 사용
    • 지연 쓰기 (비동기 쓰기)
    • 쓰기 동작은 페이지 캐시에 수행하고 즉시 디스크에 내용을 갱신하지 않음
      → dirty bit 셋팅
    • 주기적으로 더티 페이지를 디스크에 저장하는데 pdflush 데몬이 수행함
      → 더티 페이지가 일정 비율 도달 시 (vm.dirty_ratio 로 지정 가능)
      → 동기적으로 쓰기 페이지 flush작업이 진행 → 쓰기 성능 급격히 저하 발생
      → 즉, 쓰기 요청이 급격히 증가할 경우, 동기적으로 쓰기 작업이 이루어지고 성능 저하 발생할 수 있음
    • Buffer Cache가 따로 존재하지는 않고 Page Cache일부를 나누어서 사용한다
      → 쓰기 요청이 많이 발생하는 상황에서, 읽기 요청에 사용되는 공간이 적어지면 성능 저하 발생
      → pdflush로 쓰기 캐시 공간을 제한 가능함

    4-4. 동기적인 쓰기 동작

    • 만약 캐시를 사용하지 않고 디스크에 곧바로 저장하고 싶다면 fsync( ) 함수를 사용하면 된다
    • fsync(int fd) : 특정 파일에 대한 모든 지연된 쓰기 버퍼 내용을 동기적으로 디스크에 저장
    • 파일 오픈 시 동기화 옵션 사용
      • O_SYNC 모드 : write요청 + fsync요청
      • O_DIRECT : 버퍼 캐시를 사용하지 않고 바로 디스크에 쓰기 수행

    4-5. 파일시스템 관련 주요 성능 지표

    • 처리량 : 초당 전송되는 데이터 양
    • IOPS (Input/Output Operation Per Second) : 초당 IO 요청 개수
    • 읽기 / 쓰기 비율 : 페이지 캐시를 서로 공유, 페이지 캐시 크기가 작을 수록 캐시 미스가 많아짐
    • 동기적 쓰기 비율 : 지연쓰기와의 성능차이가 큼 (디스크를 접근 유/무 차이)
    • 임의적 접근 / 순차적접근

    4-6. 파일 시스템 분석 도구

    • free
      • 여유 및 사용중인 메모리 정보 확인
      • 출력 내용
        • total: 전체 메모리
        • used: 사용중인 메모리 (= total - free - buffers - cache) 
        • free: 여유 메모리 
        • shared : 호환성을 위해 컬럼 유지 (의미x) 
        • buffer/cache : 버퍼와 캐시를 합친 공간 -w 옵션 사용하면 두 공간 분리표기 
        • available : 새로운 앱 시작에 사용가능한 메모리 공간 (= free + page cache 일부 공간)
    • top
      • 메모리 요약 정보를 포함하고 있음
    • 캐시 적중 비율은 ftrace같은 도구로 커널 정보를 추가로 모니터링 하거나 eBPF 기반 도구를 사용

    5. 디스크 관련 주요 개념 및 분석

    • 디스크 종류에는 크게 HDD와 SSD가 있다
    • SSD가 모든 성능면에서 우세
    • 하지만 가격적인 부분 때문에 HDD를 사용할 수도 있다
    • HDD는 랜덤 읽기/쓰기에서는 성능이 크게 떨어지므로 연속적인 읽기/쓰기에서는 활용 가능
      ex) 대규모 스트리밍 데이터 저장
    • 그냥 SSD 쓰는게...ㅎ

    5-1. 블록 I/O 계층

    • 고정된 크기의 데이터 묶음을 임의 접근
    • 데이터 묶음을 블록이라고 부름
    • SSD, HDD, USB Memory 등
    • 파일 시스템을 통해 마운트 하여 사용
    • 블록장치는 섹터 단위(보통 512B) 로 접근
    • 파일시스템은 블록 단위(예, 4KB)로 접근

    5-2. I/O 스케줄러

    • 블록 I/O 성능을 향상 시키기 위해 블록 I/O 요청을 병합하고 정렬하는 역할 수행
    • 지연된 블록 I/O 요청들에게 디스크 I/O 자원을 골고루 분배
    • 스케줄러 타입
      1. deadline : 각 I/O 요청의 시작 시간을 보장
      2. cfq : 완전히 공정한 대기열. 프로세스간 I/O를 고정하게 할당
      3. noop : 요청을 정렬하지 않음
      4. none : (멀티큐) 요청을 정렬하지 않음
      5. mq-deadline : (멀티큐) 각 I/O 요청의 시작 시간을 보장
    • 클라우드 환경에서는 워크로드가 I/O 바운드한 앱이 아닌 경우, 어떤 스케줄러를 쓰던 극적인 효과는 보기 힘듦

    5-3. 디스크 성능 분석 도구

    • iostat
      • CPU 통계와 디바이스나 파티션에 대한 I/O 통계 내용을 표시
      • 설치 : sudo apt install sysstat
      • 표시 내용
        • tps : 디바이스에 요청된 데이터 전송 요청 횟수
        • read/s, wrtn/s : 초당 데이터 읽기 / 쓰기 양
        • read, wrtn : 전체 읽기/쓰기 양
        • dscd/s : unmapped된 블록 수 (예, 디스크 일부 공간을 메모리에 맵핑 했던 내용을 해제한 블록 수)
      • 표시 항목 확장 : iostat -x
        • r_await, w_await : 읽기/쓰기 요청의 평균 응답 시간 (큐에서 대기한 시간도 포함)
        • rrqm/s, wrqm/s : 대기열에 들어가 병합된 읽기/쓰기 요청 횟수
    • pidstat
      • -d 옵션을 사용하면 Disk I/O 통계 정보도 출력됨
      • 표시 내용
        • rd/s : 초당 읽은 크기
        • wd/s : 초당 쓴 크기
        • ccwr/s : 초당 취소한 쓰기 크기 (예, 디스크에 버퍼 캐시 내용을 플러시 하기전에 덮어 쓴 경우)
        • iodelay: 블록 I/O를 대기한 시간 (동기적인 블록 I/O를 대기한 시간, 스왑 인 시간을 포함)

    • iotop
      • top 명령과 유사하게, io에 대한 top 정보를 출력
      • 설치 : sudo apt install iotop
      • 1초 단위로 수집된 정보를 표시
      • 배치 모드, -b 를 사용
        sudo iotop -bod5 (배치 모드로, I/O를 진행중인 프로세스만, 5초 단위로 출력)
      • 표시 내용: 프로세스 별 읽기/쓰기 처리량

    5-4. 디스크 성능 튜닝

    • ionice
      • I/O 스케줄링 클래스(-c)와 우선순위(-n)를 조정
      • 설정 방법
        • ionice [-c class] [-n level] [-t] –p PID
        • ionice [-c class] [-n level] [-t] –p PGID
        • ionice [-c class] [-n level] [-t] –p UID
        •  ex) ionice -c 3 -p 1623
      • 클래스 번호
        • 0 (none): 클래스 지정 하지 않음
        • 1 (realtime): 실시간. 가장 높은 우선순위를 제공
        • 2 (best effort): 최선을 다하도록 설정
        • 3 (idle): 디스크가 유휴 상태인 경우에만 I/O를 요청 (예, 관리 도구의 운영 부하를 최소화 목적으로 사용)
      • 우선순위
        • 0-7에서 지정
        • 0이 가능 높은 우선순위
        • ex) 높은 I/O 우선순위를 가지는 프로세스 실행 : ionice -c 2 -n 0 COMMAND
    • I/O 스케줄러
      • 스케줄러 종류: [noop, cfq], [none, mq-deadline] 등
      • none : 처리 순서를 변경하지 않음. 최소 오버헤드. 빠른 SSD 디바이스에 적합
      • mq-deadline
        • 멀티 큐를 지원하는 deadline 스케줄러. 요청에 대해 보장된 대기 시간을 제공하려고 시도
        • 읽기/쓰기를 별도 큐로 관리하고, 읽기 요청이 우선적으로 처리됨
      • I/O 스케줄러 변경 방법
        • echo "mq-deadline" > /sys/block/DEVICE_NAME/queue/scheduler

    • I/O 스케줄러 변경에 따른 성능 폭은 작음

    6. 네트워크 관련 주요 개념 및 분석

    6-1. Throughput(처리량) 과 Latency(지연시간)

    • Throughput은 특정 시간동안 발생한 이벤트
      예시) S에서 P까지 1시간에 100대가 도착 → Throughput은 100 대 / 시간
    • Latency는 이벤트가 발생하기까지 걸린 시간
      예시) S에서 P까지 40시간 소요 → Latency는 40시간

    → Latency는 줄이고, Throughput은 늘려야함

    6-2. 지연 시간

    1. 이름 분석 지연시간 (Name resolution 시간) :
      • 원격 호스트 접속을 위해 DNS 질의를 하는 시간이 필요함
    2. 연결 지연시간 : 
      • 데이터를 전송하기 전에 네트워크 연결을 맺는데 걸리는 시간
        ex) TCP 경우 → 3-way 핸드쉐이크 시간
    3. 최초 바이트 지연 시간 (time to first byte)
      • 연결을 맺는데 성공한 시점부터 데이터의 첫 번째 바이트가 도착하기까지 걸린 시간
      • Full TTFB = DNS 룩업 + 커넥션(TCP, SSL) + HTTP Request TTFB
      • HTTP Request TTFB = HTTP 요청 시간 + 서버단의 요청 처리 시간 + HTTP 첫 바이트 응답 전송 시간
    4. 왕복 시간 (RTT, Round-Trip Time)
      • 네트워크 패킷이 두 끝점 사이를 왕복하는 데 걸린 시간
    5. 연결 지속 시간 (Connection Life Span)
      • 네트워크 연결이 맺어진 시간부터 연결이 닫힐 때까지의 시간
      • 일부 프로토콜은 계속 연결 유지(keep-alive, Multiplexed Stream등)
        → 연결 수립에 필요한 부가비용과 지연시간을 줄일 수 있음

    6-3. Cloud 환경 네트워크 최적화 방법

    1. Latency를 줄이는 방법
      • CloudFront 사용
        • 네트워크는 물리적인 거리에 절대적 영향을 받음
        • 클라이언트 근처의 캐시 서버에 데이터를 캐싱
        • 엣지 서버까지 데이터를 빠르게 이동
        • 안정적인 응답 시간 → 응답 시간이 튀지 않음
    2. Throughput을 늘리는 방법
      • 인스턴스 크기 또는 종류 변경
        • 일반적으로 인스턴스의 크기가 증가할수록 네트워크 대역폭도 증가
        • 높은 네트워크 대역폭을 제공하는 인스턴스로 종류를 변경
      • 점보 프레임을 사용
        • 실시간성의 데이터나 트랙잭션 데이터가 아닌 경우에는 패킷 자체의 크기를 늘릴 수 있음
          * MTU (Maximum Transmission Unit) : 해당 레이어가 전송할 수 있는 최대 프로토콜 데이터 단위
        • 단점으로는 더 큰 패킷은 손상되기 쉽고, 오류가 발생하는 경우 다시 전송하는 양도 많아지고 애초에 장비가 점보프레임을 지원해야 사용 가능함, 라우팅 경로 중간에 지원하지 않는 장비가 존재할 수도 있음
        • AWS내에서 VPC 간 연결에 사용할 수 있음, 점보 프레임 기능 지원

    6-4. 네트워크 성능 관련 주요 지표

    • 네트워크 인터페이스 (RX, TX) - Receive, Transmit
      • 사용률 : 인터페이스가 프레임을 보내거나 받기 위해 작업한 시간
      • 포화 : 인터페이스를 완전히 사용하기 때문에 발생하는 대기, 링 버퍼 사용, 차단 정도
      • 오류 : 수신의 경우, 잘못된 체크 섬
      • ethtool로 네트워크 드라이버/하드웨어 정보 확인 가능

    • TCP 프로토콜
      • TCP 백로그 대기열 사용
        • 인터페이스에 요청이 커널의 처리량 보다 많을 경우 패킷을 쌓아 놓는 큐
          sysctl net.core.netdev_max_backlog
          예) 10Gbps이상 네트워크: 1000 → 3000
      • TCP 송신/수신 버퍼의 사용
        • sysctl net.ipv4.tcp_wmem 
        • sysctl net.ipv4.tcp_rmem
      • 혼잡 윈도우 크기
        • 혼잡제어 알고리즘(net.ipv4.tcp_available_congestion_control)에 따른 윈도우 크기
      • 전송 가능한 윈도우 크기
        • 수신 윈도우와 혼잡 윈도우 중 작은 크기가 전송 가능한 윈도우의 크기이다

    6-5. 네트워크 성능 분석 도구

    • netstat
      • 다양한 네트워크 스택 및 인터페이스 통계
      • netsstat : 연결한 소켓 목록을 표시
      • netstat -a : 모든 소켓의 정보 목록을 표시
      • netstat -r : 라우팅 테이블 표시
      • netstat -i : 인터페이스 통계 정보를 표시
        • OK : 전송에 성공한 패킷
        • ERR: 패킷 오류 수
        • DRP: 유실된 패킷 수
        • OVR: 패킷 오버런 수 (링 버퍼 처리 속도보다 더 빠르게 패킷이 요청됨)
      • netstat -n : IP 주소를 호스트 이름으로 변경하지 않음
      • netstat -c : 연속적으로 결과를 출력
      • netstat -t : TCP 연결을 출력
      • netstat -l : 연결가능한 상태만 출력
      • netstat -p : 프로그램 정보 출력
      • netstat -s : 네트워크 스택 통계를 표시
    • ip
      • 네트워크 인터페이스와 라우팅 설정에 사용
      • 각 상태와 통계를 표시

    • tcpdump
      • 네트워크 패킷을 캡처해 분석
      • 이름은 tcpdump지만, UDP, ICMP도 덤프 가능함
      • 패킷 요약을 화면에 출력하거나, 파일로 저장할 수 있음
        tcpdump -i eth0 -w /tmp/out.tcpdump
        tcpdump -r /tmp/out.tcpdump
        권한 오류 발생시 → sudo apt install apparmor-utils && sudo aa-complain /usr/sbin/tcpdump
      • 출력정보: 시간, 송신측/수신측 IP 주소, TCP 헤더 등
      • tcpdump -i eth0 ← 인터페이스 eth0 정보
      • tcpdump -i eth0 -c 10 ← 10개만 덤프 
      • tcpdump host 192.168.0.1 ← 특정호스트 양방향 덤프
      • tcpdump src 192.168.0.1 ← 출발지 192.168.0.1 덤프 
      • tcpdump dst 192.168.0.1 ← 목적지 192.168.0.1 덤프 
      • tcpdump port 80 ← 포트가 80 덤프
      • tcpdump src port 80 ←  출발지 포트가 80 덤프
      • tcpdump dst port 80 ← 목적지 포트가 80 덤프 
      • tcpdump -i eth0 -v 'tcp and port 80’ 
      • sudo tcpdump host google.com

    • ping
      • ICMP echo 요청 패킷을 보내서 네트워크 연결성을 테스트
      • 패킷 왕복 시간(round trip time, RTT) 정보를 표시
      • ICMP 패킷은 라우터가 일반 애플리케이션 프로토콜보다 더 낮은 순위로 처리될 수 있음
        → 실제보다 더 높은 지연시간 나올 수 있음
      • 방화벽에 막힌 경우 확인 불가능
    • traceroute
      • 일련의 테스트 패킷을 보내서 대상 호스트까지 이르는 현재 경로를 파악
      • IP 프로토콜의 패킷 생존 시간(time to live, TTL)을 1씩 증가시키면서 전송 (=1 hop씩 증가)
      • sudo apt install traceroute
      • ICMP 패킷에 응답 안 하는 라우터도 존재
      • ping 명령과 마찬가지로, 패킷의 우선순위가 낮음 → 높은 지연시간 보일 수 있음
      • sudo traceroute google.com
      • sudo traceroute -T -p 443 google.com
      • 물리적으로 긴 네트워크 구간으로 긴 RTT이 발생할 수 있음

    6-6. 네트워크 성능 튜닝

    • 사용 가능한 튜닝 파라미터는 운영체제 버전에 따라 차이가 있음
    • 수정 방법
      • sysctl 명령 
      • /etc/sysctl.conf 설정
      • 경우에 따라 /proc/sys/net
    • TCP 네트워크 튜닝 파라미터
      • 소켓 버퍼의 크기를 조정
        • 큰 사이즈 메모리, 높은 네트워크 대역폭의 인스턴스 → net.core.rmem_max, net.core.wmem_max
          예) net.core.rmem_max 의 기본값 208 KB → 변경값 16 MB (reInvent 2017, performance tuning session)
      • 혼잡제어 알고리즘 변경 (전제, 혼잡이 발생 → 서비스 품질 저하 발생)
        • CUBIC : 전송속도를 지속적으로 증가시켜 나가면서 네트워크 상태를 파악 ← 혼잡이 발생하게 되는 구조
        • BBR : 현재 이용 가능한 대역폭의 크기와 최소 지연 시간의 곱을 기반으로 데이터 양을 제한 ← 혼잡 방지
        • sysctl -w net.ipv4.tcp_congestion_control="bbr"
        • 단, 해당 모듈 컴파일 여부 확인 → cat /boot/config-$(uname -r) | grep 'CONFIG_TCP_CONG_BBR’
          → 네트워크 사용량이나 성능이 중요한 앱의 겨우 적용 검토. 운영환경 적용 전에 실험을 여러 번 진행

     

     

     


     

     

     

    • 아이고... 많다
    반응형
    댓글