2. 개발/2.8 OSS

Linux7에서 PGSQL 성능 저하 관련 글 보충 자료(AI생성)

NeoZest 2026. 5. 6. 23:54

제미나이로 정리한 기술 원고. 공부하기 좋은 세상임!

 

리눅스 커널 변화와 PostgreSQL 성능 분석 보고서

1. 핵심 개념 상세 설명

SpinLock (스핀락)

스핀락은 임계 구역(Critical Section)에 진입하기 위해 대기하는 스레드가 잠들지 않고 루프를 돌며 권한을 획득할 때까지 계속 확인하는 동기화 기법

  • 동작 방식:
    1. 스레드가 자원 사용을 위해 락(Lock)을 요청합니다.
    2. 락이 이미 사용 중이라면, 스레드는 대기 큐로 들어가는 대신 CPU를 계속 사용하며(Spinning) 락의 해제 여부를 체크합니다.
    3. 락이 해제되는 순간 즉시 자원을 점유합니다.
  • 특징:
    • Context Switch 없음: 스레드가 잠들고 깨어나는 오버헤드가 없습니다.
    • 비결정적 대기: 대기 중에도 CPU를 100% 점유하므로, 대기가 길어지면 시스템 성능이 급락합니다.
  • 장단점:
    • 장점: 임계 구역이 매우 짧을 때, 잠들고 깨어나는 시간보다 그냥 기다리는 시간이 짧아 효율적입니다.
    • 단점: 락을 쥐고 있는 스레드가 지연되거나 선점(Preemption)당하면, 기다리는 모든 스레드가 CPU를 낭비하며 '미친 듯이 도는' 현상이 발생합니다.

rseq (Restartable Sequences)

리눅스 커널이 제공하는 최신 기술

유저스페이스 코드가 원자적(Atomic)으로 실행되어야 하는 구간에서 커널에 의해 중단(선점)되었는지를 감지

  • 도입 배경: 멀티 코어 환경에서 'CPU별 데이터(Per-CPU data)'에 접근할 때 락 없이 빠르게 처리하기 위해 고안되었습니다.
  • 동작 원리:
    1. 프로세스가 특정 코드 구간(rseq 구간)을 시작함을 커널에 알립니다.
    2. 만약 이 구간을 실행하다가 커널이 스레드를 중단시키고 다른 일을 시킨다면(Preemption), 커널은 이 사실을 기록합니다.
    3. 스레드가 다시 CPU를 잡았을 때, 구간 중간부터 이어서 하는 것이 아니라 구간의 처음으로 돌아가 다시 실행(Restart)합니다.
  • 효과: 락을 쓰지 않고도 데이터의 일관성을 유지할 수 있으며, 이번 PostgreSQL 사례처럼 "락을 쥐고 잠드는" 최악의 시나리오를 방지할 수 있는 대안으로 제시되었습니다.
비교 항목 SpinLock Mutex rseq / Lock-free
대기 방식 계속 회전 (CPU 소모) 잠듦 (CPU 반납) 재시도 또는 원자적 처리
권장 상황 매우 짧은 임계 구역 긴 대기 시간 예상 시 고성능 멀티코어 환경
오버헤드 낮음 (즉시 반응) 높음 (문맥 교환) 매우 낮음 (난이도 높음)

2. 커널 스케줄링 및 선점 (Preemption) 관련

리눅스 커널이 CPU 자원을 여러 프로세스에게 나누어 주는 방식에 대한 용어입니다.

  • 선점 (Preemption): 실행 중인 스레드의 의사와 상관없이 OS 스케줄러가 강제로 CPU 사용권을 뺏어 다른 스레드에게 주는 행위입니다.
  • PREEMPT_NONE: "나 건드리지 마" 모드입니다. 스레드가 스스로 I/O를 기다리거나 잠들기 전까지는 커널이 웬만해서는 실행을 중단시키지 않습니다. 서버 환경에서 처리량(Throughput)을 극대화할 때 유리합니다.
  • PREEMPT_FULL / LAZY: "언제든 비켜줄게" 모드입니다. 응답 속도(Latency)는 빨라지지만, 자주 흐름이 끊겨 전체적인 일 처리량은 줄어들 수 있습니다. 리눅스 7.0에서 NONE 모드가 사라지면서 이번 성능 저하의 도화선이 되었습니다.
  • Restartable Sequences (rseq): 커널이 유저스페이스(PostgreSQL 등)에 "방금 네 실행 흐름이 중간에 끊겼었어"라고 알려주는 기능입니다. 이를 통해 중단되었던 작업을 처음부터 다시 안전하게 실행할 수 있게 돕는 최신 기술입니다.

3. PostgreSQL 성능 회귀 사건 분석 (통합)

최근 리눅스 7.0(내부 커널 버전 기준)에서 발생한 이슈는 하드웨어와 OS, 소프트웨어의 설계 철학이 충돌한 대표적 사례입니다.

📍 사건의 발단: 커널 정책의 변화

  • PREEMPT_NONE 제거: 과거 서버용 리눅스의 기본값이었던 "자발적 양보 외엔 절대 끊지 않음" 모드가 사라졌습니다.
  • PREEMPT_LAZY 도입: 처리량을 고려하되 필요시 선점하는 절충안이 기본이 되었으나, PostgreSQL의 전역 스핀락 구조와 상극을 일으켰습니다.

📍 문제의 메커니즘 (Cascading Failure)

  1. 스핀락 점유: PostgreSQL의 백엔드 프로세스가 공유 버퍼 풀 접근을 위해 단일 전역 스핀락(s_lock)을 획득합니다.
  2. 마이너 페이지 폴트: 락을 쥔 상태에서 메모리에 접근했는데, 해당 페이지가 물리 램에 매핑되지 않아 커널이 개입합니다.
  3. 선점 발생: 페이지 폴트 처리 중, 커널이 스레드를 잠시 중단(Preemption)시킵니다.
  4. 폭주: 락을 쥐고 있는 놈이 자리를 비우자, 나머지 수백 개의 CPU 코어들이 락을 얻으려고 스핀락 루프를 돌며 CPU 점유율을 100%까지 끌어올립니다.

📍 해결책 및 트레이드오프

해결 방법 주요 내용 장점 단점
Huge Pages 메모리 페이지를 4KB → 2MB/1GB로 확대 페이지 폴트 발생 빈도 감소 메모리 사전 할당 필요
rseq 도입 선점 시 재시작 메커니즘 선점 병목 해소 대대적 코드 수정 필요
Direct I/O OS 캐시 우회 중복 캐싱 방지 성능이 케바케임

4. 용어 사전 요약

  • Direct IO
    • 운영체제(OS)의 페이지 캐시(Page Cache)를 거치지 않고 데이터베이스 엔진이 저장 장치(Disk)와 직접 데이터를 주고받는 방식
    • 보통 OS는 성능 향상을 위해 디스크에서 읽은 데이터를 메모리에 임시로 저장(캐싱)합니다. 하지만 DBMS는 자체적으로 더 정교한 버퍼 풀(Buffer Pool) 관리 시스템을 가짐
    • 중복 캐싱(OS와 DBMS가 같은 데이터를 이중으로 들고 있는 현상)을 방지하고 CPU 사용량을 줄일 수 있음. 다만 OD가 제공하는 최적화 기능을 사용하지 못하므로 DBMS가 데이터를 효율적으로 관리하지 못하면 성능이 떨어질 수 있음
  • 네할렘 (Nehalem):
    • 메모리 컨트롤러를 CPU 내부로 통합. 이로 인해 NUMA 구조를 확립한 아키텍처.
    • 2008년 말 인텔이 출시한 CPU 마이크로 아키텍처. 2009년 서버 시장에 보편화
  • SMP( ymmetric Multi-Processing, 대칭형 다중 처리):
    • 모든 CPU가 동일한 메모리 접근 권한을 갖는 대칭형 구조.
    • CPU 개수가 늘어날수록 메모리로 가는 통로(Bus)에 병목 현상이 생겨 성능 확장 어려움 -> NUMA 등장
  • NUMA( Non-Uniform Memory Access , 비균할 메모리 접근): 
    • CPU별 독립 메모리 구조. 멀티 소켓 서버의 표준. 네할렘 이후의 멀티 소켓 서버는 대부분 이 구조를 따름
    • 각 CPU(소켓)마다 자신만의 전용 메모리 영역을 가짐. 자기 옆 메모리 접근시에는 빠르지만, 다른 CPU에 붙은 메모리 접근하려면 버스로 주고 받아야 하므로 속도가 느려짐.
    • NUMA를 지원하지 않는 소프트웨어는 멀리 떨어진 메모리만 쓰다가 성능이 떨어질 수 있음.
  • CCIX(Cache Coherent Interconnect for Accelerators):
    • CPU와 가속기 (GPU, FPGA 등) 간 캐시 일관성을 유지하면서 아주 빠른 속도로 데이터를 주고받기 위한 차세대 인터페이스.
    • NUMA의 데이터 전송 속도 한계를 극복하고, 서로 다른 제조사의 칩들이 마치 하나의 메모리를 쓰는 것처럼(캐시 일관성) 통신
    • 최근에는 인텔이 주도하는 CXL(Compute Express Link) 기술이 이 분야의 대세가 되면서, NUMA가 가졌던 물리적 한계를 극복하는 메모리 풀링(Memory Pooling) 시대로 이행되고 있
  • TLB(Translation Lookaside Buffer):
    • 가상 주소를 실제 주소로 바꾸는 맵이 담긴 변환용 초고속 캐시. TLB가 작으면 자주 매핑 정보를 구성해야 해서 속도 느려짐. Huge Pages 사용 시 효율 급증.
  • Huge Page
    • 기본 메모리 페이지 크기를 4K에서 2M/1GB로 뻥튀기. 페이지 수가 줄어들어 페이지 폴트 발생횟수가 줄어들면서 TLB 효율이 높아짐.
  • 페이지 폴트(Page Fault)
    • 프로그램이 메모리 주소를 불렀는데, 실제 물리 램에 아직 준비가 안되었을 때 발생하는 이벤트
    • 커널은 급히 램을 할당해줘야 하므로 아주 미세한 지연이 발생.

5.  성능 분석 및 벤치마크 관련

  • TPS (Transactions Per Second): 초당 처리되는 트랜잭션 수로, DB의 심박수와 같습니다. 이번 사례에서는 9.8만에서 5만으로 반토막 났습니다.
  • pgbench: PostgreSQL의 성능을 측정하는 표준 도구입니다.
  • perf: 리눅스 커널의 성능 분석 도구입니다. CPU가 어떤 함수에서 시간을 가장 많이 쓰는지 초 단위로 쪼개서 보여줍니다. 이번 분석에서 s_lock(스핀락)이 CPU의 55%를 먹고 있다는 범인을 잡아냈습니다.

 

반응형