buffer manager는 shared memory와 DB 스토리지 간 data 전송을 관리함.
그래서 buffer manger가 DB 성능에 큰 영향을 미칠 수 있음.
buffer manager 구조
- PostgreSQL에서 모든 data files의 각 page 정보를 가지고 고유한 tag값을 생헝하는데 그것을 buffer tag라고 함.
- buffer tag를 만들 때 사용되는 구성 요소
- specOid : page를 포함하는 relation이 속한 tablespace의 OID
- dbOid : page를 포함하는 relation이 속한 database의 OID
- relNumber : page를 포함하는 relation file의 number
- blockNum : relation file의 page number
- forkNum : 어떤 relation type인지 기록( 0 : tables, 1: FSM , 2: VM)
buffer table layer
- table,index,FSM,VM과 같은 data file page가 저장되는 공간
- buffer pool은 simple arrary로 구현되어 있으며 array의 각 slot은 8KB이며 page size와 같음.
- buffer pool arrary의 각 index는 buffer_id로 불림.
buffer descriptors layer
- freelist라고 불리는 linked list로 구성되어 있음.
- BufferDesc 구조체를 확인하면 어떤 데이터가 저장되는 지 알 수 있음.
- 그 중 일부만 정리
- tag : buffer pool slot에 저장된 page의 buffer_tag를 기록하는 영역
- buf_id : descriptors를 식별하기 위해 사용
- descriptor의 상태값
- empty : buffer pool slot에 data file page가 없을 때 상태값
- pinned: buffer pool slot에 data file page가 있고 page에 접근하는 프로세스가 있을 때 상태값
- unpinned: buffer pool slot에 data file page가 있으나 page에 접근하는 프로세스가 없을 때 상태값
buffer table
- 위 그림처럼 buffer table은 세 부분으로 나눠짐
- hash function : buffer tags를 hash bucket slot에 mapping할 때 hash function을 사용
- hash bucket slots
- hash bucket slot이 buffer pool slot보다 크더라도 충돌이 발생할 수 있어서 linked list로 체인형태로 구현
- 위 그림에서 보는 것처럼 data entries를 hash function을 수행한 결과가 같은 bucket으로 나온다면
linked list 형태로 연결해서 저장
- data entries
- data file내 page 정보로 만들어진 buffer tags
- page의 metadata 정보를 저장하는 descriptor의 buffer_id
- 위 그림에서 data entries (Tag_C, id =1)을 설명
- buffer_id 1인 buffer descriptor는 data file의 page 메타 정보를 가지고 만들어진 Tag_C를 저장.
- 이걸 좀 더 풀어서 써보자.
- buffer descripotr 1번 arrary에는 buffer pool slot에 저장된 page의 메타정보를 가지고 만든 Tag_C 정보를 저장함.
첫 페이지를 buffer pool에 load하는 과정
아래 그림으로 설명
(1) descriptor 영영에서 freelist 상단에 빈 descriptor를 검색하고 상태값을 pin으로 변경
(2) data file 내 page 정보를 가지고 만든 tag와 검색된 descrptor의 buffer_id를 맵핑시켜서 buffer table에 data entry를 insert
(3) 스토리지에서 필요한 page를 buffer pool slot으로 load
(4) 검색된 descriptor에 buffer pool slot에 load된 page의 metadata를 저장.
이후 page가 load되는 방식은 유사한 방식으로 처리됨.
freelist에서 검색된 descriptors는 page의 metadata를 저장.
일단 다시 한 번 사용된 descriptors는 freelist로 다시 반환되지는 않음.
그러나 freelist로 다시 반환되고 상태가 empty로 바뀌는 case가 있음.
1. table과 index가 drop될 때
2. database가 drop될 때
3. VACUUM FULL 명령으로 table과 index가 cleanup될 때
buffer manger locks
buffer mangager는 다양한 목적으로 lock을 사용하며 관련된 내용은 아래 내용 참고
BufMappingLock - shared mode or exclusive mode로 획득
content_lock - shared mode or exclusive mode로 획득
https://www.interdb.jp/pg/pgsql08/03.html
8.3. Buffer Manager Locks :: Hironobu SUZUKI @ InterDB
Until PostgreSQL version 9.4, BufMappingLock was split into 16 separate locks by default.
www.interdb.jp
backend process가 page를 읽는 방법
(1) table or index page를 읽는 중일 때 backend process는 data file 내 page의 정보를 이용해 buffer tag를 만들고 buffer manager에서 요청을 보냄.
(2) buffer pool에 요청된 page가 있는 경우, buffer manger는 요청된 page의 buffer_id를 리턴
없는 경우, buffer manager는 스토리지에서 buffer pool slot 중 하나로 page를 load하고 slot의 buffer_id를 리턴
(3) backend process는 buffer pool에 buffer_id slot을 접근해서 원하는 page를 읽음.
PostgreSQL에서 사용하는 page 교체 알고리즘
buffer pool은 유한하기 때문에 결국 load되고 미사용 중인 page는 교체되어야 함.
PostgreSQL 8.1부터 clock sweep을 사용하며 LRU 알고리즘보다 효율적이고 간단한 알고리즘임.
NFU(Not Frequently Used)의 변형으로 overhead가 낮음.
buffer pool로 원하는 page가 어떻게 로드되는지 알고 싶고
clock sweep 알고리즘에 대해 자세히 알고 싶다면 아래 페이지를 참고
https://www.interdb.jp/pg/pgsql08/04.html
8.4. How the Buffer Manager Works :: Hironobu SUZUKI @ InterDB
(2) Select a victim buffer pool slot using the clock-sweep algorithm. Obtain the old entry, which contains the buffer_id of the victim pool slot, from the buffer table and pin the victim pool slot in the buffer descriptors layer. In this example, the buffe
www.interdb.jp
flush dirty page
backend process가 buffer pool에서 page를 수정할 때 수정된 page가 스토리지로 아직 fulsh되지 않은 상태를 dirty page라고 함.
dirty page는 결국 스토리지로 flush되어야 하고 background process인 checkpointer와 background writer에 의해 flush됨.
direct I/O 기능 도입 가능성 PostgreSQL 15이하 version에서는 direct I/O 기능이 없었음. PostgreSQL 16에서 developer option으로 debug_io_direct가 추가되었으며 추후 공식적으로 direct I/O 기능을 제공할 가능성이 있음. |
checkpointer의 역할
checkpoint가 시작될 때마다 WAL segment file에 checkpoint record를 기록하고 dirty page를 flush함.
background wrtier의 역할
DB에 최소한의 영향을 끼치도록 dirty page 조금씩 나눠서 계속 flush함.
bgwriter_delay(defautl 200ms) 마다 최대 bgwriter_lru_maxpages(default 100 buffers)를 flush함.
'PostgreSQL' 카테고리의 다른 글
22. PostgreSQL - query processing (1) | 2024.12.29 |
---|---|
21.PostgreSQL - WAL(Write Ahead Log) (3) | 2024.12.28 |
19. PostgreSQL - index-only scans (3) | 2024.12.25 |
18. PostgreSQL - Heap-Only Tuples(HOT) (1) | 2024.12.25 |
17. PostgreSQL - vacuum full (3) | 2024.12.25 |