[ PostgreSQL ] Vacuum 최적화

Manx·2023년 2월 28일
0

DBMS

목록 보기
1/8

PostgreSQL은 다른 RDBMS와는 다르게 Vacuum이라는 개념이 존재한다.

Vacuum이란

간단히 말하자면 더 이상 사용되지 않는 데이터들을 정리하는 명령이다.

사용되지 않는 데이터란 ?

DB에 데이터는 물리적으로 디스크에 저장되게 된다.
그러나, 이 데이터를 UPDATE or DELETE 시에 디스크에 있던 기존 정보를 갱신하거나 삭제하지 않는다.

UPDATE 과정

  • FSM(FreeSpaceMap)에 사용 가능한 공간이 있는지 확인, 없으면 FSM을 추가로 확보
    (FSM : 사용 가능한 공간을 표시하는 Map)

  • FSM의 사용 가능한 공간에 update된 데이터를 기록 (Insert)

  • update된 데이터의 저장이 완료되면 update 이전 원본 Tuple을 가리키던 포인터를 이동

해당 과정을 거친 뒤, 기존 데이터는 어디에도 참조되지 않는 Tuple이 된다. 이 Tuple을 Dead Tuple 이라고 한다.


그렇다면 왜 이런 번거로운 작업을 수행할까?

그 이유는 PostgreSQL의 MVCC(Multi-Version Concurrency Control)구현 방식때문이다.
-> (쉽게 말하자면 Transaction을 위해 )


PostgreSQL의 MVCC 구현

  • UPDATE 되었을 시, 새로운 튜플을 쌓는다.
  • Old version과 New version의 판단은 Transaction ID가 저장된 xmin, xmax 값을 비교해서 판단한다.

Transaction ID 예시

xminxmaxvalue
20102020AAA
20120BBB
20142030CCC
20200ZZZ
  • Transaction ID : 2015에서는 'AAA', 'BBB', 'CCC'를 볼 수 있다.
    -> 'ZZZ'는 xmin이 2020으로 2015보다 크기 때문에 볼 수 없다.
  • Transaction ID : 2021에서는 'BBB', 'CCC', 'ZZZ'를 볼 수 있다.
    -> 'AAA'는 xmax가 2020으로 2020까지만 존재하던 값으로, 2021에서는 볼 수 없다.

따라서 DB에 데이터가 변경될 수록 Dead Tuple이 많아지고, 쓸모 없는 데이터까지 page 단위로 읽어와 메모리에 올리기 때문에 성능이 저하되는 현상이 발생한다.


Vacuum 수행

Vacuum, Vacuum full에 차이가 존재한다.

Vacuum (AutoVacuum)

  • OS 디스크의 공간 반환까지는 처리되지 못하고 FSM만 반환되어 Dead Tuple이 있던 공간을 재사용할 수 있게끔만 처리된다.

Vacuum full

  • OS 디스크의 공간 반환까지 처리한다.
  • DB Lock이 걸리며, 운영 중에는 할 수 없는 작업이다.
  • 대상 테이블을 1개 더 COPY하는 방식으로 동작해 디스크 용량이 여유로워야 한다.

해결책 : pg_repack (Open Source)

-- DB 전체 풀 실행
vacuum full analyze;

-- DB 전체 간단하게 실행
vacuum verbose analyze;

-- 해당 테이블만 간단하게 실행
vacuum analyse [테이블 명];

-- 특정 테이블만 풀 실행
vacuum full [테이블명];

DB 설정으로 AutoVacuum을 OFF해놔도 관련 임계치를 초과하면 DB에서 강제로 수행하게 된다.


Transaction ID Wraparound

Tuple의 xmin, xmax를 통해 MVCC가 구현되어 있다.

약 40억개의 트랜잭션을 표현할 수 있으며, 20억개는 과거/20억개는 미래를 위해 사용하게 된다.

만약 Transaction ID가 20억이 넘어 1이 되었다면, 기존의 데이터들이 모두 미래에 있는 것 처럼 되어 보여지게 않게 된다.
이 현상을 Transaction ID Wraparound 라고 한다.

이를 방지하기 위해 특정 시점에 모두 frozen XID = 2 라는 특별한 Transaction ID로 바꿔버린다.
이 동작을 freeze 혹은 Anti Wraparound Vacuum 이라고 한다.

AutoVacuum 호출 시기

기본적으로 두 가지 상황에서 수행된다.

  • Dead Tuple의 개수의 누적치가 임계치에 도달했을 때
  • Table이나 Tuple의 age가 누적되어 임계치에 도달했을 때
  1. Dead Tuple 임계치 도달
vacuum threshold = autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * number of Tuples

Default : Dead Tuple 누적치가 테이블의 모든 행 중 20% + 50개를 초과하는 경우 AutoVacuum 이 호출되어 Dead Tuple을 정리하게 된다.

  1. Table or Tuple의 age의 임계치 도달
  • age가 2억 임계치를 초과한 경우
  • vacuum_freeze_table_age < 테이블의 age < autovacuum_freeze_max_age
    => 테이블의 age가 위 두 파라미터 값 사이에 속하면서 해당 테이블에 vacuum이 호출되었을 때

Vacuum 튜닝

  • 일반적으로 Vacuum이 드물게 수행될수록 정리해야 하는 Dead Tuple이나 frozen 작업이 점점 많아져 오히려 큰 부하를 유발하는 상황이 올 수 있다.
  • 그렇다고 너무 자주 수행하는 것도 DDL 수행과 겹치는 경우에 장애 상황이 발생할 수 있다.

Dead Tuple 정리와 Vacuum의 부하 간 적절한 균형을 찾아야 한다.


autovacuum_vacuum_scale_factor & autovacuum_vacuum_threshold

default 설정

  • autovacuum_vacuum_threshold = 50
  • autovacuum_vacuum_scale_factor = 0.2

권장 설정

  • autovacuum_vacuum_threshold = 50
  • autovacuum_vacuum_scale_factor = 0.1

autovacuum_vacuum_cost_limit & autovacuum_vacuum_cost_delay

default 설정

  • autovacuum_vacuum_cost_limit = 200
  • autovacuum_vacuum_cost_delay = 20ms

권장 설정

  • autovacuum_vacuum_cost_limit = 1000 or autovacuum_vacuum_cost_limit = 200 * (autovacuum_max_workers / 3)
  • autovacuum_vacuum_cost_delay = 5ms

autovacuum_vacuum_cost_limit : AutoVacuum이 한 번 수행될 때마다 갖는 credit
autovacuum_vacuum_cost_delay : 가진 credit을 모두 소모한 뒤 sleep 텀

credit이 모두 소진되면 해당 AutoVaccum 프로세스는 종료된다.
credit이 너무 작으면, Dead Tuple을 정리하지 못한 채 끝나버리기 때문에 Dead Tuple이 계속 누적된다.

요약
AutoVacuum이 너무 드물게 돌고있다

  • autovacuum_vacuum_scale_factor & autovacuum_vacuum_scale_threshold
  • autovacuum_vacuum_insert_scale_factor & autovacuum_vacuum_scale_threshold

AutoVacuum이 너무 느리다

  • autovacuum_vacuum_cost_delay
  • autovacuum_vacuum_cost_limit
  • autovacuum_naptime
  • autovacuum_max_workers
  • autovacuum_work_mem
  • max_parallel_maintenance_workers

추가

우아한 테크 세미나 - PostgreSQL 모니터링 방법


우아한형제들 기술블로그

profile
백엔드 개발자

0개의 댓글