본문 바로가기
IT/Linux

[Linux] 커널 튜닝 ext4 파일 시스템 성능 최적화 실전 사례

by 수누다 2026. 7. 18.
반응형

[Linux] 커널 튜닝 ext4 파일 시스템 성능 최적화 실전 사례

리눅스 서버를 오래 보다 보면 CPU나 메모리보다도 디스크 I/O가 먼저 발목을 잡는 순간이 꼭 옵니다. 특히 로그가 많이 쌓이거나 작은 파일이 계속 생성되는 워크로드에서는 커널 튜닝 ext4 한 번으로 체감이 확 달라지기도 하거든요. 저도 홈랩과 운영 환경에서 비슷한 문제를 몇 번 겪었는데, 처음엔 애플리케이션 문제인 줄 알고 한참 돌아갔었습니다. 근데 막상 뜯어보니 ext4 마운트 옵션과 writeback(라이트백, 커널의 지연 쓰기) 동작이 핵심이더라고요. 이번 글에서는 Linux 성능 최적화 관점에서 ext4 파일 시스템을 어떻게 점검하고, 어떤 순서로 조정해야 덜 위험하게 성능을 끌어올릴 수 있는지 실제 사례 흐름으로 정리해보겠습니다.

특히 이 글은 벤치마크 숫자를 과장해서 보여주는 방식이 아니라, 제가 실제로 자주 쓰는 확인 절차와 안전한 튜닝 기준 위주로 풀어갑니다. 혹시 디스크 사용률은 높지 않은데 응답이 한 번씩 뚝 끊기는 경험 있으신가요? 여기서 중요한 포인트가 바로 파일 시스템 자체보다도 파일 시스템 튜닝과 커널 writeback 정책을 같이 봐야 한다는 점입니다.

커널 튜닝 ext4와 I/O 경로를 설명하는 개요 다이어그램

애플리케이션 쓰기 요청이 페이지 캐시와 ext4 저널을 거쳐 블록 디바이스로 내려가는 흐름을 보여주는 개요 이미지입니다.

왜 ext4 성능 개선이 생각보다 큰 차이를 만들까

쉽게 말해 ext4는 그냥 디스크에 바로 쓰는 시스템이 아닙니다. 애플리케이션이 파일을 쓰면 먼저 page cache(페이지 캐시, 메모리 기반 캐시)에 반영되고, 이후 커널이 적절한 시점에 실제 저장 장치로 내립니다. 여기에 journaling(저널링, 메타데이터 일관성을 위한 기록)까지 얹히니까, 같은 SSD를 써도 마운트 옵션과 커널 파라미터에 따라 체감이 꽤 달라질 수 있어요.

제가 처음 이걸 제대로 체감한 건 로그 수집 서버였습니다. 디스크는 NVMe였고 CPU도 여유가 있었는데, 특정 시간대만 되면 flush(플러시, 메모리의 변경 내용을 디스크로 밀어내는 작업)가 몰리면서 응답이 출렁이더라고요. 처음엔 "스토리지가 느린가?" 싶었는데 사실 스토리지보다는 쓰기 패턴과 ext4 기본 동작이 workload(워크로드, 실제 작업 특성)과 안 맞았던 겁니다.

ext4와 커널 튜닝 개념 먼저 정리해보겠습니다

ext4에서 먼저 봐야 할 핵심 포인트

  • atime: 파일 읽기 때 접근 시간(access time)을 갱신할지 여부입니다.
  • commit: 저널 커밋 주기 관련 옵션입니다. 너무 공격적으로 늘리면 장애 시 최근 변경 유실 범위가 커질 수 있습니다.
  • journaling mode: <code>data=ordered, data=writeback, data=journal 같은 모드가 있습니다.
  • discard: SSD/TRIM 처리 방식입니다. 연속 discard가 편할 때도 있지만, 주기적 fstrim이 더 나은 경우가 많습니다.
  • dirty page: 커널이 메모리에 쌓아두는 더티 페이지 비율입니다. 이게 높아지면 한 번에 밀어내는 양이 커질 수 있어요.

자주 쓰는 옵션 비교

항목 의미 장점 주의할 점
noatime 읽기 시 access time 갱신 비활성화 불필요한 메타데이터 쓰기 감소 atime 의존 프로그램이 있으면 영향 확인 필요
lazytime 시간 정보 갱신을 지연 반영 메타데이터 쓰기 감소 일부 운영 정책과 충돌 없는지 확인 필요
commit=30 저널 커밋 간격 증가 잦은 커밋 부담 완화 가능 장애 시 최근 변경 유실 범위 증가 가능
data=ordered 일반적인 기본 저널링 모드 안정성과 성능 균형 쓰기 특성에 따라 병목 가능
data=writeback 데이터 기록 순서 보장 완화 일부 쓰기 성능 유리 가능 일관성 측면 주의, 무조건 권장 아님

여기서 제가 강조하고 싶은 건, ext4 성능 개선은 옵션 몇 개 붙인다고 끝나는 작업이 아니라는 점이에요. 파일 생성이 많은지, 순차 쓰기가 많은지, fsync(에프싱크, 즉시 디스크 반영 요청)가 잦은지에 따라 접근이 달라져야 하거든요.

실전 사례: 로그 적재 서버에서 지연 스파이크를 줄인 과정

상황은 이랬습니다. 작은 로그 파일이 자주 쓰이고, 1분 단위 배치 작업이 돌 때 응답 지연이 크게 튀었습니다. 시스템을 보면 CPU는 넉넉했고 메모리도 부족하지 않았습니다. 그런데 iostatvmstat를 같이 보니 특정 시점마다 writeback이 몰리더라고요. 저도 처음엔 애플리케이션 쓰레드 문제인 줄 알고 삽질 좀 했습니다 ㅎㅎ 결국 원인은 "작은 쓰기 + 메타데이터 갱신 + flush 집중" 조합이었습니다.

1. 현재 ext4 마운트 상태부터 확인

  1. 대상 파일 시스템의 마운트 옵션을 확인합니다.
  2. 저널링 모드와 예약 블록, 파일 시스템 특성을 확인합니다.
  3. 실제 장치의 readahead와 I/O 패턴을 함께 봅니다.
findmnt -no TARGET,SOURCE,FSTYPE,OPTIONS /data
mount | grep ' /data '
sudo tune2fs -l /dev/nvme0n1p1 | egrep 'Filesystem features|Reserved block count|Block size|Journal'
sudo dumpe2fs -h /dev/nvme0n1p1 2>/dev/null | egrep 'Filesystem state|Errors behavior|Journal mode'

이 단계에서 중요한 건 "이미 어떤 옵션이 걸려 있는지"예요. 의외로 relatime 기본값으로 충분한 환경도 있고, 반대로 불필요한 discard가 항상 켜져 있어서 쓰기 경로를 괜히 복잡하게 만드는 경우도 있었습니다.

2. 병목이 파일 시스템인지, 블록 계층인지 분리

iostat -xz 1
vmstat 1
pidstat -d 1
sar -b 1

제가 실제로 자주 보는 건 이 네 가지입니다. iostat로 디바이스 지연과 큐를 보고, vmstat로 dirty page와 writeback 타이밍 감을 잡고, pidstat로 어떤 프로세스가 얼마나 쓰는지 확인합니다. 여기서 애플리케이션 fsync 호출이 잦으면 ext4 튜닝보다 앱 설정 조정이 먼저일 수 있어요. 그러니까 커널 튜닝 ext4는 언제나 계층 분리를 먼저 해야 합니다.

3. 안전한 범위의 1차 조정

제가 처음부터 무리하게 건드리지 않는 항목은 대체로 아래 정도입니다.

sudo cp /etc/fstab /etc/fstab.bak
sudo editor /etc/fstab
UUID=xxxx-xxxx  /data  ext4  defaults,noatime,lazytime,commit=30  0  2

noatime은 읽기 위주의 접근에서도 불필요한 메타데이터 갱신을 줄이는 데 꽤 도움이 돼요. lazytime은 시간 정보 반영을 지연시켜서 메타데이터 쓰기 부담을 줄일 수 있고요. commit=30은 저널 커밋 빈도를 낮춰 writeback이 너무 자주 발생하는 상황을 완화하는 데 써볼 만합니다. 다만 이 값은 서비스 특성에 따라 보수적으로 잡아야 합니다. 데이터 안전성이 아주 민감하면 함부로 늘리면 안 돼요.

커널 튜닝 ext4 설정 변경 과정을 보여주는 시스템 점검 이미지

fstab 편집, findmnt 확인, sysctl 조정 흐름을 한눈에 보여주는 구성 이미지입니다.

4. 커널 writeback 파라미터도 함께 조정

파일 시스템 옵션만 바꾸고 끝내면 절반만 본 셈입니다. 실제로 써보니까 flush가 몰리는 서버에서는 이쪽 영향도 꽤 크더라고요.

sysctl vm.dirty_background_ratio
sysctl vm.dirty_ratio
sysctl vm.dirty_expire_centisecs
sysctl vm.dirty_writeback_centisecs
sudo tee /etc/sysctl.d/99-ext4-tuning.conf >/dev/null <<'EOF'
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
EOF
sudo sysctl --system

이 수치는 만능 정답이 아닙니다. 다만 dirty page가 너무 많이 쌓였다가 한꺼번에 내려가는 패턴을 줄이는 출발점으로는 꽤 무난했어요. 저는 메모리가 큰 서버에서 기본값 그대로 두었다가 writeback 몰림이 생긴 적이 있었는데, 이 값을 조정하고 나서 지연 스파이크가 훨씬 덜해졌습니다.

5. SSD라면 discard 운영 방식 점검

여기서 한 번 더 많이 헷갈립니다. SSD니까 discard를 무조건 마운트 옵션에 넣어야 할 것 같죠? 저도 예전엔 그렇게 했었는데, 실제론 주기적 TRIM이 더 나은 경우가 적지 않아요.

systemctl status fstrim.timer
sudo systemctl enable --now fstrim.timer
systemctl list-timers | grep fstrim

즉시 discard보다 주기적 fstrim을 선호하는 이유는, 연속 discard가 쓰기 경로에 부담을 줄 수 있기 때문입니다. 물론 환경에 따라 다르니 확인은 꼭 필요해요.

⚠️ 실무에서 자주 만나는 트러블슈팅

문제 1: noatime 넣었더니 일부 프로그램 동작이 달라졌습니다

아주 드문 편이긴 하지만 atime을 실제로 참조하는 도구가 있을 수 있습니다. 이런 경우 noatime 대신 기본 relatime 유지가 더 안전해요. 무조건 성능만 보고 밀어붙이면 안 됩니다.

문제 2: commit 값을 늘렸더니 찜찜합니다

이건 정상적인 감각입니다. commit 간격을 늘리면 메타데이터 커밋 빈도는 줄 수 있지만, 장애 발생 시 최근 변경이 디스크에 완전히 반영되지 않았을 가능성은 커집니다. 그래서 데이터 무결성이 중요한 DB 데이터 디렉터리에는 저는 보수적으로 접근해요. 로그, 캐시, 재생성 가능한 데이터인지 먼저 구분하세요.

문제 3: data=writeback으로 바꾸면 더 빠른가요?

경우에 따라 다를 수는 있어도, 이걸 기본 추천으로 보시면 안 돼요. data=writeback은 데이터 기록 순서 보장이 더 약하므로 장애 시 예상 못 한 상태를 만날 수 있습니다. 제가 운영 서버에서는 대부분 data=ordered를 유지합니다. 성능 때문에 일관성을 희생하는 선택은 언제나 마지막이어야 하거든요.

문제 4: reserved block이 너무 크게 잡혀 있습니다

대용량 데이터 볼륨이라면 예약 블록(reserved block) 비율이 과한 경우가 있습니다. 루트 파일 시스템이 아니라 일반 데이터 파티션이면 점검해볼 만해요.

sudo tune2fs -m 1 /dev/nvme0n1p1

다만 이것도 서비스 성격을 봐야 합니다. 시스템 영역과 일반 데이터 볼륨은 판단 기준이 다르니까요.

검증: 바꿨으면 반드시 재현 테스트를 해봐야 합니다

튜닝은 느낌으로 하면 안 돼요. 저도 처음엔 "체감상 좋아진 것 같은데?" 하고 넘어가려다가 다시 문제를 만난 적이 있습니다. 그래서 지금은 꼭 동일한 패턴의 테스트를 다시 돌립니다.

fio로 쓰기 패턴 재현

fio --name=ext4-logtest \
    --directory=/data/fiotest \
    --size=2G \
    --bs=4k \
    --rw=randwrite \
    --iodepth=16 \
    --ioengine=libaio \
    --direct=0 \
    --numjobs=4 \
    --runtime=60 \
    --time_based \
    --group_reporting

여기서 포인트는 숫자 한 줄만 보지 않는 거예요. IOPS만 보고 "성공!" 하면 나중에 다시 당합니다. 저는 아래 항목을 같이 확인합니다.

  • 지연(latency) 분포가 덜 튀는지
  • 테스트 중 writeback 몰림이 줄었는지
  • 애플리케이션 응답이 실제로 안정적인지
  • 마운트 옵션 변경 후 오류 로그가 없는지
dmesg -T | tail -n 50
journalctl -k -n 50
findmnt -no OPTIONS /data
ext4 성능 개선 결과를 검증하는 대시보드 이미지

튜닝 전후의 지연 분포, 쓰기 대기열, writeback 패턴을 비교하는 성능 검증 이미지입니다.

실제로 해보니까 단순 최고 성능보다 최악 구간이 얼마나 줄었는지가 훨씬 중요했어요. 운영 환경은 평균값보다 꼬리 지연(tail latency, 최악 구간 지연)이 문제를 만들거든요. 이 부분은 다음 글에서 XFS와 ext4를 워크로드별로 비교하면서 더 자세히 다뤄볼 예정입니다.

정리: 제가 ext4 튜닝할 때 지키는 순서

  1. 현재 마운트 옵션과 저널 상태를 확인합니다.
  2. 디스크 병목인지, 앱의 fsync 패턴인지 먼저 분리합니다.
  3. noatime, lazytime, commit 같은 안전한 범위부터 조정합니다.
  4. 커널 dirty page 정책을 함께 봅니다.
  5. SSD라면 discard 대신 fstrim.timer 운영도 검토합니다.
  6. 반드시 재현 테스트와 커널 로그 확인으로 검증합니다.
튜닝 대상 먼저 볼 상황 제가 보통 취하는 액션
메타데이터 쓰기 많음 작은 파일, 잦은 읽기/쓰기 noatime, lazytime 검토
주기적 지연 스파이크 writeback 몰림 dirty page 관련 sysctl 점검
SSD 지속 쓰기 부담 discard 상시 사용 fstrim.timer 전환 검토
데이터 안정성 민감 DB, 중요 서비스 공격적 journaling 변경 지양

자주 묻는 질문

ext4보다 다른 파일 시스템이 항상 더 빠른가요?

항상 그렇진 않아요. 워크로드에 따라 다릅니다. ext4는 여전히 범용성과 안정성 면에서 아주 강한 선택지입니다.

모든 서버에 noatime을 넣어도 되나요?

대부분 문제 없지만, atime 의존 프로그램이 아예 없는지 확인은 필요합니다. 운영 표준으로 넣기 전에는 테스트 서버에서 먼저 검증하세요.

커널 튜닝 ext4는 어느 정도까지 해야 하나요?

제 기준은 간단해요. 관찰 가능한 병목이 있을 때만, 그리고 되돌릴 수 있는 범위부터입니다. 근거 없는 튜닝은 그냥 리스크죠.

커널 튜닝 ext4 적용 전후를 요약한 비교 인포그래픽

운영 반영 전 점검 항목과 튜닝 우선순위를 한 장으로 정리한 요약 이미지입니다.

마무리

커널 튜닝 ext4는 화려한 작업은 아닙니다. 그런데 운영 서버에서 한 번 병목이 터졌을 때 가장 현실적으로 효과를 보는 지점이기도 합니다. 제가 직접 해보니 핵심은 "옵션 많이 넣기"가 아니라 "현재 쓰기 패턴을 이해하고, 안전한 범위부터 검증하는 것"이었어요. 드디어 됐다 싶을 때도 로그와 지연 분포를 꼭 다시 보셔야 합니다. 진짜 편하더라고요.

이번 글에서는 ext4 기준으로 정리했지만, 다음 글에서는 Linux 성능 최적화 관점에서 XFS와 ext4를 어떤 워크로드에서 나눠서 볼지 이어서 다뤄보겠습니다. 이전 글에서 다룬 I/O 스케줄링과 블록 디바이스 점검 내용도 함께 보시면 흐름이 더 잘 잡히실 겁니다. 혹시 지금 운영 중인 서버에서 파일 시스템 튜닝을 고민하고 계시다면, 먼저 현재 마운트 옵션과 iostat 출력부터 확인해보세요. 거기서 절반은 이미 답이 보입니다.

반응형