PostgreSQL

PostgreSQL: SLRU(Simple Least Recently Used) 버퍼 캐시

dewstream 2025. 5. 15. 08:00
728x90

※ PostgreSQL: SLRU (Simple Least Recently Used) Buffer Cache.

 

안녕하세요. 듀스트림입니다.

 

오늘은 PostgreSQL 내부 구조에서 단순하지만 매우 중요한 버퍼 캐시 관리 시스템인 SLRU에 대해 알아보겠습니다.


1. 배경 지식

LRU (Least Recently Used) 알고리즘이란?

  • 가장 오랫동안 사용되지 않은 데이터를 가장 먼저 제거하는 전략입니다.
  • LRU는 메모리 캐시, DB 버퍼 관리, 운영체제 페이지 교체 등에서 가장 널리 쓰이는 알고리즘 중 하나입니다.

LRU의 핵심 개념

  • 캐시에는 제한된 크기만큼의 데이터를 저장할 수 있습니다.
  • 새로운 데이터가 들어왔는데 공간이 부족하면?
    • 가장 오래 전에 접근된 데이터를 찾아서 제거
  • 가장 최근에 접근한 항목은 가장 늦게 제거

동작 예시 (Step-by-step)

  • 예시: 캐시 크기 = 3
  • 접근 순서: A → B → C → A → D
시점 접근한 값 캐시 상태 설명
1 A A A 삽입
2 B A B B 삽입
3 C A B C C 삽입
4 A B C A A 재접근 → 가장 최근으로 이동
5 D C A D B 제거 (가장 오래 사용 X)
  • 결과적으로 LRU는 사용 빈도가 아니라, 얼마나 오래 전 사용되었는지에 따라 제거 여부가 결정됩니다.

LRU 구현 방식

  1. 연결 리스트 (Linked List) 기반
    • 이중 연결 리스트(Doubly Linked List)로 최근 접근한 순서를 유지
    • 가장 앞(head): 최근에 접근
    • 가장 뒤(tail): 가장 오래된 항목 → 제거 대상
  2. HashMap + LinkedList 조합 (LRU Cache 구현의 정석)
    • HashMap: O(1) 시간으로 데이터 위치 찾기
    • LinkedList: 접근 순서 유지 및 LRU 제거
// Key-Value 구조로 저장 + 연결 리스트로 순서 유지
hashmap[key] = pointer to node

PostgreSQL의 LRU와의 차이점 (SLRU)

항목 일반 LRU 알고리즘 PostgreSQL SLRU
목적 범용 캐시 교체 트랜잭션 메타 캐시
단위 항목(Item) 페이지(page, 8KB)
구현 LinkedList or Tree 고정 슬롯 + LRU 카운터
크기 유동적 (설정 가능) 고정 (8~32 슬롯)

요약

항목 내용
목적 캐시 공간이 부족할 때 오래된 항목 제거
전략 가장 최근에 접근된 항목은 보존, 오래된 것부터 제거
구현 HashMap + LinkedList, LRU 카운터 등
PostgreSQL pg_xact 등 SLRU 구조에 LRU 방식 적용

2. PostgreSQL의 SLUR (Simple Least Recently Used)

SLRU (Simple LRU)란?

  • SLRU(Simple LRU)는 이름 그대로 단순한 LRU 알고리즘 기반의 메모리 캐시 구조입니다.
  • PostgreSQL 내부에서 소형의 페이지 기반 저장소(persistent metadata)를 캐시하기 위해 사용됩니다.

주요 역할

  • 디스크에 저장되는 트랜잭션 상태 파일(예: pg_xact)을 메모리로 로딩해서 접근 성능이 향상됩니다.
  • 핫스탠바이, hint bit 업데이트, MVCC 판단 시 트랜잭션 상태 조회/갱신에 사용됩니다.
  • 버퍼 수가 작기 때문에 LRU(Least Recently Used) 알고리즘으로 교체됩니다.

SLRU로 관리되는 목록

디렉토리 이름 설명 SLRU 캐시 이름
pg_xact 트랜잭션 커밋 상태 (예전의 clog) Xact
pg_subtrans 서브트랜잭션 → 부모 매핑 Subtrans
pg_multixact/members, offsets 멀티락(MultiXact) 상태 관리 MultiXactOffset, MultiXactMember
pg_notify LISTEN/NOTIFY용 큐 Notify
pg_commit_ts 트랜잭션 커밋 타임스탬프 기록 CommitTs
  • 각 항목은 SLRU 페이지(보통 8KB 단위)로 구성되며, 메모리 내에 일정 수만 캐싱됩니다.

구성 요소 별 SLRU 버퍼 슬롯 수

구성 요소 (디렉토리) 상수 이름 기본값 설명
pg_xact (구 pg_clog) NUM_CLOG_BUFFERS 32 트랜잭션 커밋 상태
pg_subtrans NUM_SUBTRANS_BUFFERS 8 서브트랜잭션 → 부모 매핑
pg_commit_ts NUM_COMMITTS_BUFFERS 8 커밋 타임스탬프 저장
pg_notify NUM_NOTIFY_BUFFERS 8 LISTEN/NOTIFY용 큐
pg_multixact/offsets NUM_MXACTOFFSET_BUFFERS 8 MultiXact ID → offset
pg_multixact/members NUM_MXACTMEMBER_BUFFERS 32 MultiXact Member 저장
  • 기본값으로 구성되었을 경우 총 96슬롯, 슬롯당 8KB의 크기를 갖고 있으며 총 캐시 메모리 사용량은 약 768KB입니다.

동작 방식

구조

  • 내부적으로는 페이지 단위로 데이터를 로딩함 (page_number → 8KB)
  • 8~32개의 페이지 버퍼 슬롯만 유지하며, 오래된 페이지는 LRU에 따라 제거
    • 슬롯 수는 PostgreSQL 빌드 설정 또는 사용 목적에 따라 다를 수 있습니다.
// src/include/access/clog.h
#define NUM_CLOG_BUFFERS 32

// src/include/access/subtrans.h
#define NUM_SUBTRANS_BUFFERS 8

 

로딩 & 저장

  • SLRU는 필요할 때 디스크에서 페이지를 읽어와 메모리에 로딩함 → SimpleLruReadPage()
  • 변경된 페이지는 flush 되며 → SimpleLruWritePage()

모니터링 방법

SELECT * FROM pg_stat_slru;

[그림 1] 모니터링 예시


요약

항목 설명
구조 단순한 페이지 캐시 (8KB 단위, 8~32개 유지)
사용 대상 트랜잭션 메타데이터 (pg_xact 등)
교체 방식 LRU (Least Recently Used)
사용 목적 디스크 접근 최소화, 성능 향상
관리 방법 내부 함수 (SimpleLruReadPage, SimpleLruWritePage)
모니터링 pg_stat_slru 뷰 사용

오늘은 여기까지~

 

728x90