01. PostgreSQL 메모리 구조
- PostgreSQL 은 데이터를 읽고 쓰는 과정에서 공유 메모리 영역인 Shared Buffer 에 있는 메모리를 사용한다.
- 자주 사용되는 데이터(페이지) 를 메모리에 올려 디스크 I/O를 줄이고 빠른 성능 향상을 유도한다.
02. OS Cache Page 활용
- PostgreSQL 은 데이터베이스 성능 향상을 위해 OS 파일 시스템 Cache 를 활용합니다. 따라서 데이터가 Shared Buffer에 있다면 OS Cache 에도 있을 수 있습니다. 이를 활용하여 WAL, 테이블, 인덱스 모두 OS 캐시를 거쳐 디스크에 기록됩니다.
- 조회 할 데이터가 Shared Buffers 에 없다면, OS 캐시에 데이터를 찾고 있다면 참조, 없다면 최종적으로 디스크에 읽어 Shared Buffers 와 OS 캐시에 올리는 구조입니다. (PostgreSQL은 기본적으로 Bufferd I/O 방식)

- Linux 의 경우 OS 캐시에서 페이지 단위는 4K 입니다. PostgreSQL 페이지는 8K
- 많은 양의 페이지는 전체 스캔 시 느릴수 밖에 없게 되고, 페이지 hit 비율도 떨어질 수 있다.
- 페이지 단위가 커질수록 기존(4K)보다 훨씬 적은 페이지로 페이지 당 담을수 있는 데이터 양이 늘어나기 때문에, 부하를 줄이고 조회 성능과 메모리 관리가 용이합니다.
- 이와 같이 OS 캐시 페이지 단위를 늘리는 방법이 hugepage 입니다.
03. hugepage 설정
적용 전
# 현재 Hugepage 당 할당 메모리 확인
[root@ztest-db2 /]# cat /proc/meminfo | grep Hugepagesize
Hugepagesize: 2048 kB
# Hugepage 전체 갯수 확인
[root@ztest-db2 ~]# grep huge /etc/sysctl.conf
vm.nr_hugepages = 512
# 2048 kB * 512 = 약 1GB 정도가 할당되어 메모리에 올라가 있는 모습
[root@ztest-db2 /]# free -m
total used free shared buff/cache available
Mem: 7805 1855 3298 187 2652 5571
Swap: 2048 1 2046
적용 후
[root@ztest-db2 /]# cat /proc/meminfo | grep Hugepagesize
Hugepagesize: 2048 kB
# 실제 shared_buffer 사이즈 보다 5~10% 여유롭게 잡는 것이 좋다.
[root@ztest-db2 /]# grep huge /etc/sysctl.conf
vm.nr_hugepages = 1024
# 변경 적용
[root@ztest-db2 /]# sysctl -p
# 2048 kB * 1024 = 약 2GB 정도가 할당되어 메모리에 올라가 있는 모습
[root@ztest-db2 /]# free -m
total used free shared buff/cache available
Mem: 7805 2876 2277 187 2651 4549
Swap: 2048 1 2046
03. THP(Transparent Huge Pages) 끄기
- Linux 의 경우 OS 상의 메모리 사용 패턴에 따라 동적으로 HugePage 를 맞춰주는Transparent Huge Pages (THP) 가 있는데 해당 기능을 활성화 할 경우 오히려 성능 저하를 유발하기 때문에 설정을 never 로 바꾸는 것이 좋다.
- 즉 Linux 커널이 4KB 페이지를 모아서 Hugepage 로 실시간으로 자동 변환하는 과정에서 메모리를 할당,해제,재배치 하는 동안 해당 프로세스가 멈추게 된다 그러면, 트랜잭션 대기, I/O 증가, Replication lag 증가 등 DB에 치명적임
[root@ztest-db2 /] vi /etc/sysconfig/grub
sudo grubby --update-kernel=ALL --args="transparent_hugepage=never"
[root@ztest-db2 /] sudo reboot
# 런타임 THP 상태가 never 인지
[root@ztest-db2 /] cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
[root@ztest-db2 /] cat /sys/kernel/mm/transparent_hugepage/defrag
always defer defer+madvise [madvise] never
# THP 할당 값 0 kB 확인
[root@ztest-db2 /] cat /proc/meminfo | grep AnonHugePages
AnonHugePages: 0 kB
04. PostgreSQL 에서 Hugepage 설정
- Hugepage 는 OS 페이지(4KB) 와 다르게 전용 메모리 영역으로써 부팅 시 할당이 되어 지기 때문에
PostgreSQL 기동시 공유 메모리(Shared_Memory) 및 기타 메모리 영역에 사용하기 위해 할당되는 메모리가 OS Hugepage 영역에 그대로 매핑된다
[tarandb@ztest-db2 tarandb]$ psql -c "show huge_pages"
huge_pages
------------
try
(1 row)
# huge_pages = try # 기본값 (리눅스 기준)
# huge_pages = off # 아예 HugePages 안씀
# huge_pages = on # HugePages 반드시 써야 함(없으면 기동 실패)
참고로 PostgreSQL 기동 중지상태이더라도 OS Hugepage 할당 메모리는 줄어들지 않고 사용하지 않아도 메모리를 반환하지 않는다
[tarandb@ztest-db2 tarandb]$ pg_ctl restart
[tarandb@ztest-db2 tarandb]$ psql -c "show huge_pages"
huge_pages
------------
on
(1 row)
# Hugepage 할당 여부 확인
[root@ztest-db2 /]# cat /proc/meminfo | grep Huge
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
FileHugePages: 0 kB
HugePages_Total: 1024
HugePages_Free: 908
HugePages_Rsvd: 540 # PostgreSQL이 540 * 2MB = 1080MB 이상을 Hugepage 로 매핑해서 사용 중
HugePages_Surp: 0
Hugepagesize: 2048 kB
[root@ztest-db2 /]# ps -ef | grep postgres
tarandb 916 1 0 16:13 ? 00:00:01 /app/tarantuladb/v16/bin/postgres
tarandb 917 916 0 16:13 ? 00:00:00 postgres: logger
tarandb 918 916 0 16:13 ? 00:00:00 postgres: checkpointer
tarandb 919 916 0 16:13 ? 00:00:00 postgres: background writer
tarandb 921 916 0 16:13 ? 00:00:00 postgres: walwriter
tarandb 922 916 0 16:13 ? 00:00:00 postgres: autovacuum launcher
tarandb 923 916 0 16:13 ? 00:00:00 postgres: archiver
tarandb 924 916 0 16:13 ? 00:00:00 postgres: logical replication launcher
root 2501 994 0 16:21 pts/1 00:00:00 grep --color=auto postgres
# PostgreSQL PID 메모리 매핑 정보 확인
[root@ztest-db2 /]# grep -i huge /proc/916/smaps
AnonHugePages: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
...
7cc7dea00000-7cc830a00000 rw-s 00000000 00:10 17904505 /anon_hugepage (deleted)
AnonHugePages: 0 kB # THP 사용 X
Shared_Hugetlb: 55296 kB # 정적 Hugepages 사용
Private_Hugetlb: 182272 kB # 정적 Hugepages 사용
05. PostgreSQL Hugepage 트러블 슈팅
- Hugepage 설정 후 기동 시 Shared_buffer 사이즈 만큼 Hugepage 가 확보가 되지 않거나 OS Hugepage 할당 자체가되어 있지않다면 아래와 같이 메모리 부족하다는 로그와 함께 기동이 되지 않는다.
- 또는 DB 기동 중지 후 메모리(Shared_memory) 가 안내려가고 떠있다면, ipcs -a 로 조회 후 강제로 내려야 함.
[tarandb@ztest-db2 /]# pg_ctl start
pg_ctl: another server might be running; trying to start server anyway
waiting for server to start....2025-11-20 10:34:49 KST [205] []: [1-1] db=,user=,app=[],host=[],[691e7038.cd,,0] FATAL: could not map anonymous shared memory: Cannot allocate memory
2025-11-20 10:34:49 KST [205] []: [2-1] db=,user=,app=[],host=[],[691e7038.cd,,0] HINT: This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 1375731712 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.
2025-11-20 10:34:49 KST [205] []: [3-1] db=,user=,app=[],host=[],[691e7038.cd,,0] LOG: database system is shut down
stopped waiting
pg_ctl: could not start server
Examine the log output.
- PostgreSQL Hugepage 설정 및 기동 전 반드시 OS Hugepage 설정 및 메모리 확인이 필요함.
'PostgreSQL' 카테고리의 다른 글
| [PostgreSQL] bufferd I/O vs direct I/O (3) | 2025.11.25 |
|---|---|
| [PostgreSQL] pgvector 설치 및 간단한 사용 예시 (0) | 2025.11.25 |
| [PostgreSQL] Clustering 란 ? (1) | 2023.04.19 |
| [PostgreSQL] Unlogged Table 이란 ? (0) | 2023.04.19 |
| [PostgreSQL] 단일 사용자 모드 (single mode) 란 ? (0) | 2023.04.19 |