Hacker News인프라 · 데브옵스

읽기와 쓰기는 생각보다 비대칭적이다

원제 Reading and writing are less symmetric than you (probably) think

102 포인트댓글 24
Key Point

데이터 손실 방지가 중요한 애플리케이션을 개발할 때, fwrite 후 fflush/close 반환 코드와 fsync만으로는 실제 저장 보장이 부족함을 알아야 한다.

핵심 요약

  • POSIX의 read(2)와 write(2) 시스템 콜은 대칭적으로 보이지만, 실제로는 중요한 동작 차이가 있다.
  • 파일 I/O는 커널의 버퍼 캐시와 사용자 공간의 버퍼 등 여러 계층을 거친다. 블록 디바이스는 전체 블록(512바이트~4KB)만 읽고 쓸 수 있어서, 바이트 단위 I/O 요청을 정렬된 블록 연산으로 변환해야 한다.
  • 읽기 작업은 버퍼링이 투명하게 작동한다. 데이터를 채우는 과정에서 문제가 생기면 fread 호출이 반환되기 전에 감지되어 즉시 에러 코드로 보고된다.
  • 쓰기 작업은 버퍼링 때문에 에러 보고가 지연된다. fwrite는 데이터를 쓰기 버퍼로만 복사하고 즉시 성공을 반환하며, 실제 write 시스템 콜은 버퍼가 가득 차거나 fflush·fclose를 호출할 때까지 실행되지 않는다.
  • write 시스템 콜이 성공해도 데이터는 아직 커널의 버퍼 캐시에만 있고, 실제 저장 장치에 도달하지 않았을 수 있다. 장치 오류나 시스템 크래시 발생 시 손실될 수 있다.
  • NFS 같은 네트워크 파일 시스템에서는 close 호출 시점에만 쓰기 에러가 보고될 수 있으므로, close 반환 코드를 확인해야 한다.
  • 데이터가 저장 장치에 도달하도록 보장하려면 fsync(2)를 명시적으로 호출해야 한다. 단순히 write 성공 코드와 close 반환 코드를 확인하는 것만으로는 부족하다.
  • fsync 호출도 디렉토리 메타데이터가 아닌 파일 데이터만 보장한다. 파일에 접근하는 디렉토리 엔트리도 디스크에 기록되도록 하려면 디렉토리 파일 디스크립터에 fsync를 별도로 호출해야 한다.
  • RAID 컨트롤러와 저장 장치 자체도 캐시를 가지고 있으며, 전원 손실 시 안전하게 쓰기할 충분한 커패시터가 있다고 가정해야 한다.
  • 결론: 읽기 버퍼링은 투명하게 작동하지만, 쓰기 버퍼링은 에러 보고 지연과 여러 계층의 캐시로 인해 대부분의 프로그래머가 인식하지 못하는 복잡한 문제를 야기한다.
AI 요약 안내

AI가 한국어로 정리한 내용입니다. 정확한 정보는 원문을 확인해 주세요.

요약 원칙 ↗