본문 바로가기

PostgreSQL

15. PostgreSQL - VACUUM

앞 서 vacuum에서 하는 일 및 내부 처리 과정에 대해 설명

https://lsmdd.tistory.com/113

 

13. PostgreSQL - VACUUM 내부 동작 과정

vacuum이 하는 일dead tuple 제거dead tuple을 가리키는 index tuple 제거tuple의 oid txids를 freeze함.system catalog(pg_database and pg_class)와 연관된 frozen txid를 갱신clog의 불필요한 부분을 제거vacuum이 수행된 table의 F

lsmdd.tistory.com

 

이번 Post의 vacuum 관련 내용 간단 요약

아래 정리한 글을 다 읽을 필요 없이 간단하게 정리하자면 아래와 같다.

VM(Visibility Map)은 table의 page와 연관 된 정보를 가지고 있음.
    page내 dead tuple 존재 유무
    page내 freeze 대상 tuple 존재 유무


vacuum freeze 작업에는 lazy mode와 eager mode가 있음.
    freeze 대상 선정 조건
                   freezeLimit_txid = oldestXmin - vacuum_freeze_min_age(default 5000만)
    lazy mode
        vacuum이 table의 page와 연관된 VM 정보를 보고 dead tuple 정리 여부를 결정
        VM 정보 확인 후 page내 dead tuple이 있다고 판단되면 page내 freeze작업 및 dead tuple 정리 진행
        VM 정보에 page내 dead tuple이 없다고 나오면 freeze할 tuple이 있어도 page를 skip하기 때문에 freeze하지 못함.
        dead tuple 정리를 위해 접근한 page내  freezeLimit_txid보다 작은 t_xmin값을 발견할 경우 freeze 작업을 진행함.
    eager mode
        vacuum이 table의 page와 연관된 VM 정보를 보고 freeze 여부를 결정.
        VM 정보 확인 후 page 내 freeze 대상이 있다고 판단되면 freeze 진행하며 없을 경우엔 page 스캔 skip.
        eager mode로 수행 조건은 아래 2가지를 모두 만족할 때 수행
                     1. freezeLimit_txid = oldestXmin - vacuum_freeze_min_age(default 5000만)
                     2.pg_database.datfrozenid < ( oldestXmin - vacuum_freeze_table_age(default 1.5억))   
        2번 조건을 만족하면 eager mode로 수행되며 각 table의 tuple의 t_xmin 값이 1번 조건보다 작을 때 frozen 작업 진행.


수동으로 vacuum freeze 명령 수행한다면?
    vacuum_freeze_min_age  vacuum_freeze_min_age 을 0으로 설정하고 수행하는 것과 같은 효과 
    즉, vacuum 명령과 동시에 수행되고 있는 transaction이 없다면 vacuum 명령을 수행하는 txid값보다 작은 t_xmin은 모두 freeze됨.
     남는 공간 회수를 하지 않는다는 점을 제외하면 vacuum full 수행할 때의 freeze 작업과 같음.


불필요한 Clog(commit log) file을 정리
pg_database.datfrozenxid를 갱신할 때 불필요한 Clog file 및 메모리 내 clog를 정리함.
특정 txid를 기준으로 freeze작업이 진행되기 때문에 frozen된 txid를 포함하는 Clog file 및 clog는 지워져도 무방함.

 

FREEZE PROCESSING

FREEZE 작업의 2가지 방식

lazy mode

concurrent vacuum은 lazy mode로 처리되며 freeze 작업도 lazy mode임.

lazy모드에서 freeze processing은 table의 VM을 스캔해서 dead tuple이 포함된 page만 scan하는 것을 의미함.

 

lazy mode 동작 방식 정리

lazy mode로 freeze processiong을 시작할 때 freezeLimit_txid를 계산함.

계산 공식은 아래와 같음

freezeLimit_txid = oldestXmin - vacuum_freeze_min_age(default 5000만)

oldestXmin의 의미는 현재 수행중인 transaction 중 가장 오랜된 transaction을 의미함.

VACUUM을 수행할 때 현재 수행중인 transaction이 100, 101, 102이 있다고 하면 oldestXmin은 txid 100임.
만약, transaction이 수행되고 있지 않으면 oldestXmin은 vacuum을 수행하는 txid가 됨.

 

lazy mode 동작 예시

아래 그림을 예시로 설명해보겠다.

특정 table 내 3개의 page가 있고 각 page에는 3개의 tuple이 있음.

vacuum이 실행될 때 current txid가 50,002,500이고 수행중인 transaction은 없다고 가정하자.

이 경우 oldestXmin은 50,002,500되고 freezeLimit_txid를 계산해보면 2500이 된다.

freezeLimit_txid (2500) = oldestXmin(50,002,500) - vacuum_freezemin_age(50,000,000)

 

그래서 tuple에 저장된 t_xmin이 2500보다 작은 경우에  freeze 작업이 진행됨.

그러나 앞서 설명 했듯 VM(Visibility Map)에 기록된 flag가 dead tuple이 없다는 표시이면 skip하게 됨.

 

아래 그림으로 다시 와서 VACCUM 동작이 어떻게 될지 정리해보면

0번째,2번째 page에 해당하는 VM값이 0으로 dead tuple이 있다는 의미이기 때문에 vacuum이 page내 모든 tuple을 스캔하면서 dead tuple은 정리하고 tuple의 t_xmin이 2500보다 작은 경우에는 freeze 작업을 진행함.

1번째 page에는 freeze가 필요하지만 dead tuple이 없어 skip되면서 freeze작업이 진행되지 않음.

즉, tuple 1, 2,3,7,8은 freeze되고 dead tuple인 1,7은 지워지게 됨.

 

그리고 vacuum process가 끝나기 전에 작업 결과를 pg_stat_all_tables의 n_live_tup, n_dead_tup, last_vacuum, vacuum_count 등이 갱신됨.

 

 

eager mode

특정 상황일 때 eager mode로 동작함.

eager mode에서 freeze processing은 page내 dead tuple 존재 여부에 관계없이 모든 page를 스캔함.

freeze processing과 연관된 system catalogs를 갱신.

가능할 경우 clog의 불필요한 부분도 정리

 

eager mode 수행 조건

pg_database.datfrozenid < ( oldestXmin - vacuum_freeze_table_age)

pg_database.datfrozenid는 database cluster 내 각 DB에서 oldest frozen xid값을 기록하는데 각 DB의 pg_class.relfrozenxid 값 중 최솟값을 pg_database.datfrozenid 값으로 저장함.

 

eager mode 동작 예시

그림을 통해 설명할 예정.

 

전제 조건

    pg_database.datfrozenid 값은 1821 상태

    vacuum_freeze_table_age는 default 값인 150,000,000을 사용.

 

아래 그림에서 Tuple_1과 Tuple_7은 지워진 상태

2번째 page에 Tuple_10과 Tuple_11은 새로 insert됨.

VACUUM이 수행될 때 current txid = 150,002,000 이고 동시에 수행중인 transaction은 없다고 가정.

 

즉, 아래와 같다.

oldestXmin = 150,002,000

freezeLimit_txid = (150,002,000 - vacuum_freeze_table_age(50,000,000)) = 100,002,000

eager mode 수행 조건에 따라 계산하면 아래와 같고 eager mode 수행 조건이 완성됨.

1821 < (150,002,000 - 150,000,000 = 2000)

eager mode 수행에 따른 결과

    0번째 page는 이미 모든 tuple이 frozen 상태이지만 page 스캔이 진행됨.

    1번째 page는 freezeLimit_txid (100,002,000)보다 작기 때문에 모두 frozen됨.

    2번째 page는 Tuple_10은 frozen되고 Tuple_11은 frozen 대상이 아님.

 

위 그림처럼 각 table file 내 page의 tuple들이 frozen된 뒤 가장 최신인 frozenid 값으로 pg_class.relfrozenid가 갱신됨.

위 그림의 table file을 예로 들자면 freezeLimt_xid 인 100,002,000으로 pg_class.relfrozenid가 갱신됨.

즉, 위 그림의 table의 tuple 중에는 t_xmin이 100,002,000보다 작은 값이 없다는 의미임.

 

eager mode로 vacuum freeze 작업을 마무리하기 전에 pg_databae.relfrozenid 값도 필요한 경우 갱신됨.

database cluster 내 각 DB별로 pg_class.relfrozenid가 가장 최소인 값을 pg_databae.relfrozenid에 갱신함.

 

이해를 위해 아래 그림 중 (1)을 가지고 다시 설명을 해보자.

Table_1만 eager mode로 frozen되어 pg_cass.relfrozenid = 100,002,000이 되었다.

그러나 다른 table file 내 page의 tuple의  t_xmin 최소값이 1821이므로 pg_database.relfrozenid는 갱신되지 않음.

 

그림(2)의 상황은 current DB인 testdb의 모든 relations의 t_xmin이 eager mode로 frozen되었음.

그래서 pg_database.datfrozenxid가 100,002,000으로 모두 갱신되게 됨.

 

pg_class.relfrozenid와 pg_database.datfrozenid를 확인하는 방법

#### 특정 DB의 table에 대한 relfrozendxid를 확인하는 방법
psql -d postgres

SELECT n.nspname as "Schema", c.relname as "Name", c.relfrozenxid
             FROM pg_catalog.pg_class c
             LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
             WHERE c.relkind IN ('r','')
                   AND n.nspname <> 'information_schema' AND n.nspname !~ '^pg_toast'
                   AND pg_catalog.pg_table_is_visible(c.oid)
                   ORDER BY c.relfrozenxid::text::bigint DESC;
                   
   Schema   |           Name           | relfrozenxid 
------------+--------------------------+--------------
 public     | hero                     |          937
 public     | test                     |          935
 pg_catalog | pg_database              |          725
 pg_catalog | pg_foreign_table         |          722
 pg_catalog | pg_authid                |          722



#### 특정 DB의 relfrozendxid를 확인하는 방법
SELECT datname, datfrozenxid FROM pg_database WHERE datname = 'sangmudb';

 datname  | datfrozenxid 
----------+--------------
 sangmudb |          722

 

VACUUM FREEZE 수행 시 eager mode로 동작함.

VACUUM FREEZE 명령 수행 시 freeze 동작과 연관있는 파라미터인 아래 2가지를 0으로 설정한 것과 같음.

vacuum_freeze_table_age = 0

vacuum_freeze_table_age = 0

 

즉, concurrent transaction이 없다면 vacuum을 수행하는 txid 까지 frozen 시키라는 의미가 됨.

예를 들자면, vacuum freeze 명령을 수행한 txid보다 작은 t_xmin 값은 모두 frozen된 상태라는 뜻임.

 

VACUUM FULL과 유사한 이유?

concurrent transaction이 없는 상태에서  vacuum full을 수행했다면 vacuum을 수행한 txid까지 frozen 처리함.

단 VACUUM FULL은 dead tuple 제거 및 reorg 작업까지 진행

 

 

eager mode에서 freeze 작업 시 성능 개선

PostgreSQL 9.6부터 eager mode작업 시 성능 개선됨.

 

위에서 설명했던 eager mode는 9.5 version일 때를 기준으로 설명

    eager mode로 vacuum freeze 수행 시 모든 page를 scan하면서 frozen 작업을 진행

 

9.6부터 동작 방식 변경

     VM에 page내 tuple이 모두 frozen되었는지 판단하는 flag가 하나 추가함.

     그래서 page 내 모든 tuple이 모두 frozen 상태이면 VM 내 값이 1로 처리되며 eager mode로 freeze 작업을 수행하더라도 해당하는 page는 skip하고 넘어가게 됨.

 

 

 

불필요한 CLOG file 정리

Clog(Commit log)는 txid 정보와 transaction 상태 정보를 기록한 파일이라고 MVCC 관련 내용 설명 시 진행함.

https://lsmdd.tistory.com/108

 

08. PostgreSQL - commit log

요약transaction의 4가지 상태인 in_progress, commited, aborted, sub_commited 중에 하나를 Commit log(Clog)에 기록.clog는 shared memory에서 할당되고 transaction 처리 전반에 걸쳐 사용됨.DB가 shutdown되거나 checkpoint가 발

lsmdd.tistory.com

 

pg_database.datfrozenxid를 갱신할 때 불필요한 Clog file을 정리하기 위해 시도함.

 

아래 그림으로 간단하게 설명해보자

최소 pg_database.datfrozenxid가 포함된 clog file은 0002임을 알 수 잇다.

따라서 0000,0001에 존재하는 txid는  database cluster 내에서 모두 frozen 상태이기 때문에 지워져도 무방함.

 

psql postgres -c "SELECT datname, datfrozenxid FROM pg_database"

  datname  | datfrozenxid 
-----------+--------------
 postgres  |          722
 template1 |          722
 template0 |          722
 testdb    |          722


ls -la $PGDATA/pg_xact/
-rw-------  1 postgres postgres 8192 Dec 23 22:44 0000

 

 

'PostgreSQL' 카테고리의 다른 글

17. PostgreSQL - vacuum full  (3) 2024.12.25
16.PostgreSQL - autovacuum  (4) 2024.12.25
14. PostgreSQL - Visibility Map  (1) 2024.12.22
13. PostgreSQL - VACUUM 내부 동작 과정  (2) 2024.12.21
11. PostgreSQL - Lost updates  (4) 2024.12.21