상세 컨텐츠

본문 제목

InnoDB Flush 계층에서 본 Direct IO (feat. Zero Copy와의 차이점)

mysql

by downfa11 2026. 1. 9. 21:54

본문

처음에는 MySQL의 디스크 쓰기 작업에 대해서 정리하다가 O_DIRECT 옵션을 보고 이런 생각이 들었다.

zero copy랑 비슷한 얘기 아닌가? 둘 다 불필요한 복사를 줄여서 성능을 개선하는건데.

 
궁금해져서 그 차이가 궁금해져서 좀 더 파고들어봤다.  본 내용은 MySQL 8.0을 기준으로 작성했다. 
 

MySQL의 디스크 쓰기(Flush)

DB 튜닝시 귀에 피나도록 'disk IO를 최소화해야해'라는 말을 들었을 것이다.
 
Full table scan이 아니라 Index range scan을 그렇게 강조하고 buffer_pool에 가능한 많은 데이터를 둘려는 이유이다.
 
여기서 말하는 디스크 접근, 즉 메모리에 적재된 데이터를 디스크에 영속적으로 기록하는 행위를 Flush라고 한다. 문제는 그 피나던 말처럼 Flush 비용이 생각보다 비싸다는 점이다..
 
일반적으로 시스템은 데이터를 바로 디스크에 기록하지 않는다. 메모리에 두면서 쓰기 작업들을 모아서 한번에 하는걸 본 적이 있을 것이다.
 
이른바 지연된 쓰기(delayed write)라고 하는데, 보통 버퍼 크기(batch_size)를 채우던가 일정 시간(linger_ms)이 지나면 Flush하는 식으로 disk IO를 줄이는 '배치 쓰기'로 이해하면 된다.
 
우리는 데이터를 어느정도 크기, 시간동안 메모리에 적재한 채로 두는가에 따라서 장애 발생시 유실 가능성을 점칠 수 있다. 그래서 Flush 주기나 조건은 항상 데이터베이스 튜닝시 민감한 영역이 된다.
 

쓰기 부하가 심해지면 나타나는 증상

다들 쓰기 부하가 발생하면 가장 먼저 commit 지연이 발생하는걸 performance_schema 로그를 통해 본 경험이 있을 것이다.
 
기본적으로 durability를 위해서 커밋시 binlog와 undo log flush하는데 2번의 fsync가 이뤄지기 때문에, 인덱스를 타지 않는 쿼리부터 시작해서 전체적으로 쿼리들이 느려지기 시작하는 거다.
 

MySQL의 innodb_flush_method 옵션

MySQL 튜닝시 InnoDB 스토리지 엔진에서 Flush 작업을 어떻게 수행할 건지 결정하는 innodb_flush_method 옵션이 존재한다.

  • fsync: 데이터와 metadata 로그를 모두 디스크에 sync하는 syscall
  • O_DIRECT: metadat 로그의 읽기 작업시는 Direct IO를 이용해서 빠르게 가져오고, 쓰기 작업은 안전하게 fsync하는 방식

 

1. Buffered IO

일반적으로 OS 수준의 캐시로 읽기 속도를 올린다.
 
그러니까, DB에 저장된 내용을 디스크에 기록하기 전에 커널 영역(OS Page Cache)에 캐싱하는 과정이 발생한다.

fsync 방식의 flush 동작

 
하지만 InnoDB는 훨씬 고도화된 Buffer Pool이 존재하기 때문에, OS 캐싱 과정이 불필요하다.
 
Page Cache가 보조 캐시 역할을 한다면 시너지가 나겠지만 그렇지 않은 경우에는 메모리 낭비로 이어진다. (double buffering)
 

2. Direct IO

이를 위해서 커널 영역에 캐싱하는 중간 과정을 생략한 채로 디스크와 직접 접근하는 Direct IO 기술이 사용된다.

O_DIRECT 방식의 flush 동작

 
user space의 InnoDB가 데이터를 캐시하면서 OS cache를 무시하는 셈이다.
 
플랫폼에 따라서 fdatasync()을 지원하는 경우가 있는데, 얘는 metadat만 필요할때 fsync하는 식으로 디스크 IO를 최소화한다.
 
여담으로 O_DSYNC라는 친구도 있긴 한데.. 몰라도 될거 같다. metadata 로그만 O_SYNC, 데이터는 fsync 하는 방식으로 대부분의 UNIX 계통 InnoDB에서 더이상 지원하지 않고 있다.
 

3. fdatasync() vs O_DIRECT

이런 설명만 보면 자연스럽게 O_DIRECT가 항상 더 좋아 보인다. 불필요한 캐시 과정이 생략되면서 메모리 이점을 볼 수 있으면 좋은거 아닌가 싶지만 역시 은탄환은 없다.
 
아래 블로그에서 직접 flush_method에 따라서 벤치마크를 진행한 결과가 있다.

 

MySQL innodb_flush_method 튜닝 포인트 | Mimul Tech blog

MySQL InnoDB 스토리지 엔진을 사용하면 매개 변수 innodb_flush_method가 있는데 이 설정 값의 의미와 테스트를 통해 튜닝 포인트를 검토.

www.mimul.com

 
buffer_pool의 크기가 128M 이하일때 fdatasync 방식이 우세하고, 128M 이후부터는 O_DIRECT 방식이 더 높은 결과를 보여주고 있다.

 
작성자분께서는 buffer pool의 크기가 더 작은 경우에서 fsync 계열이 성능이 더 잘 나온 이유로 Page Cache가 제 역할(여기서는 보조 캐시)을 해준 것이라 보셨다.
 
모든 데이터가 buffer pool에 들어갈 크기는 되어야 O_DIRECT의 성능적 이점이 나온다고 설명하셨다.
 
'추측하지 말라, 데이터를 보고 계산된 예측을 하라' 라고 하시는데 진짜 DBA같아서 심금을 울린다.... 너무멋있으니 다들 보고 가삼
 

Zero Copy와의 차이점

둘 다 불필요한 복사 과정을 최소화해서 성능을 개선하는 기술이라는 점에서 비슷하다고 생각했다. 그럼 어떤 차이점이 있을까?
 
비교를 위해서 직접 그렸다.
 

 
 
direct IO같은 경우는 Page Cache(kernel)를 건너뛰고 디스크에 바로 접근한다. (OS 캐싱 과정을 생략)

 

수정) 위에서 한번 얘기했지만, 내용이 부실했던 부분이 있어서 보충하겠다.

 

metadata 로그의 읽기는 direct IO, 쓰기는 안전하게 fsync한다고만 설명했었다. 데이터 쓰기/읽기시에는 모두 Direct IO 처리한다.
 

 
zero copy는 커널 영역에서 fs의 종류에 따라서 다른 Page Cache나 Socket Buffer로 전달한다. (User Buffer 복사를 생략)
 
이 둘은 겉보기에 비슷해보여도 서로 생략하는 복사의 영역도 다르고 그 목적도 다르다.

  • Direct IO: 중간자 역할인 커널모드 캐싱을 건너뛰고 전달
  • Zero copy: 유저모드로의 복사를 건너뛰고 전달

zero copy 자체가 비동기 통신쪽에서 자주 언급되다 보니 소켓 네트워크 기술 내지는 SKB로만 가는걸로 오해할 수 있다. 하지만 파일도 소켓도 모두 file descriptor라는 점!!
 
 
출처 및 인용.
https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_method
https://medium.com/@nuwanwe/innodb-flush-method-balancing-performance-and-data-integrity-d39d8ac50766

관련글 더보기