본문 바로가기
Operating System

Redis, MongoDB 로그의 THP 경고 제대로 끄기: systemd, GRUB, tuned로 영구 비활성화

나크나로·2026년 8월 11일·조회 1

새 인스턴스에 Redis나 MongoDB를 올리고 기동 로그를 보면 거의 매번 THP 관련 경고 한 줄이 붙는다. 나도 설치할 때마다 이 줄을 보고, 급하면 echo never 한 번으로 덮고 넘어가곤 했다. 문제는 그렇게 끄면 재부팅 한 번에 다시 살아난다는 점이다. 이 글은 그 경고를 재부팅 뒤에도 유지되게 제대로 끄는 방법을 정리한다.

결론부터 말하면, THP는 커널 부팅 파라미터나 systemd oneshot 서비스로 꺼야 재부팅 후에도 유지된다. Redis는 공식 문서가 never를 권장하고, MongoDB 7.0 이하도 never를 권장한다. 다만 MongoDB 8.0부터는 THP를 오히려 켜라고 바뀌었으니 버전을 먼저 확인해야 한다. 아래에서 현재 상태 확인, 임시 비활성화, 영구 비활성화 세 가지 방법, 재부팅 검증 순서로 살펴본다.

1. THP가 무엇이고 왜 경고가 뜨나

Transparent Huge Pages(THP)는 리눅스 커널이 4KB짜리 일반 페이지 여러 개를 2MB 대형 페이지로 자동으로 묶어주는 기능이다. 페이지 테이블 크기를 줄여 일부 워크로드에서 TLB 미스를 낮추는 효과가 있다. 문제는 이 묶고 쪼개는 작업을 khugepaged 커널 스레드가 백그라운드에서 수시로 한다는 점이다.

Redis나 MongoDB처럼 fork로 백그라운드 저장(RDB, AOF 재작성)을 하는 프로세스는 여기서 손해를 본다. Redis 공식 문서는 이렇게 설명한다. fork 직후 부모, 자식이 대형 페이지를 공유하는데, 바쁜 인스턴스에서 몇 번의 이벤트 루프만 돌아도 수천 개 페이지가 수정되고, 그러면 거의 프로세스 전체 메모리가 copy-on-write로 복사되어 큰 지연과 메모리 사용으로 이어진다. 그래서 서버 기동 시 로그에 경고를 남긴다.

2. 현재 상태 확인

THP 설정은 /sys/kernel/mm/transparent_hugepage/ 아래 sysfs 파일로 노출된다. 핵심은 enableddefrag 두 개다.

$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

$ cat /sys/kernel/mm/transparent_hugepage/defrag
[always] defer defer+madvise madvise never

대괄호로 감싼 값이 현재 활성 상태다. 위 출력은 always로 켜져 있다는 뜻이다. 목표는 두 파일 모두 never에 대괄호가 오게 하는 것이다.

RHEL, CentOS 계열 일부 커널에서는 경로가 /sys/kernel/mm/redhat_transparent_hugepage/로 나올 수 있다. 위 경로에서 파일이 없다는 에러가 나면 이쪽을 확인한다.

$ cat /sys/kernel/mm/transparent_hugepage/enabled
cat: /sys/kernel/mm/transparent_hugepage/enabled: No such file or directory

$ cat /sys/kernel/mm/redhat_transparent_hugepage/enabled
[always] madvise never

3. 임시로 끄기 (재부팅하면 원복)

당장 경고를 없애고 싶으면 sysfs 파일에 직접 써 넣는다. Redis 공식 문서가 안내하는 방법이다.

$ echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
never
$ echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
never

$ cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]

여기서 반드시 서비스를 재기동해야 경고가 사라진다. THP를 끈 뒤에도 이미 떠 있는 Redis, MongoDB 프로세스는 예전 설정 기준으로 동작하기 때문이다.

$ sudo systemctl restart redis
$ sudo systemctl restart mongod

이 방법은 즉시 반영되지만 sysfs 값은 부팅 때마다 초기화된다. 재부팅하면 다시 always로 돌아온다. 그래서 아래 영구 방법 중 하나를 반드시 함께 적용한다.

4. systemd 서비스로 영구 비활성화 (권장)

가장 이식성이 좋은 방법이다. 부팅 초기에 sysfs 값을 never로 써 주는 oneshot 서비스를 만들고, 데이터베이스 서비스보다 먼저 실행되게 순서를 잡는다. 아래는 MongoDB 공식 문서가 제시하는 유닛 파일을 그대로 쓴 것이다.

$ sudo tee /etc/systemd/system/disable-transparent-huge-pages.service <<'EOF'
[Unit]
Description=Disable Transparent Hugepages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=mongod.service

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null && echo never | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null'

[Install]
WantedBy=basic.target
EOF

Before=mongod.service는 THP를 먼저 끄고 나서 DB를 띄우도록 순서를 강제한다. Redis를 쓴다면 이 줄을 Before=redis.service로 바꾸거나 두 줄을 함께 적는다. 서비스 이름은 배포판, 설치 방식에 따라 다를 수 있으니 systemctl list-units | grep -E 'redis|mongod'로 실제 이름을 확인한다.

유닛을 등록하고 활성화한다.

$ sudo systemctl daemon-reload
$ sudo systemctl start disable-transparent-huge-pages
$ sudo systemctl enable disable-transparent-huge-pages
Created symlink /etc/systemd/system/basic.target.wants/disable-transparent-huge-pages.service -> /etc/systemd/system/disable-transparent-huge-pages.service.

여기서 한 번 걸린 적이 있다. enable만 하고 start를 빼면 그 부팅 세션에서는 값이 그대로라 재부팅 전까지 경고가 남는다. 지금 바로 적용하려면 start도 같이 실행한다.

5. GRUB 커널 파라미터로 끄기

부팅 아주 초기부터 THP를 막고 싶으면 커널 명령줄에 transparent_hugepage=never를 넣는다. sysfs를 건드리지 않고 커널이 처음부터 THP를 비활성화 상태로 뜬다.

RHEL, CentOS, Rocky 계열은 /etc/default/grubGRUB_CMDLINE_LINUX에 파라미터를 추가한 뒤 설정을 다시 생성한다.

# /etc/default/grub 편집 후
GRUB_CMDLINE_LINUX="... transparent_hugepage=never"

# BIOS 부팅
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# UEFI 부팅(RHEL 8/9)
$ sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg

Ubuntu, Debian은 같은 파일을 고친 뒤 update-grub을 쓴다.

$ sudo update-grub
Generating grub configuration file ...
done

GRUB 방식은 재부팅해야 반영된다. 커널 파라미터만으로는 defrag가 명시적으로 never가 아니라 종속 상태가 되므로, sysfs 값까지 확실히 통제하고 싶으면 4번 systemd 방법과 함께 쓴다.

6. tuned 프로파일로 끄기

RHEL 계열에서 tuned를 쓰고 있다면 프로파일에 THP 설정을 넣는 방법도 있다. tuned는 시스템 튜닝 파라미터를 프로파일 단위로 관리하는 데몬이다. 주의할 점은 tuned가 부팅 후 자기 프로파일 값으로 THP를 덮어쓸 수 있어서, systemd나 GRUB로 껐는데도 tuned 프로파일이 always면 다시 켜질 수 있다는 것이다.

기존 프로파일을 상속하는 커스텀 프로파일을 만들어 THP만 never로 지정한다.

$ sudo mkdir -p /etc/tuned/virtual-guest-no-thp
$ sudo tee /etc/tuned/virtual-guest-no-thp/tuned.conf <<'EOF'
[main]
include=virtual-guest

[vm]
transparent_hugepages=never
EOF

$ sudo tuned-adm profile virtual-guest-no-thp
$ tuned-adm active
Current active profile: virtual-guest-no-thp

include에는 원래 쓰던 프로파일 이름을 넣는다. 물리 서버면 throughput-performance처럼 현재 활성 프로파일을 tuned-adm active로 먼저 확인한 뒤 그 값으로 바꾼다.

7. 재부팅 후 검증

영구 설정을 넣었으면 실제로 재부팅해서 확인해야 한다. 부팅 순서 문제로 DB가 THP 비활성화보다 먼저 떠버리는 경우가 있어서, 설정만 보고 넘어가면 놓친다.

$ sudo reboot

# 재부팅 후
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
$ cat /sys/kernel/mm/transparent_hugepage/defrag
always defer defer+madvise madvise [never]

두 파일 모두 [never]면 성공이다. GRUB 방식을 썼다면 커널이 실제로 파라미터를 받았는지도 확인한다.

$ cat /proc/cmdline
BOOT_IMAGE=... transparent_hugepage=never

마지막으로 DB 로그에서 경고가 사라졌는지 본다. Redis는 기동 로그, MongoDB는 startup warnings에서 THP 줄이 없으면 정리된 것이다.

$ sudo journalctl -u redis -b | grep -i huge
$ sudo journalctl -u mongod -b | grep -i huge
# 아무 출력도 없으면 정상

8. 제품별 주의: Redis와 MongoDB 버전

Redis는 판단이 단순하다. 공식 문서와 지연 진단 문서 모두 THP를 never로 끄라고 못 박는다. 기동 시 로그에 나오는 경고는 이런 형태다.

WARNING you have Transparent Huge Pages (THP) support enabled in your
kernel. This will create latency and memory usage issues with Redis.
To fix this issue run the command 'echo madvise >
/sys/kernel/mm/transparent_hugepage/enabled' as root ...

런타임 경고는 madvise를 제안하기도 하지만, 공식 관리 문서의 권장값은 never다. 위 절차대로 never로 끄면 된다. 참고로 Redis는 vm.overcommit_memory = 1도 함께 권장하니 /etc/sysctl.conf에 같이 넣어두면 fork 관련 경고도 정리된다.

MongoDB는 버전을 먼저 봐야 한다. MongoDB 7.0 이하는 THP를 never로 끄라고 안내하고, 기동 경고도 다음처럼 나온다.

** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
**        We suggest setting it to 'never' in this binary version.

반면 MongoDB 8.0부터는 방향이 바뀌었다. 새 per-CPU 캐시 방식의 TCMalloc을 지원하기 위해 THP를 켜라고 권장한다. 대신 enabled=alwaysdefrag=defer+madvise, khugepaged/max_ptes_none=0을 함께 설정하는 별도 튜닝을 요구한다. 그러니 MongoDB 8.0 이상을 쓰면서 무작정 THP를 never로 끄면 벤더 권장과 어긋난다. 설치한 버전의 공식 튜토리얼을 확인하고, 8.0 이상이면 disable이 아니라 enable 쪽 유닛 파일을 적용한다.

일반적인 관계형 DB나 다른 메모리 집약 서비스도 THP 백그라운드 재구성이 지연 스파이크를 만드는 사례가 알려져 있다. 다만 제품별로 권장이 다를 수 있으니, 무조건 끄기 전에 해당 벤더 문서를 확인하는 습관을 들인다.

자주 묻는 질문

THP를 임시로 끈 뒤 왜 서비스를 재기동해야 하나?

sysfs 값을 never로 바꿔도 이미 실행 중인 Redis, MongoDB 프로세스는 기동 시점의 메모리 매핑을 그대로 쓴다. 새 설정이 프로세스에 반영되고 기동 경고가 사라지려면 systemctl restart로 서비스를 다시 띄워야 한다.

systemd 서비스와 GRUB 커널 파라미터 중 무엇을 써야 하나?

재부팅 후 유지되면서 배포판을 가리지 않는 systemd oneshot 서비스가 가장 이식성이 좋다. GRUB의 transparent_hugepage=never는 부팅 초기부터 막는 장점이 있지만 defrag 값까지 명시적으로 통제하려면 systemd 방식과 함께 쓰는 편이 확실하다.

tuned를 쓰는데도 THP가 계속 켜진다.

tuned 데몬이 부팅 후 활성 프로파일 값으로 THP를 덮어쓰기 때문이다. tuned-adm active로 현재 프로파일을 확인하고, transparent_hugepages=never를 지정한 커스텀 프로파일을 만들어 적용하면 된다.

MongoDB 8.0에서도 THP를 꺼야 하나?

아니다. MongoDB 8.0부터는 per-CPU 캐시 TCMalloc 지원을 위해 THP를 always로 켜고 defrag를 defer+madvise, khugepaged/max_ptes_none을 0으로 두라고 권장한다. 7.0 이하만 never로 끈다. 설치한 버전의 공식 튜토리얼을 먼저 확인한다.

RHEL에서 /sys/kernel/mm/transparent_hugepage 경로가 없다.

일부 RHEL, CentOS 커널은 경로가 /sys/kernel/mm/redhat_transparent_hugepage/로 노출된다. 원래 경로에서 No such file or directory 에러가 나면 redhat_transparent_hugepage 경로의 enabled와 defrag를 확인하고 같은 방식으로 설정한다.

관련 글

댓글 0

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.