fsync 없이 로컬 스토리지 엔진을 crash-consistent하게 만든 방법
Removing fsync from our local storage engine
TL;DR Highlight
FractalBits가 fsync 없이 SSD 전용 KV 스토리지 엔진을 구현해 동일 조건 대비 약 65% 높은 쓰기 성능을 달성한 설계 방법을 공유했다. fsync의 메타데이터 오버헤드를 피하기 위해 사전 할당, O_DIRECT, SSD 원자 쓰기 단위 정렬 저널을 조합한 구조가 핵심이다.
Who Should Read
고성능 로컬 스토리지나 KV 엔진을 직접 구현 중인 시스템 개발자, 또는 기존 오브젝트 스토리지(MinIO 등)의 쓰기 지연 문제를 파악하고 싶은 인프라 엔지니어.
Core Mechanics
- fsync는 파일 데이터뿐 아니라 inode, 디렉터리 엔트리, extent map, 파일시스템 저널 커밋까지 전부 플러시한다. 실제로 수 KB짜리 write 하나가 내부적으로 수십 배 규모의 I/O를 유발할 수 있다.
- fsync 호출 한 번의 지연시간은 SSD 기준으로 수백 마이크로초에서 수 밀리초에 이른다. 게다가 동시 I/O, 파일시스템 저널 상태, SSD의 GC(가비지 컬렉션) 활동에 따라 tail latency가 중앙값 대비 몇 배씩 튀는 게 문제다.
- 주요 스토리지 시스템들의 fsync 전략을 비교해보면: MinIO는 데이터와 메타데이터 모두 fdatasync/fsync, etcd는 Raft 안전성을 위해 모든 엔트리에 fsync, Postgres는 WAL 커밋 시 fsync + group commit으로 지연 분산, Kafka는 기본적으로 fsync를 아예 안 쓰고 복제(replication)에만 의존한다.
- 이 엔진의 핵심 전제조건은 세 가지다: SSD 전용 배포, 수백 바이트~수백 KB 범위의 값 크기, 단일 키 단위의 원자적 write 의미론(쓰기가 완전히 보이거나 완전히 안 보이거나). 이 조건 중 하나라도 벗어나면 설계를 처음부터 다시 해야 한다.
- 엔진은 index, journal, data area 세 컴포넌트로 구성된다. index는 키→값 위치 매핑이며 주로 메모리에 상주하고, journal은 index와 data area 할당 상태 변경을 기록하는 crash-consistency 경계이며, data area는 실제 값을 저장한다.
- fsync 없이 crash-consistency를 유지하는 핵심 기법은 고정 크기 사전 할당(pre-allocated) 파일 + 사전 제로화(pre-zeroed extents) 조합이다. 런타임에 새 파일을 생성하거나 파일 크기를 변경하지 않아서 inode/디렉터리 엔트리 변경이 발생하지 않는다.
- O_DIRECT 쓰기를 SSD의 원자적 쓰기 단위(atomic-write unit)에 맞게 정렬해서 저널 커밋을 수행한다. 이렇게 하면 저널 블록 하나가 '완전히 기록되거나 전혀 기록되지 않는' 원자성이 보장돼 fsync 없이도 복구 일관성을 확보할 수 있다.
- AWS i8g.2xlarge 로컬 NVMe 환경에서 4KB 랜덤 쓰기 벤치마크 결과, 이 엔진은 190,985 obj/s를 기록했고 ext4 + O_DIRECT + fsync 조합은 116,041 obj/s였다. 약 65% 성능 향상이다.
Evidence
- O_DIRECT만으로는 충분하지 않다는 회의적인 의견이 많았다. O_DIRECT는 OS 페이지 캐시를 우회할 뿐이고, 드라이버 메모리나 드라이브 내부의 비내구성 캐시에 데이터가 남아있을 수 있어서 '커밋 성공'을 반환할 수 없다는 지적이다. 실질적인 durability 보장을 위해서는 ATA/NVMe FUA(Force Unit Access) 명령이 전송되어야 한다는 의견이 제기됐다.
- WAL 블록 순서 보장 문제도 지적됐다. fsync 없이는 이전 WAL 블록이 현재 블록보다 먼저 디스크에 쓰였다는 보장이 없고, SSD는 내부적으로 쓰기를 재정렬할 수 있어서 전원 손실 시 로그에 '구멍(hole)'이 생겨 잘못된 복구가 일어날 수 있다는 우려가 나왔다.
- O_DSYNC를 O_DIRECT와 함께 쓰면 더 정확하다는 대안 제시도 있었다. O_DSYNC는 필요한 경우 디스크 쓰기에 FUA를 추가해서 내구성을 확보하므로, 이 엔진의 설계에 추가하면 durability 보장이 명확해진다는 의견이었다.
- 유사한 S3 호환 단일 노드 스토리지(hs5)를 만든 개발자가 댓글을 달았는데, 자신은 데이터와 메타데이터 durability를 위해 제대로 fsync를 사용하지만 옵션으로 끌 수 있게 해뒀다고 했다. 그는 WAL에 체크섬과 시퀀스 번호를 써서 잘못된 데이터 커밋을 방지하고 있으며, WAL만 fsync를 비활성화하는 모드를 추가하는 건 좋은 생각이 아닐 것 같다고 했다.
- 글쓴이(Author)가 직접 댓글에서 'fsync 전체 부정이 아니다'라고 명확히 선을 그었다. 이 설계는 SSD 전용 배포, 사전 할당 파일, O_DIRECT, 단일 키 원자성, 디바이스 쓰기 보장이라는 전제조건이 모두 충족될 때만 성립하며, 그 외 환경에는 적용하면 안 된다고 밝혔다.
How to Apply
- SSD 전용 단일 노드 KV 스토리지를 직접 구현하는 경우, 고정 크기 파일을 미리 할당(fallocate)하고 내용을 제로화해두면 런타임에 inode나 extent map 변경이 발생하지 않아 fsync의 메타데이터 오버헤드를 없앨 수 있다.
- O_DIRECT 쓰기를 사용할 때 SSD의 atomic-write unit 크기(보통 4KB 또는 512B)에 맞춰 저널 커밋 블록을 정렬하면, FUA나 fsync 없이도 단일 블록 단위의 원자적 쓰기를 활용해 crash-consistency를 확보할 수 있다.
- 기존 코드에서 MinIO나 RocksDB 기반으로 쓰기 지연이 크다면, 각 시스템의 fsync 동작(MinIO의 fdatasync, RocksDB WAL의 sync_log_entry_cache 설정 등)을 먼저 프로파일링해서 병목이 메타데이터 동기화인지 확인한 후 설계 변경 여부를 판단하는 게 좋다.
- O_DIRECT만으로 durability를 보장했다고 착각하지 않도록, 실제 운영 환경에서는 O_DSYNC를 함께 사용하거나 NVMe FUA 명령이 실제로 발행되는지 확인하는 테스트를 포함시켜야 한다. 그렇지 않으면 드라이브 내부 캐시에서 전원이 끊길 경우 데이터 유실이 발생한다.
Terminology
관련 논문
Swift로 LLM 학습시키기 Part 1: 행렬 곱셈을 Gflop/s에서 Tflop/s로 끌어올리기
Apple Silicon에서 Swift로 직접 행렬 곱셈 커널을 구현하며 CPU, SIMD, AMX, GPU(Metal)를 단계별로 최적화해 Gflop/s에서 Tflop/s 수준까지 성능을 높이는 과정을 상세히 설명한 글이다. 프레임워크 없이 LLM 학습의 핵심 연산을 밑바닥부터 구현하고 싶은 개발자에게 Apple Silicon의 성능 한계를 체감할 수 있는 드문 자료다.
Google Chrome, 사용자 동의 없이 4GB AI 모델(Gemini Nano)을 몰래 설치
Google Chrome이 사용자 동의 없이 Gemini Nano 4GB 모델 파일을 자동 다운로드하고, 삭제해도 재다운로드되는 문제가 발견됐다. GDPR 위반 가능성과 수십억 대 기기에 적용될 때의 환경 비용 문제가 제기되고 있다.
OpenAI가 대규모 저지연 Voice AI를 제공하는 방법
OpenAI가 9억 명 이상의 사용자에게 실시간 음성 AI를 제공하기 위해 WebRTC 스택을 어떻게 재설계했는지 설명하는 글로, relay + transceiver 분리 아키텍처의 설계 결정과 trade-off를 상세히 다룬다.
Truncated Decoding Tree의 결정론적 탐색을 통한 효율적인 Test-Time Inference
Self-consistency의 중복 샘플링 낭비를 없애는 결정론적 트리 탐색 디코딩 기법 DLE로 수학/코드 추론 성능과 속도를 동시에 개선
GoModel – Go로 작성된 오픈소스 AI Gateway
OpenAI, Anthropic, Gemini 등 여러 AI 프로바이더를 하나의 OpenAI 호환 API로 묶어주는 Go 기반 오픈소스 AI 게이트웨이로, LiteLLM의 컴파일 언어 대안이다.
Claude Token Counter 업그레이드: 모델 간 토크나이저 비교 기능 추가
Claude Opus 4.7이 새 토크나이저를 도입하면서 같은 입력에 대해 최대 1.46배 더 많은 토큰을 소비한다는 사실이 확인됐고, 이는 사실상 40% 이상의 비용 인상 효과다.