로그 한 줄에 49KB, 실화입니다 — systemd-journald가 당신의 SSD를 갉아먹는 방식
“로그 한 줄 쓰는 데 49KB요?” 처음 이 숫자를 봤을 때 저도 오타인 줄 알았습니다. 그런데 사실이었습니다. systemd-journald에 짧은 로그 한 줄을 던지면 실제 디스크에는 그 수천 배가 기록됩니다. ext4에서 약 49KB, btrfs에서는 110KB까지 올라갑니다. 평소엔 아무도 신경 안 쓰던 숫자인데 요즘 다시 화제입니다. AI 에이전트가 하루에도 수십만 줄씩 로그를 뱉어내기 시작했거든요.
쓰기 증폭이 뭔가요
쓰기 증폭(write amplification)은 애플리케이션이 요청한 데이터 양보다 실제 저장장치에 기록되는 양이 훨씬 큰 현상입니다.
원래 이 말은 SSD 내부 이야기였습니다. 플래시 메모리는 바이트 단위로 덮어쓰기가 안 됩니다. 블록 단위로 지우고 다시 써야 합니다. 그래서 4KB만 바꾸려고 해도 내부에서는 훨씬 큰 단위가 움직입니다. SSD 컨트롤러 레벨의 증폭은 보통 1.1배에서 3배 정도입니다.
그런데 저널드 사례는 층위가 다릅니다. 애플리케이션과 파일시스템 사이, 그러니까 소프트웨어 레이어에서만 수천 배가 발생합니다. 그다음에 파일시스템 증폭이 붙고, 마지막으로 SSD 내부 증폭이 또 곱해집니다. 곱셈이 세 번 일어나는 구조입니다.
왜 49KB나 되는 걸까
저널드가 특별히 못 만든 소프트웨어라서 그런 건 아닙니다. 설계 목표가 달랐을 뿐입니다.
저널드는 단순한 텍스트 로거가 아닙니다. 구조화된 바이너리 데이터베이스에 가깝습니다. 로그 한 줄이 들어오면 여기에 이런 게 붙습니다. 타임스탬프, 부팅 ID, 프로세스 ID, 실행 파일 경로, cgroup 정보, 유닛 이름, 우선순위, 그리고 해시 기반 무결성 검증용 데이터까지. 메타데이터만 해도 원본 메시지의 수십 배입니다.
여기서 끝이 아닙니다. 저널드는 필드별로 역색인을 만듭니다. journalctl -u nginx 같은 명령이 즉시 결과를 뱉는 게 이 색인 덕분입니다. 색인은 새 로그가 들어올 때마다 갱신됩니다. 색인 파일의 해시 테이블 영역이 바뀌고, 그 수정이 페이지 단위로 디스크에 내려갑니다.
결정타는 fsync입니다. 저널드는 로그를 잃지 않으려고 주기적으로 디스크 동기화를 강제합니다. 커널 페이지 캐시에서 뭉쳐 처리할 기회를 스스로 걷어차는 셈입니다. 한 줄 쓰고 동기화, 또 한 줄 쓰고 동기화. 파일시스템 입장에서는 매번 저널 커밋을 해야 하니 실제 쓰기가 폭증합니다.
btrfs에서 110KB가 되는 이유
같은 로그인데 파일시스템에 따라 두 배 차이가 납니다. btrfs의 설계 특성 때문입니다.
btrfs는 Copy-on-Write 방식입니다. 기존 데이터를 제자리에서 고치지 않고 새 위치에 쓴 다음 포인터를 바꿉니다. 문제는 이 포인터가 트리 구조라는 겁니다. 리프 노드 하나가 바뀌면 그 부모가 바뀌고, 부모의 부모가 바뀌고, 루트까지 연쇄로 갱신됩니다. 트리 전체를 타고 올라가는 쓰기가 생깁니다.
여기에 체크섬까지 붙습니다. btrfs는 데이터 무결성을 위해 블록마다 체크섬을 저장하는데, 이 체크섬 트리도 같이 갱신돼야 합니다.
그래서 btrfs 커뮤니티에서는 예전부터 데이터베이스 파일이나 VM 이미지에는 chattr +C로 CoW를 끄라고 조언해왔습니다. 저널 파일도 사실 같은 부류인데, 이걸 아는 사람이 많지 않습니다.
실제로 얼마나 위험한가
숫자를 좀 굴려보겠습니다.
초당 100줄 정도 로그를 남기는 평범한 서버가 있다고 칩시다. 49KB를 곱하면 초당 약 4.9MB입니다. 하루면 약 420GB입니다. 로그 몇 MB 남기자고 디스크에 400GB 넘게 쓰고 있는 겁니다.
일반적인 TLC SSD의 내구성은 드라이브 용량당 하루 쓰기(DWPD) 기준으로 0.3에서 1 정도입니다. 1TB 드라이브라면 하루 300GB에서 1TB 쓰기를 5년간 견디도록 설계했다는 뜻입니다. 로그만으로 그 예산의 상당 부분을 태우고 있는 셈입니다.
물론 여기엔 조건이 붙습니다. 이 수치는 로그가 드문드문 들어올 때의 최악 상황입니다. 로그가 몰아쳐 들어오면 저널드도 배치로 처리하고 커널 페이지 캐시도 병합해줍니다. 초당 수천 줄이 쏟아지면 줄당 증폭은 훨씬 낮아집니다. 역설적이지만 로그가 적은 서버가 상대적으로 손해를 봅니다.
그래서 진짜 위험군은 따로 있습니다. 라즈베리파이처럼 SD 카드로 돌아가는 기기, 저가 eMMC를 쓰는 임베디드 장비입니다. 이쪽은 내구성 여유가 애초에 거의 없습니다. 라즈베리파이 SD 카드가 자꾸 죽는다는 하소연이 리눅스 커뮤니티의 오래된 레퍼토리인데, 상당 부분이 여기서 나옵니다.
AI 에이전트 시대에 이 숫자가 다시 뜨는 이유
문제 자체는 새롭지 않습니다. 저널드 쓰기 증폭 논의는 몇 년 전부터 있었습니다. 그런데 2026년 지금 다시 사람들이 이 얘기를 꺼냅니다.
코딩 에이전트와 자율 에이전트가 남기는 로그는 예전 애플리케이션과 양이 다릅니다. 에이전트 하나가 작업하면서 뭘 남기는지 떠올려보세요. 툴 호출 기록, 각 호출의 입출력, 추론 과정, 재시도 이력, 토큰 사용량. 사람이 짠 코드가 남기던 로그와는 밀도가 다릅니다.
게다가 에이전트 로그는 디버깅에 필수입니다. 결정론적으로 동작하지 않는 시스템이라, 로그가 없으면 무슨 일이 있었는지 재구성할 방법이 없습니다. 그래서 다들 로그를 더 많이, 더 상세하게 남깁니다.
관측 가능성(observability)에는 원래 청구서가 붙습니다. 그동안은 그 청구서를 SaaS 로그 수집 서비스 요금으로만 봤습니다. 그런데 청구서는 한 장이 아니었습니다. 디스크 수명이라는 두 번째 청구서가 조용히 쌓이고 있었습니다.
그래서 뭘 해야 하나
다행히 손댈 구석은 있습니다.
가장 손쉬운 건 휘발성 저장입니다. /etc/systemd/journald.conf에서 Storage=volatile로 바꾸면 저널이 /run, 즉 램디스크에만 저장됩니다. 디스크 쓰기가 아예 사라집니다. 재부팅하면 로그도 날아가니, 로그를 원격으로 수집하는 서버에 맞습니다.
동기화 주기를 늘리는 방법도 있습니다. SyncIntervalSec= 값을 기본값보다 크게 잡으면 fsync 빈도가 줄면서 증폭이 크게 완화됩니다. 대신 갑자기 전원이 나가면 최근 로그를 잃을 수 있습니다. 트레이드오프를 알고 쓰셔야 합니다.
RateLimitIntervalSec와 RateLimitBurst로 폭주하는 서비스의 로그를 제한하는 것도 방법입니다. 에이전트처럼 로그를 쏟아내는 프로세스가 있다면 특히 잘 듣습니다.
btrfs를 쓰신다면 저널 디렉터리에 chattr +C를 적용해보세요. 110KB를 49KB 수준으로 끌어내릴 수 있습니다. 단, 이 속성은 빈 디렉터리에 미리 설정해야 새로 만들어지는 파일에 적용됩니다. 기존 파일에는 소급 적용되지 않습니다.
임베디드나 라즈베리파이라면 아예 저널드를 최소화하고 가벼운 로거로 갈아타는 선택지도 있습니다. 구조화 로그의 편의를 포기하는 대신 저장장치 수명을 얻는 거래입니다.
마무리
저널드를 욕하자는 얘기가 아닙니다. 저널드는 빠른 검색과 구조화 질의, 무결성 검증이라는 목표를 제대로 달성한 소프트웨어입니다. 다만 그 대가를 어디서 치르는지 대부분의 사용자가 몰랐을 뿐입니다.
기술 선택에는 늘 청구서가 따라붙습니다. 그런데 그 청구서가 항상 눈에 보이는 곳으로 오지는 않습니다. 저널드의 청구서는 SSD의 마모 카운터에 조용히 적립되다가, 3년쯤 지나 드라이브가 죽는 날 한꺼번에 날아옵니다.
여러분의 서버는 지금 몇 KB를 쓰고 있나요? journalctl --disk-usage로 보이는 숫자와 실제 디스크에 기록된 양의 차이, 한 번쯤 확인해볼 만합니다.
댓글
댓글을 불러오는 중...