새 인스턴스에 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 파일로 노출된다. 핵심은 enabled와 defrag 두 개다.
$ 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/grub의 GRUB_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=always에 defrag=defer+madvise, khugepaged/max_ptes_none=0을 함께 설정하는 별도 튜닝을 요구한다. 그러니 MongoDB 8.0 이상을 쓰면서 무작정 THP를 never로 끄면 벤더 권장과 어긋난다. 설치한 버전의 공식 튜토리얼을 확인하고, 8.0 이상이면 disable이 아니라 enable 쪽 유닛 파일을 적용한다.
일반적인 관계형 DB나 다른 메모리 집약 서비스도 THP 백그라운드 재구성이 지연 스파이크를 만드는 사례가 알려져 있다. 다만 제품별로 권장이 다를 수 있으니, 무조건 끄기 전에 해당 벤더 문서를 확인하는 습관을 들인다.