오픈소스 RDBMS로 많이 사용되는 Postgresql에서 Vacuum과 Autovacuum의 동작방식을 알아보도록합니다.
Vacuum이란?
Vacuum은 한마디로 휴지통 비우기와 같습니다.
운영체제에서 파일을 삭제하면 지워지지만 휴지통으로 옮겨집니다. 휴지통으로 옮겨진 파일은 보이진 않지만 디스크 용량을 차지하고 있습니다. Postgres도 이와 같습니다. delete
된 데이터는 삭제되었어도 실제로 차지하는 공간은 그대로 남아있습니다. 이 공간을 Bloat
라고 부르고 이런 공간을 차지하는 데이터를 dead tuple
이라고 부릅니다. 참고로 Postgres에서 update는 insert와 delete를 수행하기 때문에 update나 delete된 데이터는 dead tuple
이 됩니다.
휴지통에 옮겨진 파일은 휴지통 비우기를 해야만 데이터가 삭제되고 디스크 공간으로 반환됩니다. Postgres에서도 이처럼 dead tuple
을 삭제하여 Bloat
의 공간을 여유공간으로 바꾸어 주는것을 Vacuum
이라고 합니다. (진공청소기라는 의미지만 개념상 OS의 휴지통과 유사하다고 생각합니다. 휴지통 비우기와 Vacuum에서 데이터의 메모리 구조는 다르겠지만 프로세스가 비슷하여 비유로 차용하였습니다)
Vacuum은 Non-blocking작업입니다.
데이터를 읽고 쓰는데 영향을 주는 Lock을 Exclusive락이라고 합니다. Vacuum은 데이터에 Exclusive락을 잡지 않아서 트렌젝션에서 데이터를 읽고 쓰는데 영향을 주지 않습니다. 이를 Non-blocking이라고 부릅니다. 따라서 여러 트렌젝션에서 쓰기작업을 수행하는 테이블에도 vacuum을 병렬로 수행할 수 있습니다. 하지만 vacuum이 실행되면 많은 I/O 트래픽을 유발하기 때문에 다른 트랜젝션에 성능을 나쁘게 만듭니다.
Dead tuple → Free space
참조되지 않는 Dead tuple은 vacuum을 통해 삭제되고 비워진 공간은 예비공간으로 남게됩니다. Database마다 정해진 격리수준이 있고, 격리수준에 따라 지워진 데이터더라도 아직 트랜젝션에서 참조가 될 수 있습니다. 하지만 참조가 없는 데이터는 Vacuum의 대상이 됩니다. Vacuum으로 깨끗해진 데이터 공간은 disk로 즉시 반환되지 않고 신규데이터를 위한 예비공간으로 남아있게 됩니다.
테이블의 PK기준 앞이나 중간 일부분이 지워지면 예비공간으로 남아 있습니다. 하지만, 테이블 전체가 지워지거나 특정 PK값 이후로 데이터가 모두 삭제된 경우에는 예비공간으로 남지 않고 파일 시스템으로 반환됩니다. 이 예비공간을 모두 파일시스템으로 반환하고 데이터를 재구성하고 싶으면 VACUUM FULL
을 수행할 수 있습니다. 마치 윈도우의 디스크조각모음에 거칠게 비유할 수 있습니다.
Autovacuum이란?
Autovacuum = Vacuum + Analyze
Autovacuum
은 dead tuple
이 차지하던 공간을 사용가능한 공간으로 변경해주는 vacuum작업과 테이블의 통계정보를 갱신하는 analyze 작업을 동시에 수행합니다. auto-
이름에서 알 수 있듯 자동으로 실행되며 실행되는 기준을 가지고 있습니다. 이 기준을 threshold
(문턱값) 이라고 부릅니다. 그리고 두 가지 작업을 동시에 수행하기 때문에 실행기준 또한 vacuum과 analyze 별도로 지정해 줄 수 있습니다.
Threshold = 전체 데이터 수 * 비율 + 최소문턱값
threshold
를 계산하는 식은 전체 데이터 수 * 비율 + 최소문턱값
으로 구할 수 있습니다. 식 앞부분인 전체 데이터 수 * 비율
은 dead tuple이 전체 데이터에서 몇 퍼센트가 될 때 vacuum이 실행될 것인지 의미합니다. 식 뒷부분인 최소문턱값
은 dead tuple
이 최소한 몇개 이상될 때 실행될 것인지 고정값을 의미합니다.
vacuum과 analyze가 실행되는 수식은 동일하고 설정하는 변수만 다릅니다.
-- vacuum threshold
autovacuum_vacuum_scale_factor * number of tuples + autovacuum_vacuum_threadhold -- analyze threshold
autovacuum_analyze_scale_factor * number of tuples + autovacuum_analyze_threshold
해당 값은 전역설정이 가능하며 테이블별 상세설정도 가능합니다. 글로벌 설정은 간편하지만 테이블에 따라 볼륨이 다르기 때문에 튜닝을 위해서는 테이블별 설정이 도움이 됩니다.
-- 전역 설정
alter system set autovacuum_vacuum_scale_factor = 0.1;
-- 확인 쿼리
select * from pg_settings where where name = 'autovacuum_vacuum_scale_factor';-- 개별설정
alter table {{schema.table_name}} set (autovacuum_vacuum_scale_factor=0.1);
-- 확인쿼리
select relname, reloptions from pg_class where relname={{table_name}};
-- 설정 초기화
alter table {{schema.table_name}} reset (autovacuum_vacuum_scale_factor);
Postgres를 메인 DB로 사용하게 되면서 Vacuum 이슈를 겪었는데 처음 개념을 잡기 어려워 내용을 정리해보았습니다. 간략히 정리한 이 문서가 도움이 되었으면 좋겠습니다. 🤗 이후엔 Postgres 튜닝가이드 문서로 찾아오겠습니다.
참고문서
- https://americanopeople.tistory.com/370
- https://nrise.github.io/posts/postgresql-autovacuum/?fbclid=IwAR3axiM0p1cohJVV-rz0Mw-HUaU0vCsP8gi5M8QqN6FXhMWQQfKa38osRS0
- https://www.enterprisedb.com/postgres-tutorials/how-tune-postgresql-memory
- https://www.percona.com/blog/2018/08/10/tuning-autovacuum-in-postgresql-and-autovacuum-internals/