13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] 리눅스 디스크 I/O

  • [Linux] ext4 디스크 I/O 성능 저하 원인 분석 및 진단 방법

    [Linux] ext4 디스크 I/O 성능 저하 원인 분석 및 진단 방법

    [Linux] ext4 디스크 I/O 성능 저하 원인 분석 및 진단 방법

    안녕하세요, 13년차 서버실 지킴이입니다. 🤓

    어느 날 갑자기 서버가 느려졌는데, CPU나 메모리 사용량은 평온하고 네트워크 트래픽도 평소와 다를 바 없을 때, 문득 이런 생각이 들지 않으세요? “혹시 ext4의 디스크 I/O 문제인가?” 네, 정확한 추측일 수도 있어요. 리눅스 서버에서 가장 흔하게 사용되는 파일시스템인 ext4에서 성능 저하가 벌어지면 정말 당황스럽죠. 특히 서비스 운영 중이라면 심장이 덜컥 내려앉을 겁니다.

    저도 홈랩에서 이것저것 실험하다가 갑자기 디스크 읽기/쓰기 속도가 확 떨어져서 며칠 밤낮을 삽질했던 경험이 있거든요. 처음엔 설정 문제인가 싶었는데, 알고 보니 ext4 파일시스템 자체의 특성이나 잘못된 마운트 옵션, 혹은 숨겨진 병목 때문이었더라고요. 그래서 오늘은 ext4 디스크 I/O 성능 저하의 원인을 파헤치고, 어떻게 진단하고 해결할 수 있는지 제 경험을 바탕으로 솔직하게 풀어보려 합니다. 함께 리눅스 디스크 I/O 문제를 해결해 봅시다! 💡

    리눅스 서버의 ext4 파일시스템 I/O 흐름 및 잠재적 병목 지점 개요 다이어그램

    ext4 파일시스템과 디스크 I/O, 대체 뭐가 문제일까요? 🤔

    먼저, 기본적인 개념부터 짚고 넘어갈게요. 디스크 I/O(Input/Output)는 말 그대로 디스크에 데이터를 쓰고(write) 읽는(read) 작업을 말합니다. 서버 애플리케이션의 응답 속도는 이 디스크 I/O 성능에 크게 좌우되죠. 웹 서버의 로그 기록, 데이터베이스의 쿼리 처리, 캐시 파일 저장 등 거의 모든 작업이 디스크 I/O를 수반하거든요.

    ext4는 리눅스에서 가장 널리 사용되는 저널링 파일시스템(Journaling Filesystem)입니다. 저널링 덕분에 시스템 크래시(crash) 시 데이터 일관성(data consistency)을 보장하는 강력한 장점이 있지만, 이 저널링 과정 자체가 때로는 I/O 성능 오버헤드(overhead)로 작용할 수 있어요. 쉽게 말해, 데이터를 변경하기 전에 먼저 변경 내용을 저널(journal)이라는 특별한 영역에 기록하고 나서 실제 데이터 영역에 쓰는 방식이라, 안정성은 높지만 그만큼 추가적인 디스크 작업이 필요하다는 거죠.

    ext4의 성능에 영향을 미치는 주요 요소는 다음과 같습니다:

    • 저널링 모드 (Journaling Mode): data=journal, data=ordered, data=writeback 등 모드에 따라 데이터 안정성과 성능이 달라집니다.
    • 블록 사이즈 (Block Size): 파일시스템 생성 시 지정하는 데이터 처리 단위로, 작은 파일이 많으면 작은 블록 사이즈가, 큰 파일이 많으면 큰 블록 사이즈가 유리할 수 있습니다.
    • 마운트 옵션 (Mount Options): noatime, discard, barrier=0 등 다양한 옵션으로 성능을 튜닝할 수 있습니다.
    • 디스크 자체 성능: HDD냐 SSD냐, RAID 구성이냐 등 물리적인 디스크의 스펙도 중요하죠.
    • 파일 단편화 (Fragmentation): 파일이 디스크 여러 곳에 흩어져 저장되면 읽기/쓰기 성능이 저하됩니다.

    실전! ext4 디스크 I/O 성능 진단 도구 활용법 🛠️

    자, 이제 실제로 서버에서 디스크 I/O 병목을 어떻게 찾아내는지 알아볼 차례입니다. 리눅스에는 정말 유용한 도구들이 많아요. 제가 즐겨 쓰는 몇 가지를 소개합니다.

    1. iostat: 시스템 전체 디스크 I/O 통계

    iostat은 시스템 전체의 디스크 I/O 통계를 실시간으로 보여주는 강력한 도구예요. 특정 디스크의 사용률, 큐 길이, 응답 시간 등을 한눈에 파악할 수 있거든요.

    # iostat -x 1 5
    # -x: 확장 통계 정보 출력 (extended statistics)
    # 1: 1초 간격으로
    # 5: 5번 반복 출력
    
    Linux 5.15.0-78-generic (my-server) 	08/20/2023 	_x86_64_ 	(8 CPU)
    
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
               1.20    0.00    0.80    0.10    0.00   97.90
    
    Device             r/s   w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
    sda               0.10  0.00    2.00    0.00     40.00     0.00    0.20    0.20    0.00   0.20   0.00
    sdb               0.00  0.00    0.00    0.00      0.00     0.00    0.00    0.00    0.00   0.00   0.00
    

    여기서 봐야 할 핵심 지표들은 다음과 같습니다:

    • %util: 디스크 사용률입니다. 100%에 가깝다면 디스크가 항상 바쁘다는 뜻인데, 성능 병목의 강력한 신호일 수 있어요. (⚠️ 단, 고성능 NVMe SSD의 경우 100%에 가까워도 실제 성능은 좋을 수 있으니 다른 지표와 함께 봐야 합니다!)
    • avgqu-sz (Average Queue Size): 디스크 I/O 요청 큐의 평균 길이입니다. 이 값이 지속적으로 높다면 디스크가 요청을 처리하지 못하고 대기 중인 작업이 많다는 뜻이에요. 보통 1 이상이면 주의 깊게 봐야 합니다.
    • await (Average Wait Time): I/O 요청이 디스크에서 처리되기까지 걸리는 평균 시간(밀리초)입니다. 큐에서 대기하는 시간까지 포함하므로, 이 값이 높으면 응답성이 떨어진다는 의미죠.
    • svctm (Average Service Time): I/O 요청이 디스크 컨트롤러에 의해 실제로 처리되는 평균 시간(밀리초)입니다. await과 svctm의 차이가 크다면, 큐에서 대기하는 시간이 길다는 의미로 해석할 수 있어요.

    2. sar -d: 상세 디스크 활동 통계

    sar는 시스템 활동 리포트(System Activity Reporter)의 약자로, CPU, 메모리, 네트워크 등 다양한 시스템 통계를 기록하고 분석할 수 있습니다. 디스크 I/O를 보려면 -d 옵션을 사용하면 되죠.

    # sar -d 1 5
    # -d: 디스크 활동 통계 출력
    # 1: 1초 간격으로
    # 5: 5번 반복 출력
    
    Linux 5.15.0-78-generic (my-server) 	08/20/2023 	_x86_64_ 	(8 CPU)
    
    02:30:01 PM   DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz  await  svctm  %util
    02:30:02 PM   sda      0.10      2.00      0.00     40.00      0.00   0.20   0.20   0.00
    02:30:02 PM   sdb      0.00      0.00      0.00      0.00      0.00   0.00   0.00   0.00
    

    iostat과 비슷한 지표들을 제공하지만, sar는 기록된 데이터를 나중에 분석할 때 유용해요. 특히 tps (초당 전송 수), rd_sec/s (초당 읽기 섹터 수), wr_sec/s (초당 쓰기 섹터 수)를 통해 디스크의 처리량(throughput)을 가늠해볼 수 있습니다. sar는 sysstat 패키지에 포함되어 있으니, 설치되어 있지 않다면 sudo apt install sysstat (Debian/Ubuntu) 또는 sudo yum install sysstat (CentOS/RHEL)로 설치해 주세요.

    3. iotop: 프로세스별 디스크 I/O 사용량

    시스템 전체나 특정 디스크의 I/O 통계를 봤는데, 어떤 프로세스가 디스크를 많이 쓰고 있는지 궁금할 때가 있습니다. 이럴 땐 iotop이 아주 유용해요. 마치 top 명령어처럼 프로세스별 I/O 사용량을 실시간으로 보여주거든요.

    # iotop
    # -o: 현재 I/O를 사용하는 프로세스만 표시
    # -P: 프로세스만 표시 (스레드 제외)
    
    Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
    Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
      TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
        1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % init
        2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
      ...
    

    iotop을 실행하면 어떤 프로세스가 디스크를 가장 많이 쓰고 있는지 바로 알 수 있어요. IO> 컬럼을 통해 I/O 대기(wait) 상태를 파악할 수 있고, 이를 통해 특정 애플리케이션이나 서비스가 디스크 병목을 유발하는 주범인지 쉽게 찾아낼 수 있습니다. 💡

    iotop 명령어로 확인하는 프로세스별 디스크 I/O 사용량

    iotop 명령어를 통해 실시간 프로세스별 디스크 I/O 사용량을 확인하는 모습

    ⚠️ 삽질 경험담: ext4 마운트 옵션과 저널링의 함정

    제가 가장 많이 삽질했던 부분 중 하나가 바로 ext4의 마운트 옵션(Mount Options)과 저널링(Journaling)이었습니다. 단순히 디스크를 마운트할 때 아무 생각 없이 기본값으로 쓰다가 나중에 피를 본 적이 많거든요. 특히 작은 파일을 빈번하게 읽고 쓰는 웹 서버나 캐시 서버에서 이런 문제가 자주 발생하더라고요.

    1. atime 업데이트 오버헤드

    기본적으로 리눅스 파일시스템은 파일에 접근(access)할 때마다 atime(access time)을 업데이트합니다. 이게 참 좋은 기능이지만, 문제는 파일에 접근할 때마다 디스크 쓰기 작업이 발생한다는 거예요. 즉, 읽기 작업인데도 쓰기 I/O가 발생해 성능 저하를 일으킬 수 있어요. 그래서 저는 특별한 이유가 없다면 noatime 옵션을 즐겨 사용합니다.

    # /etc/fstab 파일 예시
    UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data ext4 defaults,noatime,errors=remount-ro 0 1
    
    # 변경 후 적용
    sudo mount -o remount /data
    

    noatime은 atime 업데이트를 완전히 비활성화합니다. 만약 atime 정보가 필요하지만 I/O 오버헤드를 줄이고 싶다면 relatime 옵션을 사용할 수도 있어요. relatime은 마지막 접근 시간이 마지막 변경 시간(mtime)보다 오래되었을 때만 atime을 업데이트합니다. 대부분의 경우 relatime으로도 충분하고, 극단적인 성능이 필요하면 noatime을 사용하죠.

    2. 저널링 모드 선택

    앞서 설명했듯이, ext4는 저널링 모드에 따라 성능과 데이터 안정성이 달라집니다. 주요 모드는 세 가지입니다.

    • data=journal: 데이터와 메타데이터(metadata) 모두 저널에 기록합니다. 가장 안전하지만, 가장 느려요. 데이터 일관성이 최우선인 경우에만 고려해볼 만합니다.
    • data=ordered (기본값): 메타데이터만 저널에 기록하고, 데이터는 메타데이터가 커밋(commit)되기 전에 디스크에 쓰여지도록 보장합니다. 안정성과 성능의 균형이 좋아서 대부분의 경우에 적합하죠.
    • data=writeback: 메타데이터만 저널에 기록하고, 데이터는 저널링되지 않습니다. 가장 빠르지만, 시스템 크래시 시 데이터 손실 위험이 있어요. 캐시 디스크나 로그 디스크처럼 데이터 손실이 치명적이지 않은 경우에 고려할 수 있습니다.

    저널링 모드 변경은 파일시스템 생성 시 또는 tune2fs 명령으로 변경 가능하지만, 마운트 옵션으로도 지정할 수 있어요. 예를 들어, 성능을 최우선으로 한다면:

    # /etc/fstab 파일 예시
    UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /cache ext4 defaults,noatime,data=writeback 0 2
    
    # 변경 후 적용
    sudo mount -o remount /cache
    

    ⚠️ data=writeback은 데이터 손실 위험이 있으니 신중하게 사용하세요!

    3. 그 외 유용한 마운트 옵션

    몇 가지 더 유용한 옵션들을 표로 정리해봤습니다.

    옵션 설명 효과 주의사항
    noatime 파일 접근 시간(atime) 업데이트 비활성화 읽기 I/O 발생 시 쓰기 I/O 감소 atime 정보가 필요한 애플리케이션에 문제 발생 가능
    relatime mtime보다 오래된 atime만 업데이트 noatime과 atime 업데이트의 절충안 대부분의 경우 noatime 대신 사용 권장
    data=writeback 데이터 저널링 비활성화 가장 빠른 쓰기 성능 시스템 크래시 시 데이터 손실 위험
    barrier=0 디스크 쓰기 배리어(write barrier) 비활성화 일부 환경에서 쓰기 성능 향상 RAID 컨트롤러 또는 가상 환경에서 데이터 손실 위험 증가, 신중히 사용
    discard TRIM 명령 활성화 (SSD에 유용) SSD 성능 유지 및 수명 연장 지속적인 TRIM으로 인한 오버헤드 발생 가능 (주기적인 fstrim 권장)
    ext4 마운트 옵션별 성능 및 데이터 안정성 비교 인포그래픽

    ext4 마운트 옵션별 성능 및 데이터 안정성 비교

    ✅ 검증 및 결과 확인: 성능 개선을 눈으로 확인하기!

    마운트 옵션을 변경했거나, 문제가 되는 프로세스를 해결했다면, 이제 정말로 성능이 개선되었는지 확인해야겠죠? 저는 주로 iostat이나 sar로 다시 한번 지표를 확인해요. 특히 await, avgqu-sz, %util 값이 어떻게 변했는지 집중해서 봅니다.

    • await 값이 5ms 미만으로 꾸준히 유지된다면 양호한 수준입니다. 10ms 이상으로 지속된다면 여전히 I/O 병목이 있을 가능성이 높아요.
    • avgqu-sz 값이 1 이하로 떨어졌는지 확인해요. 이 값이 높으면 I/O 요청이 계속 밀리고 있다는 뜻이거든요.
    • %util은 무조건 낮다고 좋은 건 아니지만, 과도하게 높으면서 다른 지표들(await, avgqu-sz)도 높다면 문제가 있다는 신호예요.

    만약 특정 애플리케이션의 성능 저하가 문제였다면, 해당 애플리케이션의 응답 시간(response time)이나 처리량(throughput) 지표를 직접 확인하는 것이 가장 정확해요. 예를 들어, 데이터베이스 쿼리 속도가 빨라졌는지, 웹 페이지 로딩 시간이 단축되었는지 등을 측정해보는 거죠. 저는 Grafana와 Prometheus를 활용해서 I/O 지표를 시각화해서 보곤 하는데, 이렇게 하면 변화 추이를 한눈에 파악하기 정말 편하더라고요. 🎉

    Grafana 대시보드에서 디스크 I/O 성능 개선 추이를 시각적으로 확인하는 예시

    마무리: 나의 ext4는 어떤 길을 가야 할까? 🚀

    ext4 디스크 I/O 성능 문제는 정말 흔하고, 처음엔 막막하게 느껴질 수 있어요. 하지만 iostat, sar, iotop 같은 도구들을 활용해서 정확한 원인을 파악하고, 적절한 마운트 옵션 튜닝이나 저널링 모드 변경을 통해 충분히 해결할 수 있습니다.

    결론적으로, “내 ext4는 어떤 설정이 최적일까?”라는 질문에 대한 답은 “어떤 데이터를, 어떻게 사용하는지에 따라 다르다”는 거예요.

    • 만약 데이터 일관성과 안전성이 최우선이라면, data=ordered (기본값)를 유지하고, noatime보다는 relatime을 고려하는 것이 좋습니다.
    • 로그 파일이나 캐시처럼 데이터 손실에 비교적 관대한 환경에서 최고의 쓰기 성능을 원한다면, data=writeback과 noatime 조합을 신중하게 테스트해볼 수 있습니다. 하지만 이 경우 백업 전략을 더욱 철저히 해야겠죠.
    • SSD를 사용 중이라면, discard 옵션을 사용하거나 주기적으로 fstrim 명령을 실행하여 성능을 유지하는 것이 좋아요.

    이번 글이 여러분의 ext4 성능 문제 해결에 작은 도움이 되었기를 바랍니다. 다음번에는 파일 단편화(fragmentation) 문제를 깊이 다루거나, 더 나아가 ZFS나 Btrfs 같은 다른 파일시스템의 성능 튜닝에 대해서도 이야기해볼까 합니다. 궁금한 점이 있다면 언제든 댓글로 남겨주세요! 저의 삽질 경험이 또 다른 글이 될 수 있으니까요. 😉

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

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

    [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는 넉넉했고 메모리도 부족하지 않았습니다. 그런데 iostat와 vmstat를 같이 보니 특정 시점마다 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 출력부터 확인해보세요. 거기서 절반은 이미 답이 보입니다.