반응형

PostgreSQL에서의 Vacuum 하는 역할 ??

 

- 공간 사용

- 트랙잭션 ID 관리

- 통계정보 갱신

- 인덱스 검색 성능 향상

 

명령어

• 표준 Vacuum :

• Vacuum 수행 중에도, SELECT, DML 작업이 가능.

단순히 사용 가능한 공간을 Free Space Map에 반환.

• 이전 vacuum 작업 이후 부터, 변경된 페이지들만 대상으로 Vacuum을 진행

표준 vacuum 명령이라도 가장 뒤쪽의 페이지부터 연속된 페이지 존재 경우, 해당 페이지를 삭제 하여 Disk 공간을 확보 한다.

 

• Vacuum Full :

• 테이블에서 사용할 수 있는 데이터만을 따로 모아서, 새로운 공간에 저장하는 방식

  --> create as select 작업이라고 생각하면 . 그래서 공간이 필요하고, 기존의 테이블 사이즈보다 작아짐.

   (디스크 상의 여유 공간이 있어야 작업이 가능 함)

• 이로 인하여 시간도 오래 걸리며, 수행되는 테이블에 대한 exclusive Lock이 발생 됨.

• 디스크 상의 여유 공간이 확보 됨.

 

파라미터 (postgresql.conf)

Parameter :

autovacuum                         

autovacuum_analyze_scale_factor    

autovacuum_analyze_threshold       

autovacuum_freeze_max_age          

autovacuum_max_workers             

autovacuum_multixact_freeze_max_age

autovacuum_naptime                 

autovacuum_vacuum_cost_delay       

autovacuum_vacuum_cost_limit       

autovacuum_vacuum_scale_factor     

autovacuum_vacuum_threshold        

autovacuum_work_mem                

log_autovacuum_min_duration

 

 

Create table or Alter table command :

autovacuum_enabled

autovacuum_vacuum_threshold

autovacuum_vacuum_scale_factor

autovacuum_analyze_threshold

autovacuum_analyze_scale_factor

autovacuum_freeze_max_age

vacuum_freeze_min_age

autovacuum_vacuum_cost_delay

autovacuum_vacuum_cost_limit

 

CREATE TABLE test ( id int ) with (autovacuum_enabled=TRUE) ;

select relname, reloptions from pg_class

where relname = 'test' ;

 

relname |reloptions              |

--------|------------------------|

test    |autovacuum_enabled=true |

 

ALTER   TABLE test  SET (autovacuum_enabled = FALSE);

select relname, reloptions from pg_class

where relname = 'test' ;

 

relname |reloptions               |

--------|-------------------------|

test    |autovacuum_enabled=false |

 

 

1. 공간 사용

PostgreSQL은 Update가 발생 할 경우 기존 Row 데이터 영역의 데이터를 변경 하지 않고, 새로운 데이터를 insert 한다.

이는 다중 버전 동시성 제어(Multiversion Concurrency Control, MVCC)를 구현하기 위함이며, update나 delete의 대상이 되었던 이전 데이터를 다른 세션에서 사용 중일 수 있으므로, Update나 Delete가 끝난 이후에도 해당 공간을 삭제 하지 않는다. (MVCC 트랜잭션 ID 기반으로 한다.)

새로운 Insert update 발생 경우 PostgreSQL FSM(Free Space Map)에서 사용 가능한 공간을 할당 받아서 데이터를 저장한다.

Update Delete 의하여 데이터는 삭제 되었으나, 실제 물리적인 공간을 차지하고 있는 dead tuple들은 Vacuum 명령을 이용하여 FSM 반환을 주어야 한다.

Vacuum명령을 이용하여 사용되지 않는 공간을 정리하지 않을 경우, insert update 빈번히 발생하는 테이블의 크기가 dead tuple 인하여 정상적으로 있다.

 

Free Space Map (FSM)

- 8.4 이전

PG Startup shared memory 구성(pg_fsm.cache)되며, shutdown되거나 instance crash 경우 분실 된다.

max_fsm_pages, max_fsm_relations 파라미터로 구성 .

 

- 8.4 이후

Disk 8k 짜리 파일로 관리. shared_buffer cache 된다.

vacuum 명령 수행 생성 된다. (매번 생성)

Binary tree 형태의 파일로 존재

max_fsm_pages, max_fsm_relations 파라미터 사용 안함.

    

 

Visibility Map(VM)

Free Space Map 사용 가능한 공간의 정보가 저장되는 map 반면, Visibility Map(VM) 페이지 안에 dead tuple 없는 페이지를 나타내는 Map이다.

Vacuum수행 해당 페이지를 읽어야 하는지 말아야 하는지 판단 하는데 사용되며, Only index 스캔으로 쿼리에 대한 결과를 가져올 참조되는 파일이다.

테이블의 하나의 페이지당 하나의 Bit 표현하며, 1 의미하는 것은 페이지의 모든 tuple들은 모든 트랜잭션에서 보여진다는 뜻이다.

다른 말로 표현해 보면 모든 트랜잭션에서 있다는 것은, 해당 페이지의 모든 데이터가 변경이 없는 상태란 뜻으로 해석 수도 있다.

페이지에 insert, update, delete tuple 있으면 해당 페이지의 bit 지워 진다.

그래서 변경이 없는 페이지(bit 1 설정 ) 이후 vacuum 수행 해당 페이지는 skip 된다. 연속된 32개의 all-visible page 있으면, vacuum Skip한다.

최초 vacuum 명령으로 생성되고, vacuum 명령으로 update 된다.

 

 

2. 트랜잭션 ID관리

PostgreSQL에서는 하나의 tuple 개의 트랜잭션 ID(XID) 갖는다.

tuple Insert 되었을 해당 tuple 이후 트랜잭션에서 있어야 하므로 xmin 이라는 트랜잭션 ID값을 가지게 된다.

이후 해당 tuple update 되거나 delete 되면 해당 시점의 트랜잭션 ID xmax값이 된다. (xmin : created / xmax : expired)

그래서 다른 세션에서 해당 데이터를 SELECT 할때 xmin ~ xmax 사이의 트랜잭션 ID 가진 세션이 엑세스를 경우는 데이터가 보여지고, 사이에 없는 트랜잭션 ID 가진 세션이 엑세스를 경우 보여지지 않는다. (MVCC 트랜잭션 ID 기반으로 한다.)

 

 

PostgreSQL에서는 트랜잭션 ID 4billion(40)개를 사용할 있다. 이중 20억개를 (older) , 20억개를 (newer) 하여 사용하며, 40억개를 사용하면 다시 1부터 트랜잭션 ID 부여해서 사용한다.

만약 테이블의 tuple 트랜잭션 ID 99999 가진 시점에 insert , 다량의 트랜잭션이 발생하여서 트랜잭션 ID 사용한 , 다시 1부터 트랜잭션 ID 사용되어 지는 시점이라고 ,   트랜잭션 ID 1 사용 중인 세션은 xmin 99999 데이터를 조회할 수가 없다.

분명 이전 데이터 이기에 조회가 가능해야 하지만, 현재 자신의 트랜잭션 ID보다 크므로 조회를 없게 된다.

이는 문제를 발생 시킬 있으므로, 해당 tuple freeze 마크(FrozenTransactionId) 주면, freeze tuple 항상 어떤 트랜잭션 ID 보다 older 되어서 항상 조회를 있게 된다.

자동으로 freeze 수도 있고, 변화가 없는 테이블일 경우 명시적으로 analyze freeze 명령을 이용하여 FREEZE 시킬 있다.

 

3. Autovacuum

vacuum, freeze, analyze명령을 자동으로 수행해 준다.

Luncher 프로세스와 Worker 프로세스로 구성되어 있으며, autovacuum_max_workers 파라미터 값으로 조정.

launcher 프로세스는 autovacuum_naptime()값이 지날 마다, 각각의 데이터 베이스에 Worker 프로세스를 하나씩 시작 시킨다. 시작된 Worker프로세스는 insert, update, delete 테이블들을 check 해서 analyze 필요한지 체크 한다. (track_counts=true 되어 있어야 ), Temporary table autovacuum 수행되지 않음.

Autovacuum 오브젝트 사이즈를 이진 않는다.

 

scale_factor threshold 파라미터는 autovacuum 자주 돌아서, autovacuum 테이블에 적은 부분만 vacuum 있도록 설정 하기 위한 파라미터들이다.

데이터 베이스 레벨에서 설정을 수도 있고, 테이블 별로 설정을 수도 있다.

 

파라미터

log_autovacuum_min_duration

autovacuum 결과를 log 파일에 저장할 여부를 결정 (-1 :not logged, 0: log all, 시간: 해당 시간 이상 autovacuum 수행된 것만 log)

autovacuum_vacuum_threshold

이전 vacuum이후 update delete

autovacuum_analyze_threshold

이전 vacuum이후 insert, update, delete

autovacuum_vacuum_scale_factor

얼마나 변경이 되어야지 autovacuum 수행될지 여부 결정(예를 들어서 0.01이면 autovacuum 돌기 전에 테이블 사이즈의 1% 변해야 )

autovacuum_analyze_scale_factor

얼마나 변경 되어야지 auto analyze 수행될지 여부 결정

 

auto vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples      (number of tuples = pg_class.reltuples)

auto analyze threshold = analyze base threshold + analyze scale factor * number of tuples       (number of tuples = pg_class.reltuples)

 

Autovacuum 수행 되어야 오브젝트 선정이나, Autovacuum 일을 하면서 얼마나 자원을 사용하게 되는지는 다음의 파라미터로 설정 한다.

 

파라미터

autovacuum_naptime

autovacuum 대상이 되는 오브젝트를 선정하는 주기(?). 해당 시간이 되면 launcher 프로세스가 번에 하나의 데이터베이스를 처리 있도록 worker프로세스를 하나씩 깨운다. 깨어난 worker프로세스는 대상 오브젝트들이 있는지 확인

autovacuum_vacuum_cost_limt

autovacuum 대상이 되는 오브젝트를 autovacuum할때 시스템 자원을 얼마나 사용하면서 autovacuum 수행하게 설정하는 limit.

동시에 여러 worker 수행이 되고 있을 수행되고 있는 모든 worker 자원 사용량에 대한 제한이다.

autovacuum_vacuum_cost_delay

autovacuum 수행하다가 cost_limt값을 초과할 경우, cost_delay 설정 시간 동안 쉬었다가 다시 autovacuum 수행

 

vacuum 항상 수행중이라면 maintenance_work_mem 작게 설정 되어 있는지 확인이 필요 . 기본적으로 시스템 메모리 1G 50M 계산 하면 .

vaccum worker 프로세스 마다 maintenance_work_mem 메모리를 사용하게 되므로, 지나치게 크게 설정이 되어 있으면 autovacuum_naptime마다 worker 수행될

해당 메모리가 없으면 메모리 부족 메세지를 출력시킬 있다.

 

표준 Vacuum 수행 시는 이전 Vacuum 작업 이후 변경된 페이지들에 대해서만 작업을 한다. 그러나 다음의 경우는 표준 Vacuum이라도 Full Scan 발생

1. relfrozenxid값이 vacuum_freeze_table_age 보다 경우 모든 테이블의 데이터를 읽어서 Frozen Transaction Id tuple 설정

2. vacuum freeze 명령 수행

위의 두가지 경우 이외에도  XID wrap around 방지 하기 위하여  autovacuum 수행 테이블에 대한 Full Scan 발생 한다.

 

autovacuum 수행 되어야 하는데 무슨 이유에서 autovacuum 수행되지 않을 경우, 다음과 같은 메시지를 출력 한다.

 

WARNING:  database "mydb" must be vacuumed within 177009986 transactions

HINT:  To avoid a database shutdown, execute a database-wide VACUUM in "mydb".

 

위와 같은 메시지가 출력 경우, 서버를 중지하고, 관리자 모드(postgres --single -D /..... ) 서버를 실행해서 수동으로 vacuum 수행해 줘서 datfrozenxid 까지 변경을 시켜 줘야 한다.

그런데 위의 경고를 무시하고 있다가 트랜잭션 XID wrap around 경우 다음과 같은 에러 메시지가 출력 된다.

 

ERROR:  database is not accepting commands to avoid wraparound data loss in database "mydb"
HINT:  Stop the postmaster and use a standalone backend to VACUUM in "mydb".

 

 

4. Age

age 개념 (http://oraschool.tistory.com/70)

 

PostgreSQL에서는 Object 생성되면, 생성되는 시점의 트랜잭션 ID 가지고 Object relfrozenxid 설정 하고, age 1 된다.

생성 이후 데이터베이스에 트랜잭션이 하나씩 발생할 때마다(해당 Object 상관이 없어도 데이터 베이스 전체로 따짐) 모든 Object들의 나이가 1 증가가 된다.

Age 가지고 트랜잭션 아이디가 wrap around 되었을 때도, 데이터를 있도록 데이터들을 freeze하는데 사용 된다. 그래서 파라미터들이 freeze라는 단어를 포함하고 있음.

Autovacuum_enabled false 되어 있어도, XID Wrap Around용으로 수행되는 autovacuum 수행이 된다.

 

autovacuum_freeze_max_age값은 Object나이가 설정 값에 도달하면 autovacuum 수행한 vacuum_freeze_min_age 파라미터 값을 참조하여 젊게 주는 역할을 한다.

 

예를 들어보면 ,

현재 트랜잭션 ID 100 시점에 테이블 A 생성 했다고 하면,

 

autovacuum_freeze_max_age = 1000  (자동으로 autovacuum수행 나이 )

vacuum_freeze_min_age = 100         

 

autovacuum 수행

relfrozenxid =  currentXID - vacuum_freeze_min_age

age            =  currentXID - Object relfrozenxid

  

위의 그림을 설명해 보면 실제 A테이블은 XID 100 시점에 생성이 되어서, XID 1100 시점에 autovacuum 대상이 되어 autovacuum 수행하게 된다.

그러면 A테이블은 XID 1000 시점에 생성된 것처럼 relfrozenxid 1000으로 변경이 되고, 나이는 100으로 줄어든다.

말은 테이블 A 마치 트랜잭션 1000 시점에 생성 처럼 다시 태어난다(?) 젊어진다(?)

 

최초 생성 -------> autovacuum_freeze_max_age 값만큼 트랜잭션 증가 1 autovacuum 발생

             -------> 이후 autovacuum_freeze_max_age - vacuum_freeze_min_age 만큼의 트랜잭션 수행 계속 autovacuum 발생

             -------> age 점점 증가 하다가, vacuum_freeze_table_age 되면 해당 테이블의 tuple 모두 읽어서 freeze 시킨다.

 

pg_class.relfrozenxid

해당 테이블에 vacuum작업을 진행 했던 트랜잭션 ID

pg_database.datfrozenxid

해당 데이터베이스 안의 테이블들의 relfrozenxid 가장 오래된

age

현재 트랜잭션 XID relfrozenxid 값을 가지고 계산한 나이

 

- 1M 이상되는 것들 중에서 나이가 가장 오래된 20 테이블 목록 리스트      

 

SELECT c.relname, age(relfrozenxid) as age,

       pg_size_pretty(pg_table_size(oid)) as table_size ,

       p.setting::numeric - age(c.relfrozenxid) before_autovacuum

FROM   pg_class c , (SELECT setting FROM pg_settings WHERE name = 'autovacuum_freeze_max_age' ) p

WHERE  c.relkind = 'r' and pg_table_size(c.oid) > 1024000

ORDER BY age(c.relfrozenxid) DESC LIMIT 20;

 

relname    |age     |table_size |before_autovacuum |

-----------|--------|-----------|------------------|

pg_proc    |1383701 |1128 kB    |198616299         |

pg_rewrite |1383701 |1120 kB    |198616299         |

test       |119     |48 MB      |199999881         |

 

필요시 vacuum freeze pg_proc ;

 

- 데이터베이스의 가장 오래된 나이

SELECT datname, age(datfrozenxid) FROM pg_database;

 

datname   |age     |

----------|--------|

template1 |1383701 |

template0 |1383701 |

postgres  |1383701 |

edb       |1383701 |

tpch      |1383701 |

tpcc      |1383701 |

qatest    |1383701 |

 

  

 

relkind values

r = table,

i = index,

S = sequence,

v = view,

m = materialized view,

c = composite type,

t = TOAST table,

f = foreign table

 

반응형

+ Recent posts