10 KiB
id, kind, slug, title, topic, topicName, project, status, questionStatus, studio, sourceRevision, source
| id | kind | slug | title | topic | topicName | project | status | questionStatus | studio | sourceRevision | source | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| be3c2c58-1ed4-4eae-876a-3114faa61c94 | QUESTION | guest-fsync-latency-vs-host-storage-latency | Guest 의 fsync() 지연과 Host storage 지연은 같이 오르는가 | storage-virtualization | 스토리지 가상화 | virtualization | 초안 | OPEN | https://hyeonworks.com/studio/documents/be3c2c58-1ed4-4eae-876a-3114faa61c94/edit | no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 |
|
Guest 의 fsync() 지연과 Host storage 지연은 같이 오르는가
게스트 안의 fsync() 는 게스트 파일시스템과 블록 계층과 virtio-blk 와 QEMU 를 지나 호스트 스토리지까지 의미가 전달되어야 하는 요청이다. 그 전달이 이 호스트에서 실제로 이어지는지는 두 계열을 같은 시간축에 놓고 봐야 갈린다. 이 물음은 게스트 쪽 애플리케이션 지연과 호스트 쪽 스토리지 지연을 같은 타임스탬프로 남겨, 둘이 함께 움직이는지를 확인한다.
관계
- 완료라는 말의 네 가지 뜻 — write · writeback · flush · 전원 장애 생존 게스트가 받은 완료 응답이 어느 뜻인지를 그 개념이 가른다.
- Guest 의 write() 가 virtqueue 에 실리기까지 — VFS · Filesystem · Page Cache · Block Layer · virtio-blk fsync() 가 전달되어야 하는 앞쪽 경로를 그 개념이 단계로 설명한다.
- 빨라진 구성이 durability contract 를 지운 것은 아닌지 먼저 가른다 두 계열이 갈렸을 때 지연을 줄이는 방향으로 가려면 그 기준을 지나야 한다.
- 지연 원인을 CPU 로 읽기 전에 storage 계층을 따로 잰다 게스트 지연이 올랐을 때 CPU 가 아니라 스토리지를 먼저 보는 순서를 그 기준이 요구한다.
- 이 VM 들의 QEMU disk cache mode 는 무엇인가 그 값이 이 측정의 조건이므로 같은 기록에 함께 적는다.
- VM1 의 storage 부하가 VM2 의 지연을 실제로 밀어 올리는가 같은 호스트 지표를 보지만 그쪽은 다른 가상 머신의 부하가 넘어오는지를 묻는다.
- 호스트 major fault 와 스토리지 지연은 같은 시간축에서 함께 움직이는가 호스트 쪽에서 스토리지를 미는 다른 원인을 그 물음이 따로 본다.
사실
- §150 은 write(fd, data, size) 의 성공만으로는 정전 이후 생존을 보장하지 않고, 필요한 시점에 fsync(fd) 로 변경 내용을 필요한 영속성 경계까지 반영하도록 요청한다고 적었다.
- §150 은 가상 머신에서 그 요청이 지나야 하는 경로를 이렇게 그렸다. PostgreSQL, fsync(), Guest Filesystem, Guest Block Layer, FLUSH 등, virtio-blk, QEMU/Backend, Host Storage Stack, Physical Storage
- §148 은 write() 완료와 writeback 완료와 fsync/flush 완료와 전원 장애에도 안전한 durability 가 서로 같지 않다고 못박았다.
- §170 은 PostgreSQL 이 WAL 등의 durability protocol 을 사용하며 필요한 시점에 스토리지 동기화를 수행한다고 적었다. 가상 머신의 스토리지 계층이 flush 와 fsync 의 의미를 제대로 보존하지 않으면 PostgreSQL 이 전제한 영속성과 실제 스토리지 동작이 어긋날 수 있다.
- §171 은 모든 쓰기에서 스토리지 동기화를 기다리면 지연이 커질 수 있고, 특히 DB 부하에서는 fsync() 지연이 트랜잭션 지연과 연결될 수 있다고 적었다.
- §171 은 더 적극적인 캐싱으로 쓰기 지연을 개선할 수 있지만 durability semantics 는 반드시 보존해야 한다고 덧붙였다. fsync() 를 없애서 빨라졌다면 그것이 최적화가 아니라 durability contract 를 제거한 것일 수 있다.
- §169 는 호스트 관측으로 iostat -xz 1 과 iotop 을 들고, 게스트 쪽 확인 명령으로 lsblk · mount · df -h · cat /proc/mounts · iostat -xz 1 을 적었다.
- §175 OQ-8 은 게스트의 애플리케이션 지연과 호스트 iostat 를 시간축으로 함께 관찰하라고 했다.
- 이 호스트에서 두 계열을 재 본 값은 개념 문서에 없다.
가정
- 게스트에서 애플리케이션이나 데이터베이스의 지연을 시간축으로 기록할 수 있다고 본다. 그 기록에 fsync() 자체의 지연이 따로 나오는지, 아니면 트랜잭션 지연으로만 보이는지는 해 보기 전에 알 수 없다.
- 호스트와 게스트의 시계가 맞아 두 계열을 같은 타임스탬프에 놓을 수 있다고 전제한다. 어긋나 있으면 함께 움직였다는 판정 자체가 성립하지 않는다.
- 부하가 없는 구간과 있는 구간을 만들 수 있고, 두 구간에서 같은 방법으로 잴 수 있다고 본다.
- 측정 중에 캐시 모드를 비롯한 디스크 설정이 바뀌지 않는다고 두고 두 구간을 견준다.
- 같은 장치를 쓰는 다른 가상 머신이나 호스트 프로세스의 입출력이 섞일 수 있다고 보고, 어느 프로세스가 입출력을 내는지 iotop 으로 함께 남긴다.
미지수
- 게스트의 fsync() 나 트랜잭션 지연이 커지는 구간과 호스트 스토리지 지연이 커지는 구간이 시간축에서 겹치는지.
- 겹친다면 두 값이 같은 크기로 움직이는지, 게스트 쪽이 더 크게 벌어지는지.
- 게스트 지연은 오르는데 호스트 스토리지 지연이 따라 오르지 않는 구간이 있는지. 있다면 그 차이가 게스트 쪽 대기에서 생기는지 QEMU 와 백엔드 쪽에서 생기는지.
- 이때 걸려 있던 캐시 모드가 무엇인지. 그 값은 별도 물음이 읽는다.
- 게스트 쪽 지연을 어떤 단위로 기록할지. 개념 문서는 게스트에서 지연을 재는 명령을 적지 않았고 호스트 쪽 iostat 만 적었다.
제약
- 이 물음은 영속성을 줄여 지연을 낮추는 방향을 검토하지 않는다. §171 이 fsync() 를 없애 빨라진 것을 최적화로 부르지 말라고 적었고, 그런 방향은 별도 기준을 지나야 한다.
- 두 계열을 같은 시각에 남기지 못하면 이 물음은 닫히지 않는다. 나중에 따로 잰 값을 겹쳐 놓고 함께 올랐다고 적지 않는다.
- 측정 조건에 캐시 모드와 백엔드 형식과 장치 이름을 함께 적는다. 이 셋이 없으면 같은 값을 다른 환경과 견줄 수 없다.
- 측정하는 동안 다른 스토리지 실험을 같은 장치 위에서 겹쳐 돌리지 않는다.
- 호스트 지연이 오른 이유까지 이 물음이 가르지 않는다. 다른 가상 머신의 부하인지 호스트 메모리 압박인지는 그것을 재는 두 물음이 받는다.
- 그 가운데 메모리 압박 쪽 물음과는 호스트 스토리지 지표를 같이 본다. 그래도 한 물음으로 합치지 않았다. 그쪽은 호스트에서 major fault 를 유도해 그것이 스토리지를 미는지를 보고 이쪽은 게스트의 fsync() 가 호스트까지 전달되는지를 봐서, 유도 방법도 견주는 계열도 달라 한 실행으로 닫히지 않는다.
선택지
1. 부하 없는 구간과 있는 구간을 각각 찍어 두 계열을 겹친다
게스트 쪽 애플리케이션과 데이터베이스의 지연을 기록하면서 같은 시각에 호스트에서 iostat -xz 1 을 돌린다. 두 구간을 같은 방법으로 남기면 부하가 들어왔을 때 두 계열이 함께 움직였는지 그 자료에서 읽힌다. §175 OQ-8 이 적은 방법 그대로다.
게스트 쪽 지연을 무엇으로 기록할지 먼저 정해야 한다.
2. 데이터베이스 트랜잭션 부하만 걸고 fsync 쪽만 본다
§170 이 그린 WAL 경로를 따라 쓰기 위주의 트랜잭션을 돌리면 fsync() 가 지연에 직접 걸리는 구간을 만들기 쉽다. 두 계열이 어긋나는 구간을 찾기에도 이 부하가 낫다.
읽기 위주 구간에서는 어떻게 움직이는지 못 본다. §171 은 DB 부하를 예로 들었을 뿐 다른 부하를 배제하지 않았다.
3. 제외 — 캐시 모드를 바꿔 가며 두 계열을 비교한다
cache=none 과 cache=writeback 에서 두 계열이 어떻게 달라지는지 보면 전달 경로의 모양이 더 뚜렷해진다. 그러나 지금 필요한 것은 현재 구성에서 경로가 이어지는지 하나이고, 설정을 바꾸면 두 구간이 서로 다른 구성에서 나온 값이 된다. 현재 값이 무엇인지도 아직 읽지 않았다.
다음 검증
- 캐시 모드를 묻는 물음의 결과를 측정 조건으로 먼저 적는다. 함께 적을 것은 백엔드 형식과 이미지가 놓인 장치 이름이다.
- 게스트에서 애플리케이션이나 데이터베이스의 지연을 시간축으로 기록한다. 무엇으로 어떻게 기록했는지 함께 남긴다.
- 같은 시각에 호스트에서 iostat -xz 1 을 돌려 두 계열을 같은 타임스탬프로 남긴다 (§175 OQ-8).
- 부하가 없는 구간과 있는 구간을 모두 찍고, 어느 프로세스가 입출력을 내는지 iotop 으로 함께 적는다 (§169).
닫는 조건 : 두 계열이 같은 구간에서 함께 오르면 §150 이 그린 전달 경로가 이 환경에서 이어진다는 것을 확인한 것이고, 그 시계열이 Case 가 된다. 게스트의 fsync() 지연은 오르는데 호스트 스토리지 지연이 따라 오르지 않으면 그 차이가 어느 계층에서 생기는지 — 게스트 쪽 대기인지 QEMU 와 백엔드 쪽인지 — 를 다음 물음으로 넘기고 닫는다. 어느 쪽이든 성능을 위해 영속성을 줄이는 방향은 「빨라진 구성이 durability contract 를 지운 것은 아닌지 먼저 가른다」를 지나야 한다.