{ "schemaVersion": 4, "project": "virtualization", "ssot": "final/document.md", "ssotSha256": "181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd", "sourceRevision": "no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다", "generatedAt": "2026-09-09", "sourceRepository": { "name": "없음 — 코드 저장소를 분석해 쓴 문서가 아니다", "path": "/home/donghyeon/workspace/chat-gpt-container/document-haness/docs/virtualization/final/document.md", "revision": null, "verified": "이 프로젝트에는 분석한 저장소가 없다. 출발점은 사용자가 밖에서 쓴 문서 한 편이고, 체크아웃이 아니라 반입한 파일이 근거를 고정한다. 그래서 path 는 그 문서의 현재 자리인 final/document.md 다. 반입할 때의 원본(절 23개 · sha256 2b7b386de841f3e7b408066b39efaf183804b3d158d78d88e7fa0b7e00e08d69)은 source/kvm-cpu-virtualization-ssot.md 에 두었다가, 사용자가 §24~§28 을 더해 final/document.md 가 그 상위 집합이 된 뒤 지웠다 — heading marker 를 뺀 본문을 대조해 지워진 문장이 없음을 확인했다. 코드를 읽고 쓴 글이 아니라 고정할 커밋이 없어 revision 은 null 로 둔다. 지어내지 않는다." }, "candidateScope": { "document": "final/document.md", "sections": [ "2. 전체 구조", "3. 각 구성요소의 역할", "4. vCPU와 vCPU Thread", "5. Host Linux Scheduler와 실제 CPU", "6. KVM_RUN과 Guest 실행", "7. VM Entry와 VM Exit", "8. 무엇이 실제로 VM Exit을 발생시키는가", "9. VM Exit 이후 처리", "10. Guest가 idle이면 물리 CPU는 어떻게 되는가", "11. VM의 4 vCPU는 정확히 무엇을 의미하는가", "12. CPU contention과 overcommit", "13. Steal Time", "14. 실제 Linux에서 확인할 수 있는 것", "15. CPU 가상화 관점에서 장애를 보는 방법", "16. 현재 Keycloak/K3s 실험과의 관계", "17. 동시성 테스트와 부하 테스트를 분리해야 한다", "18. Bare-metal K3s와 VM 기반 K3s의 차이", "19. 이 SSOT에서 파생될 CONCEPT", "20. 이 CONCEPT에서 파생되는 OPEN QUESTION", "21. OPEN QUESTION에서 CASE가 만들어지는 흐름", "22. 현재 단계의 핵심 Claim", "23. 다음 단계", "24. CPU 가상화 계층에서 발생할 수 있는 문제", "25. CPU 문제를 계층별로 구분하는 진단표", "26. 현재 Keycloak 실험에서 CPU 문제를 오판하지 않기 위한 기준", "27. 문제 영역에서 파생되는 추가 OPEN QUESTION", "28. CONCEPT -> OPEN QUESTION -> CASE 적용 기준", "29. 이 문서에서 먼저 고정할 전체 구조", "30. 일반 Linux의 Virtual Memory부터 시작한다", "31. Page와 Physical Frame", "32. Virtual Address = Page + Offset", "33. Guest Page Table", "34. MMU: 실제 주소 변환을 수행하는 CPU 하드웨어", "35. TLB: 주소 변환 결과의 CPU Cache", "36. Bare Metal과 VM의 차이", "37. EPT(Extended Page Tables)", "38. 왜 EPT가 필요한가", "39. Shadow Page Table과 EPT의 의미", "40. QEMU는 Guest RAM을 어떻게 준비하는가", "41. KVM_SET_USER_MEMORY_REGION", "42. Configured Memory와 실제 Physical RAM 사용량은 같지 않을 수 있다", "43. Guest Page Table 자체도 메모리에 있다", "44. 정상 Memory Access는 매번 VM Exit하지 않는다", "45. Guest Page Fault", "46. Page Fault의 대표적인 원인", "47. EPT Violation", "48. Guest Page Fault와 EPT Violation 비교", "49. Host Page Fault도 별도로 존재한다", "50. Huge Page가 필요한 이유", "51. Huge Page와 TLB Coverage", "52. VM에서 Huge Page를 볼 때 주의할 점", "53. THP: Transparent Huge Pages", "54. THP의 Trade-off", "55. HugeTLB", "56. THP와 HugeTLB 비교", "57. Memory Overcommit", "58. CPU Overcommit과 Memory Overcommit의 차이", "59. Host Memory Pressure와 Reclaim", "60. Host Swap이 VM에 미치는 영향", "61. Guest Swap과 Host Swap", "62. Memory Pressure와 Storage Contention의 연결", "63. Swap Used만 보고 장애를 판단하면 안 된다", "64. Ballooning이 필요한 이유", "65. virtio-balloon 구조", "66. Balloon Inflate", "67. Balloon Page 반환의 의미", "68. Balloon Deflate", "69. Ballooning을 과도하게 하면 Guest가 압박을 받는다", "70. Ballooning과 Memory Hotplug", "71. OOM", "72. Guest OOM과 Host OOM", "73. NUMA", "74. Local Memory와 Remote Memory", "75. vCPU와 NUMA의 연결", "76. vCPU Pinning만으로는 NUMA 최적화가 끝나지 않는다", "77. Guest NUMA", "78. NUMA는 실제 장비 topology부터 확인한다", "79. 전체 Memory Virtualization 실행 경로", "80. 전체 Memory Virtualization 관리 경로", "81. CPU / Network / Storage / Memory 연결", "82. 핵심 Claim Registry", "83. 실제 환경에서 확인할 OPEN QUESTION", "84. 권장 실험 순서", "85. 실험 시 반드시 같이 기록할 것", "86. 문제를 진단할 때의 분류", "87. 최종 기준 그림", "88. 결론", "89. 문서 목적", "90. virsh / libvirt / virtio 구분", "91. virtio-net은 정확히 어디에 있는가", "92. Frontend와 Backend", "93. Guest OS는 왜 QEMU가 아니라 virtio-net을 사용하는가", "94. 전체 네트워크 계층", "95. Physical NIC의 역할", "96. Linux Bridge의 역할", "97. Routing의 역할", "98. NAT의 역할", "99. TAP의 역할", "100. virtqueue의 역할", "101. Guest TCP/IP Stack의 역할", "102. Packet이 Keycloak까지 올라오는 과정", "103. QEMU virtio Device Model의 역할", "104. 왜 `TAP → vhost-net → QEMU → virtqueue`라고 일반화하면 안 되는가", "105. Control Path와 Data Path", "106. QEMU가 Userspace인데 packet이 QEMU를 안 거칠 수 있는 이유", "107. vhost-net 최적화", "108. vhost-net은 QEMU를 제거하지 않는다", "109. Fast Path와 Slow/Control Path", "110. Data Copy 최적화", "111. Interrupt / Notification 최적화", "112. Multi-Queue 최적화", "113. Offload 최적화", "114. Linux Bridge가 항상 Host TCP/IP Stack을 거치는 것은 아니다", "115. Host Physical NIC로 나갈 때 virtio를 다시 거치지 않는다", "116. 현재 Keycloak/K3s 테스트 환경과 연결", "117. 이 구조에서 발생할 수 있는 문제", "118. 실제 Linux에서 확인할 명령어", "119. 실제 packet path 추적", "120. Keycloak Refresh Token 실험과의 관계", "121. 이 SSOT에서 파생될 CONCEPT", "122. OPEN QUESTION", "123. OPEN QUESTION → CASE", "124. 핵심 Claim", "125. 최종 기준 구조", "126. 다음 실습 순서", "127. 문서 목적", "128. 전체 구조", "129. Guest Application: `read()` / `write()`에서 시작", "130. VFS: 공통 파일 인터페이스 계층", "131. Filesystem(ext4/XFS): 파일 세계를 block 공간에 배치", "132. inode", "133. Page Cache: `write()`가 바로 SSD write는 아니다", "134. Guest Block I/O Layer", "135. `/dev/vda`: Guest가 보는 가상 Block Device", "136. `/dev/vda`와 Filesystem 관계", "137. virtio-blk: Guest의 가상 Block Device Driver", "138. virtio-blk와 virtqueue", "139. virtqueue의 실제 의미", "140. VM Boundary를 넘으면 QEMU가 등장", "141. QEMU가 물리 SSD를 직접 제어하는 것은 아니다", "142. qcow2: Host에서는 파일, Guest에서는 디스크", "143. qcow2 Virtual Size와 실제 Host 사용량", "144. RAW Image", "145. Host Block Device를 직접 backend로 사용 가능", "146. 실제 연결 확인", "147. VM에서는 Page Cache가 두 번 나타날 수 있다", "148. `write()` 완료와 영속화는 다르다", "149. Direct I/O", "150. `fsync()`가 필요한 이유", "151. FLUSH", "152. 가장 위험한 상황: 거짓 완료", "153. QEMU Cache Mode", "154. `cache=none`", "155. `cache=writeback`", "156. `writeback = 위험`이라고 단정하면 안 되는 이유", "157. Device-side Cache", "158. Host Block Layer", "159. 여러 VM이 하나의 NVMe를 공유하면", "160. blk-mq: Multi-Queue Block Layer", "161. I/O Scheduler", "162. `none`", "163. 실제 I/O Scheduler 확인", "164. NVMe Driver와 Physical Device", "165. NVMe와 SSD 구분", "166. Storage I/O Completion", "167. Storage Contention", "168. CPU가 정상이어도 Storage 때문에 느릴 수 있다", "169. Storage 관측 명령어", "170. PostgreSQL 예시: WAL과 Durability", "171. 성능과 Durability의 Trade-off", "172. Storage Virtualization Canonical Flow", "173. Network Virtualization과 비교", "174. 핵심 Claim", "175. 실제 테스트 서버에서 확인할 Open Questions", "176. 권장 실습 흐름", "177. 최종 요약" ], "excluded": [ "1. 이 문서의 범위" ], "excludedAnchorPattern": "#1-이-문서의-범위$", "note": "접어 넣은 분석이 아니라 처음부터 한 편으로 쓴 개념 문서라 제2부·제3부가 없다. 대신 이 문서 자신이 네 부다 — 제1부 CPU 가상화(§1~§28) · 제2부 메모리 가상화(§29~§88) · 제3부 네트워크 가상화(§89~§126) · 제4부 스토리지 가상화(§127~§177). 네 부 모두가 후보를 찾는 범위이고 sections 는 그 절 제목을 부 순서대로 적는다. 지금 sections 에 있는 것은 제1부 §2~§28 과 제2부 §29~§88 이고, 제3부와 제4부는 그 부를 분해할 때 같은 형식으로 뒤에 덧붙인다. §1 은 이 문서가 무엇을 다루고 무엇을 안 다루는지를 선언한 자리라 후보가 나오는 곳이 아니다 — 글감이 그 선언을 근거로 인용할 수는 있어서 concept 노드의 source 에는 들어 있고, excludedAnchorPattern 은 §1 만 가리키는 앵커로 올라온 글감을 막는다. 앵커 형식은 `final/document.md#

` 하나로 통일한다. ── 제3부(네트워크 가상화 §89~§126)를 분해하면서 그 절 제목 38개를 sections 뒤에 덧붙였다. ── 제4부(스토리지 가상화 §127~§177)를 분해하면서 그 절 제목 51개를 다시 뒤에 덧붙였다. 이제 sections 에는 네 부가 모두 들어 있다 — 제1부 §2~§28 · 제2부 §29~§88 · 제3부 §89~§126 · 제4부 §127~§177, 합쳐 176개이고 남은 부는 없다. excluded 와 excludedAnchorPattern 은 §1 그대로다." }, "assetLedger": { "note": "final/assets/diagrams/ 의 그림 아홉 장. 부마다 개념 기록이 한 장씩 받았고, 배정되지 않은 그림은 없다. 개념 열하나 가운데 셋은 그림을 안 받았다 — huge-pages-in-a-vm 과 qemu-block-backend-forms 는 본문의 비교표가 답해 3단계가 청구하지 않았고, memory-pressure-reclaim-swap-oom 은 4단계가 근거 절 §62 로 그리려다 멈췄다(그 절이 「Guest와 Host가 동시에 memory pressure를 겪으면」이라고 적어 순서가 없는데, techviz 가 그 문맥에서 허용하는 profile 이 순서를 요구하는 sequence 하나뿐이었다. 순서를 지어내야 그려진다).", "assigned": [ "vm-exit-handling-cycle", "guest-memory-address-translation-path", "page-fault-layers-in-a-vm", "virtio-balloon-inflate-deflate", "numa-vcpu-and-memory-placement", "packet-control-and-data-paths", "guest-block-io-to-virtqueue", "write-completion-boundaries", "vms-sharing-one-nvme" ], "unassigned": [] }, "contract": { "decomposition": [ "글감을 찾는 입력은 final/document.md 하나다. 거기에 없는 근거는 먼저 SSOT 에 넣는다.", "후보 전부는 candidates 에 처분과 함께 남고 PROMOTE 만 topics 로 올라간다.", "없애고 관련 Case 나 Concept 의 한 절로 넣어도 이해·결정·재사용성이 그대로라면 독립 기록으로 만들지 않는다.", "Topic 은 독자 질문 하나다. 그 물음에 답하지 않는 글감은 다른 Topic 으로 옮긴다.", "Concept 은 Case·Decision·Question 을 먼저 고른 뒤 그것을 이해하는 데 필요한 것만 거꾸로 더한다." ], "anchorStyle": "final/document.md#

. 제목에서 ` * ( ) , : · — ? . / 를 공백으로 바꾸고 연속 공백을 - 로 접고 소문자로 내린 것이다.", "readinessValues": [ "READY", "OPEN", "NEEDS_EVIDENCE", "NEEDS_DECISION", "BLOCKED" ], "dispositionValues": { "PROMOTE": "독립 Tech Log 로 쓴다", "MERGE_INTO": "다른 기록의 한 절·표 행으로 흡수한다", "KEEP_IN_SSOT": "분석에는 남기고 독립 기록으로 만들지 않는다 — 정상적인 성공 결과다", "NEEDS_EVIDENCE": "주장에 아직 검증이 없다. 측정한 뒤에 다시 판정한다", "NEEDS_DECISION": "방향이 그럴듯하지만 프로젝트가 정하지 않았다", "BLOCKED": "원본이 불완전하거나 서로 어긋난다" } }, "note": "프로젝트 virtualization 의 SSOT 는 네 부다 — CPU(§1~§28) · 메모리(§29~§88) · 네트워크(§89~§126) · 스토리지(§127~§177). 네 부를 모두 분해했고 지금 주제는 넷, 글감은 57개다 — cpu-virtualization 13 · memory-virtualization 20 · network-virtualization 10 · storage-virtualization 14. 네 주제 모두 case 와 decision 이 0 이고 이유는 하나다 — 이 SSOT 에는 이 테스트 Host 에서 잰 값이 하나도 없고 측정이 없으면 Case 가 아니다. 아래는 부마다 무엇을 어떻게 판단했는지를 분해한 순서대로 이어 적은 기록이다. ── 제1부(CPU 가상화 §1~§28)는 주제 하나에 concept 하나로 내려앉았다. 하나로 둔 근거는 SSOT 자신이다 — §19 가 이 실행 경로를 하나의 CONCEPT 로 관리하고 여러 문서로 과도하게 분할하지 않는다고 적었고, §28 이 CONCEPT 에서 확정할 범위를 「구조적으로 어떤 문제가 발생할 수 있는가 · 어떤 지표로 의심할 수 있는가 · 어느 계층에서 확인해야 하는가」로 그었다. 검사기는 그 시점에 「Topic 에 노드가 하나뿐이다」를 warn 으로 냈다. 그것이 그때 이 프로젝트의 상태였고 노드를 늘려서 지우지 않았다 — 뒤에 §20·§27 을 재판정해 question 열둘을 올리면서 그 warn 이 사라졌다. 이 SSOT 에는 이 테스트 Host 에서 잰 값이 하나도 없다. 그 상태에서 §20·§27 의 OPEN QUESTION 열둘을 question 글감으로 올렸다 — Question 은 아직 닫히지 않은 판단을 적는 종류라 측정이 없다는 것이 올리지 못할 이유가 아니고, 값이 나오면 그때 Case 가 된다. OQ 하나에 글감 하나이고 열둘의 known 에는 SSOT 가 서술한 것만 적었다. 측정이 필요한 Claim(SSOT-22-claims-12-13)은 그대로 NEEDS_EVIDENCE 다 — 그것은 「이 환경에서 실제로 그러하다」는 주장이라 재기 전에는 Case 도 Question 도 아니다. Topic 은 하나로 두었다. 열둘이 전부 「구조적으로 가능한 문제가 이 Host 에서 실제로 일어나는가」를 묻고 있어 cpu-virtualization 의 독자 질문 뒷부분(어느 계층의 문제인지 무엇을 보고 가르는가)에 그대로 걸린다. 주제를 나누면 개념과 그 개념이 낳은 물음이 갈라진다. final/assets 의 첫 그림은 vm-exit-handling-cycle 한 장이고 assetLedger 에 배정으로 적었다 — §9 가 그린 VM Exit 이후 제어권 경로다. 이 단계에서 final/document.md 의 frontmatter 를 떼고 heading 단계를 맞췄다 — 절이 h1 이면 앵커가 가리킬 절이 없다. 절을 h2, 그 아래를 h3·h4 로 내렸고 본문 문장은 한 글자도 바꾸지 않았다. ── 제2부(메모리 가상화 §29~§88)는 절 60개이고 주제 하나 (memory-virtualization) 에 글감 20개로 내려앉았다 — concept 여섯 · reference 둘 · question 열둘, case 와 decision 은 0 이다. concept 을 여섯으로 나눈 것은 절을 훑어서가 아니라 §83 의 OPEN QUESTION 을 먼저 고른 뒤 그 물음들이 읽히려면 무엇을 미리 알아야 하는지를 거꾸로 물어서다 — 주소 변환(OQ-2·3 이 필요로 한다) · page fault 세 계층(OQ-13·14) · huge page(OQ-4·5) · 메모리 압박(OQ-6·7·14) · ballooning(OQ-8·9) · NUMA(OQ-11·12) 여섯이 그렇게 나왔고 남는 개념은 없다. CPU 부가 §19 의 「하나의 CONCEPT 로 관리하고 여러 문서로 과도하게 분할하지 않는다」를 근거로 한 편으로 묶은 것과 달리 제2부에는 그런 지시가 없고, §52·§58·§61·§70·§72 처럼 「A 와 B 는 같지 않다」로 경계를 긋는 절이 계속 나와 한 편으로 묶으면 그 경계들이 한 글의 각주가 된다. case 가 0 인 이유는 제2부에도 이 테스트 Host 에서 잰 값이 하나도 없기 때문이다 — 측정이 없으면 Case 가 아니다. §82 의 CLAIM-MEM-01~18 은 전부 메커니즘 서술이라(「~할 수 있다」·「A 와 B 는 다르다」) 여섯 개념에 나눠 흡수했고, CPU 부의 Claim 12·13 처럼 「이 환경에서 실제로 그러하다」고 주장한 것이 없어 NEEDS_EVIDENCE 로 남길 것도 없었다. §83 의 OQ 열넷 가운데 열둘만 올렸다 — OQ-1(Host NUMA topology)과 OQ-10(vCPU 가 어느 Host CPU 에 있는가)은 CPU 부의 question:host-numa-topology 가 이미 묻고 있고 그 unknown 이 「두 VM 의 vCPU 와 memory 가 어느 node 에 배치되어 있는지」를 그대로 담고 있어 MERGE_INTO 로 두었다. 같은 한 번의 측정으로 닫히는 물음을 두 편으로 만들지 않는다. 그 질문이 「SSOT 는 이 확인에 쓸 명령을 적지 않았다」고 남긴 자리에 §83 이 적은 `lscpu` · `numactl --hardware` · `virsh vcpuinfo`/`vcpupin` 이 들어간다. 넘겨받은 쪽은 OQ-11(QEMU memory 가 어느 node 에 있는가 — `numastat -p` 는 CPU 부 어디에도 없다)과 OQ-12(remote access 가 latency 를 바꾸는가)다. reference 둘은 §85 와 §86 에서 나왔다 — 열두 Question 전부에 같이 걸리는 규칙이라 각 글에 되풀이하는 대신 한 편씩으로 두었다. 제2부의 그림은 아직 없다 — assetLedger 는 그대로다. ── 제3부(네트워크 가상화 §89~§126)를 분해했다. 절 38개이고 주제 하나(network-virtualization)에 글감 10개로 내려앉았다 — concept 하나 · reference 둘 · question 일곱, case 와 decision 은 0 이다. concept 을 하나로 둔 근거는 §121 이다. 그 절이 virsh 부터 Packet tracing 까지 스물한 요소를 한 목록으로 묶고 「이 요소들이 하나의 packet 실행 경로를 설명하므로 하나의 CONCEPT 로 관리한다」고 적었다. 제1부의 §19 가 CPU 실행 경로에 대해 같은 지시를 했고 그 부도 개념 하나였다. 제2부를 여섯으로 나눈 것은 거기에 그런 지시가 없었기 때문이지 절 수가 많아서가 아니다. 넷으로 쪼개는 안 — 경로 · backend 주체(§103~§109) · Host 쪽 배선(§95~§99·§114) · 최적화(§110~§113) — 을 놓고 봤지만 SSOT 가 반대로 적은 것을 뒤집을 근거를 SSOT 안에서 찾지 못해 기각했다. case 가 0 인 이유는 제3부에도 이 테스트 Host 에서 잰 값이 하나도 없기 때문이다 — 측정이 없으면 Case 가 아니다. §124 의 Claim 1~16 은 전부 메커니즘 서술이라 개념에 흡수했고, 「이 환경에서 실제로 그러하다」고 주장한 것은 §116 하나뿐이라 그것만 NEEDS_EVIDENCE 로 남겼다 — Host Nginx 아래 VM 두 대라는 앞부분은 §89 가 밝힌 실험 구성이지만 TAP → vhost-net → virtqueue 로 펼친 뒷부분은 OQ-1·2·3·6 이 답하기 전의 가정이다. CPU 부의 SSOT-22-claims-12-13 과 같은 처분이다. §122 의 OQ 일곱은 전부 올렸다 — 다른 부의 question 이 같은 측정으로 닫는 물음이 하나도 없었다. 가장 가까운 것이 OQ-7 과 CPU 부의 question:virtualization-layer-saturation-during-refresh 인데, OQ-7 이 재라고 적은 vhost thread 와 softirq 는 제1부·제2부 어디에도 나오지 않는다(§81 의 그림에 vhost 라는 낱말이 한 번 나올 뿐이다). 두 물음은 같은 실험 구간에서 서로 다른 스레드를 재므로 relations 로만 이었다. reference 둘은 §119 와 §120 에서 나왔다. §119 는 네 지점의 capture O/X 로 끊긴 구간을 좁히는 절차이고 §120 은 그것이 network 문제인지 애플리케이션·저장소 문제인지를 가르는 귀속 규칙이라 답하는 물음이 다르다. 둘 다 적용 조건과 예외를 SSOT 가 스스로 대 준다 — §113·§114 가 앞의 예외를, §102·§116 이 뒤의 예외를 댄다. 제1부에서 §14(명령 목록)와 §15(계층 분리)를 개념으로 흡수한 것과 판단이 갈리는데, 그때 적은 이유는 「붙일 Reference 가 없다」였고 제2부가 §85·§86 으로 기준을 바꿨다. 여기서는 제2부 쪽을 따랐고 §118 의 명령 목록은 §119 의 Reference 본문 표로 들어간다. 제3부의 그림은 아직 없다 — assetLedger 는 그대로다. ── 제4부(스토리지 가상화 §127~§177)를 분해했다. 절 51개이고 주제 하나(storage-virtualization)에 글감 14개로 내려앉았다 — concept 넷 · reference 셋 · question 일곱, case 와 decision 은 0 이다. concept 을 넷으로 나눈 것은 절을 훑어서가 아니라 §175 의 OQ 여덟을 먼저 고른 뒤 그 물음들이 읽히려면 무엇을 미리 알아야 하는지를 거꾸로 물어서다 — Guest 쪽 경로(OQ-1·OQ-8 이 필요로 한다) · backend 형태(OQ-1·OQ-2·OQ-3·OQ-5) · 완료의 네 가지 뜻(OQ-4·OQ-8) · Host block stack 과 경쟁(OQ-5·OQ-6·OQ-7) 넷이 그렇게 나왔고 남는 개념은 없다. 제1부와 제3부는 §19 와 §121 이 「하나의 CONCEPT 로 관리하고 여러 문서로 과도하게 분할하지 않는다」고 적어 한 편으로 묶었지만 제4부에는 그런 지시가 없고, §144·§148·§149·§152·§156·§157·§162·§165·§167·§168·§171 처럼 「A 는 B 가 아니다」로 경계를 긋는 절이 계속 나와 한 편으로 묶으면 그 경계들이 한 글의 각주가 된다 — 제2부를 여섯으로 나눈 것과 같은 이유다. 경로를 한 장으로 그린 §128·§172·§177 은 첫 개념에 흡수했다. 네 개념이 나눠 설명하는 지도라 어느 하나가 소유하지 않지만, 경로가 시작하는 글이 그림을 열고 나머지 셋이 자기 구간을 가리키는 편이 그림 하나를 다섯 번째 기록으로 만드는 것보다 낫다 — 제2부가 §79·§87 을 같은 이유로 첫 개념에 넣었다. case 가 0 인 이유는 제4부에도 이 테스트 Host 에서 잰 값이 하나도 없기 때문이다. §143 의 100 GB/3GB 도 §168 의 CPU 30%/latency 2초 도 SSOT 가 예시로 든 값이지 이 장비에서 잰 값이 아니다. §174 의 Claim 1~6 은 전부 메커니즘 서술이라(「~할 수 있다」·「A 와 B 는 같은 의미가 아니다」) 개념 둘과 Reference 하나에 나눠 흡수했고, 제1부의 Claim 12·13 이나 제3부의 §116 처럼 「이 환경에서 실제로 그러하다」고 주장한 절이 없어 NEEDS_EVIDENCE 로 남길 것도 없었다. §175 의 OQ 여덟 가운데 일곱만 올렸다 — OQ-2(qcow2 인가 RAW 인가)는 OQ-3 과 같은 한 번의 `qemu-img info` 출력으로 닫히고 형식은 그 출력의 첫 줄이라 MERGE_INTO 로 두었다. 제2부가 OQ-1 과 OQ-10 을 합친 것과 같은 판단이다. 다른 부의 question 과는 하나도 겹치지 않았다 — 가장 가까운 둘이 OQ-7 과 제1부의 question:vcpu-contention-under-two-vm-load, OQ-8 과 제2부의 question:host-major-fault-vs-storage-latency 인데 앞의 짝은 부하 형태가 같을 뿐 재는 자원이 CPU 와 storage 로 다르고, 뒤의 짝은 한쪽이 memory pressure 로 유도한 major fault 를 보고 다른 쪽이 애플리케이션의 `fsync()` 를 보므로 유도 방법도 계열도 다르다. 둘 다 relations 로만 이었다. reference 셋은 §168·§171·§145 에서 나왔다. §168 은 지연을 CPU 로 귀속하기 전에 storage 를 따로 재라는 자원 귀속 규칙이고, §171 은 빨라진 구성이 durability contract 를 지운 것은 아닌지 가르라는 평가 규칙이고, §145 는 Guest 안에서 본 disk 로 backend 를 단정하지 말라는 확정 규칙이라 셋이 답하는 물음이 다르다. 셋 다 적용 조건과 예외를 SSOT 가 스스로 대 준다 — §167·§169·§177 이 첫째의, §149·§154·§157 이 둘째의, §143·§144 가 셋째의 예외를 댄다. NEEDS_DECISION 하나를 남겼다 — cache mode 를 무엇으로 둘 것인가는 §153~§156 이 두 설정의 뜻만 갈라 놓고 방향을 정하지 않았고, 현재 값이 무엇인지도 OQ-4 가 아직 확인하지 않았다. 제4부의 그림은 아직 없다 — assetLedger 는 그대로다.", "topics": { "cpu-virtualization": { "topic": "cpu-virtualization", "title": "CPU 가상화 — vCPU 가 물리 CPU 에서 실행되기까지", "readerQuestion": "VM 에 준 vCPU 는 Host 의 어느 CPU 에서 언제 실행되고, Guest 안이 느릴 때 그것이 어느 계층의 문제인지 무엇을 보고 가르는가?", "kinds": { "case": [], "concept": [ { "title": "KVM 에서 vCPU 가 물리 CPU 에서 실행되기까지", "kind": "concept", "slug": "kvm-vcpu-to-physical-cpu", "readiness": "READY", "source": [ "final/document.md#1-이-문서의-범위", "final/document.md#2-전체-구조", "final/document.md#3-각-구성요소의-역할", "final/document.md#4-vcpu와-vcpu-thread", "final/document.md#5-host-linux-scheduler와-실제-cpu", "final/document.md#6-kvm_run과-guest-실행", "final/document.md#7-vm-entry와-vm-exit", "final/document.md#8-무엇이-실제로-vm-exit을-발생시키는가", "final/document.md#9-vm-exit-이후-처리", "final/document.md#10-guest가-idle이면-물리-cpu는-어떻게-되는가", "final/document.md#11-vm의-4-vcpu는-정확히-무엇을-의미하는가", "final/document.md#12-cpu-contention과-overcommit", "final/document.md#13-steal-time", "final/document.md#14-실제-linux에서-확인할-수-있는-것", "final/document.md#15-cpu-가상화-관점에서-장애를-보는-방법", "final/document.md#16-현재-keycloak-k3s-실험과의-관계", "final/document.md#18-bare-metal-k3s와-vm-기반-k3s의-차이", "final/document.md#19-이-ssot에서-파생될-concept", "final/document.md#22-현재-단계의-핵심-claim", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제", "final/document.md#25-cpu-문제를-계층별로-구분하는-진단표", "final/document.md#26-현재-keycloak-실험에서-cpu-문제를-오판하지-않기-위한-기준", "final/document.md#28-concept-->-open-question-->-case-적용-기준" ], "basis-version": "x86_64 Intel VMX(VT-x) · Linux KVM(`kvm` · `kvm_intel`) · QEMU/libvirt · VM 안의 K3s cgroup CPU limit. SSOT 가 커널·QEMU·libvirt 버전을 한 번도 적지 않아 특정 버전에 고정하지 않는다 — 여기 적힌 것은 이 문서가 서술한 구성이고, 버전이 바뀌어 서술이 낡았는지는 §23 의 검증을 실제 Host 에서 돌릴 때 드러난다. AMD 는 `kvm_amd`/SVM 로 대응한다는 사실까지만 SSOT 에 있다.", "classification": "§19 가 이 실행 경로를 하나의 CONCEPT 로 관리하고 여러 문서로 과도하게 분할하지 않는다고 적었다. virsh 에서 물리 CPU 까지가 한 인과 흐름이라 절 단위로 쪼개면 어느 조각도 혼자 서지 않는다 — vCPU thread 를 빼면 Host Scheduler 절이 무엇을 스케줄링하는지 말할 수 없고, VM Exit 을 빼면 Guest idle 이 왜 CPU 를 놓는지 말할 수 없다. §24 의 문제 열하나와 §25 의 진단표도 같은 경로 위의 자리들이라 이 글이 그 경로를 설명한 뒤라야 읽힌다. 근거는 문서가 서술한 메커니즘이고, 이 Host 에서 잰 값은 없다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. VM Exit 분포도, steal time 도, vCPU thread 가 실제로 logical CPU 사이를 옮겨 다니는지도 재지 않았다. §28 이 그은 경계대로 이 글은 「구조적으로 어떤 문제가 가능한가 · 어떤 지표로 의심하나 · 어느 계층에서 확인하나」까지만 말하고, 현재 서버에서 실제로 일어나는지는 사실로 확정하지 않는다. 재야 할 것은 §20·§27 의 OPEN QUESTION 열둘에 적혀 있고, 그 열둘은 이제 이 주제의 Question 글감 열둘이 되어 무엇을 재면 닫히는지를 각각 따로 적고 있다.", "relations": [ "question:vcpu-thread-migration-without-pinning", "question:vm-exit-distribution-by-workload", "question:vcpu-contention-under-two-vm-load", "question:throttling-vs-contention", "question:is-production-on-a-hypervisor", "question:host-numa-topology" ], "ssot-assets": [ "vm-exit-handling-cycle" ], "publication": "게시됨", "file": "cpu-virtualization/concept/concept-kvm-vcpu-to-physical-cpu.md", "status": "초안", "studioId": "5bcae89b-0873-4a2b-af4a-10e5234c085b", "assets": [ "vm-exit-handling-cycle" ], "assetFiles": [ "vm-exit-handling-cycle" ], "evidenceFiles": [] } ], "reference": [], "question": [ { "title": "가상 머신 두 대에 동시에 부하를 주면 이 호스트에서 vCPU 경쟁이 실제로 생기는가", "kind": "question", "slug": "vcpu-contention-under-two-vm-load", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-1", "final/document.md#12-cpu-contention과-overcommit", "final/document.md#16-현재-keycloak-k3s-실험과의-관계" ], "known": "§12 는 Host 12 logical CPU 에 8 vCPU VM 넷을 올린 예를 들어, 총 32 vCPU thread 가 12 logical CPU 위에서 Host CPU 시간을 두고 경쟁할 수 있고 그때 Guest application 이 느려진 원인이 application 이 아니라 Host CPU contention 일 수 있다고 적었다. §16 이 서술한 테스트 환경은 Physical Host 아래 Host Nginx 와 VM 두 대이고 각 VM 이 K3s 노드와 Keycloak 을 돌린다. §20 은 이 물음의 확인 대상으로 Host logical CPU 수 · 각 VM vCPU 수 · QEMU vCPU thread CPU 사용량 · Host run queue · Guest steal time 다섯을 적었다. 이 Host 의 logical CPU 수도 두 VM 의 vCPU 수도 SSOT 어디에도 적혀 있지 않다.", "unknown": "이 Host 의 logical CPU 수와 두 VM 의 vCPU 합, 그리고 그 합이 logical CPU 를 넘는지. 넘든 넘지 않든 두 VM 에 동시에 부하를 걸었을 때 QEMU vCPU thread 사용량과 Host run queue 와 각 Guest 의 steal time 이 실제로 어떻게 움직이는지.", "next-verification": "§20 의 확인 대상 다섯 가운데 정적인 둘 — Host logical CPU 수와 각 VM vCPU 수 — 을 먼저 적는다. 그 다음 VM 1 과 VM 2 에 동시에 CPU 부하를 걸고, 부하 전과 부하 중 두 시점에 Host 에서 `ps -eLo pid,tid,psr,pcpu,comm | grep qemu` (§14.7) 로 QEMU vCPU thread 의 CPU 사용량을, Host run queue 를, 각 Guest 에서 `top` (§14.8) 으로 `%st` 를 같은 시각에 기록한다.", "decision-criterion": "두 VM 의 vCPU 합이 Host logical CPU 이하이고 동시 부하에서도 Guest `%st` 와 Host run queue 가 부하 전과 다르지 않으면, 이 Host 구성에서는 contention 이 관측되지 않는다고 적고 닫는다. `%st` 나 run queue 가 움직이면 그 부하 전후 표가 Case 가 되고 이 질문은 그 Case 가 닫는다. vCPU 수를 줄일지 VM 배치를 바꿀지는 그 Case 가 나온 뒤 Decision 으로 넘긴다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:steal-time-increase-under-two-cpu-bound-vms" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-vcpu-contention-under-two-vm-load.md", "status": "초안", "studioId": "eba4a877-276a-4050-9a97-d32614546c71", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가", "kind": "question", "slug": "virtualization-layer-saturation-during-refresh", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-2", "final/document.md#16-현재-keycloak-k3s-실험과의-관계", "final/document.md#26-현재-keycloak-실험에서-cpu-문제를-오판하지-않기-위한-기준" ], "known": "§16 은 Keycloak 실험 구조 아래에 KVM 계층이 하나 더 붙는다고 적고, 결과를 해석할 때 분리해야 할 원인으로 Keycloak refresh/session 동시성 · PostgreSQL contention/locking · Redis 상태 관리 · K3s resource scheduling · VM vCPU scheduling · Host CPU saturation · Nginx/LB 를 들었다. §26 은 같은 것을 Application/Auth · Storage · K3s · Guest · Virtualization · Host 여섯 경계로 다시 그렸다. §20 은 이 물음에서 Host CPU · Guest CPU · steal time · Keycloak latency · DB/Redis latency 를 동시에 관찰하라고 적었고 그 목적이 refresh 경쟁과 Host resource contention 을 분리하는 것이라고 밝혔다.", "unknown": "refresh 경쟁 실험을 돌리는 동안 그 다섯 지표가 실제로 어떤 값을 갖는지, 그리고 가상화 계층 쪽 지표(Host CPU · steal time)가 실험 결과를 다르게 읽어야 할 만큼 움직이는지.", "next-verification": "refresh 경쟁 실험을 돌리면서 §20 이 적은 다섯 지표를 같은 시각에 기록한다 — Guest 의 steal time 은 `top` (§14.8), Host 쪽 QEMU vCPU thread 는 `ps -eLo pid,tid,psr,pcpu,comm | grep qemu` (§14.7), Keycloak 과 DB/Redis latency 는 실험이 이미 재는 값을 그대로 쓴다. 실험을 걸기 전 같은 다섯을 한 번 찍어 기준값으로 둔다.", "decision-criterion": "실험 구간의 Host CPU 와 steal time 이 기준값과 다르지 않으면, 그 실험 결과를 application/storage 문제로 읽어도 된다고 적고 닫는다. 둘 중 하나라도 움직이면 §26 의 여섯 경계를 분리해 다시 재고, refresh 경쟁 실험을 CPU 여유 상태에서 따로 돌릴지는 Decision 으로 넘긴다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:vcpu-contention-under-two-vm-load", "question:throttling-vs-contention" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-virtualization-layer-saturation-during-refresh.md", "status": "초안", "studioId": "da3a7b56-5691-4a9f-90c5-3a1a5d0f0013", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "게스트가 유휴 상태일 때 vCPU 스레드는 이 테스트 환경에서 어떻게 보이는가", "kind": "question", "slug": "idle-vcpu-thread-appearance", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-3", "final/document.md#10-guest가-idle이면-물리-cpu는-어떻게-되는가", "final/document.md#14-실제-linux에서-확인할-수-있는-것-14-6" ], "known": "§10 은 Guest 가 idle 이면 vCPU thread 가 block/sleep 상태로 들어가고 Host 는 그 CPU 시간을 다른 workload 에 쓸 수 있다고 적었다. §14.6 은 `ps -T -p ` 와 `top -H -p ` 로 vCPU 관련 thread 를 Host 에서 관찰할 수 있다고 하면서, 환경과 QEMU 버전에 따라 thread 이름이 다를 수 있다는 단서를 함께 달았다. §20 은 Guest idle 상태와 CPU workload 상태를 비교하라고 적고 확인 명령으로 `top -H -p ` 와 `ps -eLo pid,tid,psr,pcpu,stat,comm` 둘을 들었다.", "unknown": "이 환경에서 QEMU 의 vCPU thread 가 어떤 이름으로 보이는지, idle 과 부하 상태에서 그 thread 의 `pcpu` 와 `stat` 가 실제로 어떻게 갈리는지.", "next-verification": "VM 을 idle 로 둔 채 `top -H -p ` 와 `ps -eLo pid,tid,psr,pcpu,stat,comm` 을 찍는다. 같은 VM 에 CPU workload 를 걸고 같은 두 명령을 다시 찍어 두 출력을 나란히 둔다 (§20 이 적은 확인 명령 그대로).", "decision-criterion": "idle 에서 vCPU thread 의 `pcpu` 가 0 에 가깝고 `stat` 가 sleep 계열이며 부하에서 실행 상태로 바뀌면, §10 의 서술이 이 환경에서도 성립하는 것으로 개념의 확인 사례에 흡수하고 닫는다. 두 상태에서 출력이 갈리지 않거나 §10 과 반대로 나오면 그 출력이 Case 가 된다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:vcpu-thread-migration-without-pinning" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-idle-vcpu-thread-appearance.md", "status": "초안", "studioId": "4a2d3332-81c3-44fa-a4fb-216a41abb504", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "실제 작업에서 주로 발생하는 VM Exit 은 무엇인가", "kind": "question", "slug": "vm-exit-distribution-by-workload", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-4", "final/document.md#8-무엇이-실제로-vm-exit을-발생시키는가", "final/document.md#14-실제-linux에서-확인할-수-있는-것-14-9" ], "known": "§8 은 VM Exit 을 일으키는 동작으로 HLT · I/O Port 접근 · CPUID · Control Register 접근 · MSR 접근 · Exception · External Interrupt 를 들고, 무엇이 Exit 을 일으킬지는 root 권한이 아니라 VMCS 의 VM-Execution Control 설정과 동작 종류가 정한다고 적었다. §14.9 는 `sudo perf kvm stat live` 를 예로 들면서 지원되는 명령과 표시되는 Exit reason 이 kernel · perf 버전 · CPU architecture 및 설정에 따라 다를 수 있으니 `perf kvm --help` 를 함께 확인하고 필요하면 KVM tracepoint tracing 도 검토하라고 적었다. §20 의 비교 후보는 idle · CPU-bound workload · I/O-heavy workload · Keycloak 정상 요청 · Keycloak 부하 테스트 다섯이다.", "unknown": "이 Host 에서 `perf kvm` 또는 KVM tracepoint 가 실제로 열리는지, 열린다면 §20 이 든 다섯 workload 의 Exit reason 분포가 서로 얼마나 다른지.", "next-verification": "먼저 `perf kvm --help` 로 이 환경이 지원하는 하위 명령을 확인한다. 열리면 `sudo perf kvm stat live` 로 §20 의 비교 후보 다섯을 각각 돌리며 Exit reason 분포를 받아 적는다. 열리지 않으면 §14.9 가 말한 KVM tracepoint tracing 을 검토하고 그 결과도 기록한다.", "decision-criterion": "다섯 workload 의 Exit reason 분포를 한 표로 놓을 수 있으면 그 표가 Case 가 되고 닫는다. `perf kvm` 도 tracepoint 도 이 환경에서 열리지 않으면, 「이 Host 에서는 Exit 분포를 관측할 수 없다」를 그대로 적고 §24.9 의 확인 항목에서 Exit reason 을 빼는 근거로 남긴 뒤 닫는다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:exit-distribution-for-keycloak-workload" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-vm-exit-distribution-by-workload.md", "status": "초안", "studioId": "61b7486f-5dab-41df-8f4f-e8fc21d88617", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "pinning 없이 vCPU 스레드는 호스트 논리 CPU 사이를 옮겨 다니는가", "kind": "question", "slug": "vcpu-thread-migration-without-pinning", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-5", "final/document.md#5-host-linux-scheduler와-실제-cpu", "final/document.md#14-실제-linux에서-확인할-수-있는-것-14-7" ], "known": "§5 는 vCPU thread 도 다른 Host thread 와 같이 Linux Scheduler 가 실행할 logical CPU 를 정한다고 적었다. §14.7 은 `ps -eLo pid,tid,psr,pcpu,comm | grep qemu` 의 `PSR` 로 thread 가 최근 실행된 logical CPU 를 관찰할 수 있고, 이것이 vCPU 가 물리 CPU 에 영구 고정되어 있다는 뜻은 아니며 pinning 을 하지 않았다면 스케줄링에 따라 달라질 수 있다고 적었다. §20 은 `PSR` 과 scheduler tracing 으로 관찰하라고만 적었다.", "unknown": "이 Host 에서 pinning 없이 같은 vCPU thread 의 `PSR` 이 시간에 따라 실제로 바뀌는지, 바뀐다면 부하가 있을 때와 없을 때가 다른지. 현재 두 VM 에 affinity 가 걸려 있는지도 SSOT 에 적혀 있지 않다.", "next-verification": "`ps -eLo pid,tid,psr,pcpu,comm | grep qemu` 를 일정 간격으로 여러 번 찍어 같은 tid 의 `PSR` 이 바뀌는지 본다. Guest 가 idle 일 때와 CPU 부하가 있을 때를 나눠 각각 찍고, 같은 실행에서 그 VM 에 affinity 설정이 있는지도 함께 적는다 (§14.7 · §20).", "decision-criterion": "관측 구간에서 같은 tid 의 `PSR` 이 바뀌면 이동한다는 사실을 개념의 확인 사례로 흡수하고 닫는다 — 그 이동이 성능에 영향을 주는지는 OQ-10 이 받는다. `PSR` 이 고정으로 나오면 affinity 설정을 먼저 확인하고, 설정이 없는데도 고정이면 그 관측이 Case 가 된다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:pinning-before-and-after", "question:idle-vcpu-thread-appearance" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-vcpu-thread-migration-without-pinning.md", "status": "초안", "studioId": "cd58d35d-3a93-4682-82b8-b64ce3a8813c", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "운영 서버는 CPU 가상화 계층의 영향을 받는 구조인가", "kind": "question", "slug": "is-production-on-a-hypervisor", "readiness": "OPEN", "source": [ "final/document.md#20-이-concept에서-파생되는-open-question-oq-6", "final/document.md#18-bare-metal-k3s와-vm-기반-k3s의-차이", "final/document.md#25-cpu-문제를-계층별로-구분하는-진단표" ], "known": "§18 은 bare-metal K3s 가 Host scheduler 로 바로 가는 것과 달리 VM 기반 K3s 에는 vCPU · QEMU thread · KVM/VMX 계층이 더 붙는다고 적었다. §20 은 두 경로를 `K3s -> Host Scheduler -> Physical CPU` 와 `K3s -> Guest -> vCPU -> Hypervisor -> Physical CPU` 로 나란히 적고, 구조에 따라 진단 지표가 달라진다고 밝혔다. §25 의 진단표에는 Virtualization·Host 계층에만 있는 행이 따로 있다. 운영 서버가 둘 중 어느 쪽인지는 SSOT 에 적혀 있지 않다.", "unknown": "운영 서버가 bare-metal Host 에 직접 K3s 를 설치한 것인지, 상위 Hypervisor 나 Cloud VM 위에 있는지.", "next-verification": "운영 서버의 구성 기록이나 도입 경로로 bare-metal 인지 Hypervisor/Cloud VM 위인지 확인한다. 서버에 붙을 수 있으면 §14.1~§14.3 의 `grep -E 'vmx|svm' /proc/cpuinfo` · `lsmod | grep kvm` · `ls -l /dev/kvm` 으로 그 장비가 VM 을 직접 돌리는 Host 인지부터 적고, Guest 안에서 `top` 의 `%st` (§14.8) 가 관측되는지를 함께 본다.", "decision-criterion": "운영 서버가 bare-metal 로 확인되면 §25 의 Virtualization·Host 행을 운영 진단에서 빼도 된다고 적고 닫는다. Hypervisor 나 Cloud VM 위로 확인되면 그 사실이 운영 진단의 전제가 되고, §25 의 어느 행을 운영에서 쓸지는 그 뒤 Decision 이 정한다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-is-production-on-a-hypervisor.md", "status": "초안", "studioId": "2acec7d5-3eaf-4115-9d61-45647c4ec01e", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "가상 머신 두 대를 CPU-bound 로 만들면 게스트 steal time 은 얼마나 오르는가", "kind": "question", "slug": "steal-time-increase-under-two-cpu-bound-vms", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-7", "final/document.md#13-steal-time", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-4" ], "known": "§13 은 steal time 이 Guest vCPU 에 실행할 작업이 있는데 다른 workload 때문에 즉시 실행되지 못하는 상황을 가리키는 단서이며, 그것 하나만으로 원인을 확정하지 말고 Host CPU saturation · run queue · affinity · workload 를 함께 확인해야 한다고 적었다. §24.4 는 steal time 증가를 Guest 에서 관측되는 문제로 놓고 우선 확인할 것을 `%st` 와 Host contention 으로 적었다. §27 은 이 물음에서 Host CPU utilization · run queue · QEMU vCPU thread · 각 Guest 의 `%st` 를 함께 측정하라고 적었다. 이 Host 에서 `%st` 를 실제로 잰 값은 없다.", "unknown": "두 VM 을 동시에 CPU-bound 로 만들었을 때 각 Guest 의 `%st` 가 부하 전 대비 얼마나 오르는지, 그 증가가 Host run queue 와 같은 방향으로 움직이는지.", "next-verification": "부하 전에 Host CPU utilization 과 run queue, `ps -eLo pid,tid,psr,pcpu,comm | grep qemu` (§14.7) 의 QEMU vCPU thread 사용량, 각 Guest 의 `top` (§14.8) `%st` 를 기준값으로 남긴다. 그 다음 VM 두 대를 동시에 CPU-bound 로 만들고 같은 네 항목을 같은 시각에 다시 기록한다 (§27 이 적은 측정 항목 그대로).", "decision-criterion": "부하 전후의 `%st` 와 Host run queue 를 한 표로 놓을 수 있으면 그 표가 Case 가 되고 닫는다. `%st` 가 부하 전과 다르지 않으면 이 Host 구성에서는 두 VM 동시 부하가 steal time 으로 나타나는 경쟁을 만들지 않는다고 적고 OQ-1 과 함께 닫는다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:vcpu-contention-under-two-vm-load", "question:throughput-vs-vcpu-count" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-steal-time-increase-under-two-cpu-bound-vms.md", "status": "초안", "studioId": "2d058fb5-01f1-4be8-80bb-0e377868573c", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "vCPU 를 늘릴수록 이 호스트에서 Keycloak 처리량도 계속 오르는가", "kind": "question", "slug": "throughput-vs-vcpu-count", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-8", "final/document.md#11-vm의-4-vcpu는-정확히-무엇을-의미하는가", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-6" ], "known": "§11 은 4 vCPU 가 실행 컨텍스트 4개이지 물리 CPU 4개를 영구히 예약한 것이 아니라고 적었다. §24.6 은 vCPU 를 많이 준다고 항상 빨라지는 것은 아니며, Guest workload 가 그만큼의 병렬성을 쓰지 못하거나 Host 전체 CPU 에 비해 지나치게 많은 vCPU 를 주면 scheduling 대상만 늘 수 있으니 실제 workload 의 병렬성과 Host capacity 를 함께 확인해야 한다고 적었다. §27 은 비교 구성으로 2 vCPU / 4 vCPU / 8 vCPU 를 들었다.", "unknown": "이 Host 에서 vCPU 를 2 → 4 → 8 로 올렸을 때 Keycloak 처리량과 latency 가 어디서부터 더 좋아지지 않는지. 좋아지지 않는다면 그것이 workload 의 병렬성 부족 때문인지 Host capacity 부족 때문인지.", "next-verification": "VM 구성을 2 vCPU · 4 vCPU · 8 vCPU 로 바꿔 가며 같은 Keycloak 부하를 걸고 처리량과 latency 를 각각 기록한다. 세 실행 모두에서 Host logical CPU 수 대비 총 vCPU 와 Guest 의 `top` `%st` (§14.8) 를 함께 남겨, §24.6 이 말한 병렬성 부족과 Host capacity 부족을 갈라 둔다 (§27 이 든 비교 구성 그대로).", "decision-criterion": "처리량이 더 오르지 않기 시작하는 vCPU 수가 나오면 그 지점을 이 workload 의 상한으로 적고 그 세 실행이 Case 가 된다. 세 구성이 모두 같은 방향으로 오르면 이 Host 에서는 상한에 닿지 않았다고 적고 닫는다. 어느 vCPU 수로 운영할지는 그 뒤 Decision 이 정한다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:steal-time-increase-under-two-cpu-bound-vms" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-throughput-vs-vcpu-count.md", "status": "초안", "studioId": "723d8930-9e82-4552-8376-038a6446ec71", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "cgroup CPU 제한과 호스트 vCPU 경쟁을 지표로 가를 수 있는가", "kind": "question", "slug": "throttling-vs-contention", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-9", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-8", "final/document.md#25-cpu-문제를-계층별로-구분하는-진단표" ], "known": "§24.8 은 Host CPU 에 여유가 있어도 container cgroup 의 CPU limit 때문에 Keycloak Pod 실행이 제한될 수 있다고 적고, 「Host CPU 를 받지 못함」과 「Pod 가 자신의 CPU quota 를 초과함」을 구분해야 한다고 밝혔다. throttling 자체는 KVM 문제가 아니지만 VM 안에서 K3s 를 운영하는 지금 실험에서는 같은 application latency 로 관찰될 수 있어 진단 경계에 포함한다고도 적었다. §25 의 진단표는 CPU throttling 의 우선 확인 항목을 CPU limit · throttled time 으로, CPU contention 은 Host CPU · run queue · per-CPU usage 로 갈라 적었다. §27 은 둘을 의도적으로 재현해 Guest/Host/K3s 지표 차이를 비교하라고 적었다.", "unknown": "같은 크기의 application latency 증가를 두 원인으로 각각 재현했을 때 §25 가 갈라 놓은 지표들이 실제로 갈리는지, 갈린다면 어느 지표가 가장 먼저 갈리는지.", "next-verification": "같은 크기의 Keycloak latency 증가를 두 번 만든다 — 한 번은 Keycloak Pod 의 cgroup CPU limit 을 낮춰서, 한 번은 다른 VM 에 CPU 부하를 걸어서. 두 실행에서 Pod 의 throttled time 과 CPU limit, Guest CPU 와 `top` `%st` (§14.8), Host CPU 와 run queue 를 같은 항목으로 받아 적고 나란히 놓는다 (§27 · §25 의 두 행).", "decision-criterion": "두 재현에서 지표 조합이 갈리면 그 대조표가 Case 가 되고, §25 의 두 행을 어떤 순서로 보는지를 정하는 근거가 된다. 갈리지 않으면 「이 지표들로는 두 원인이 구분되지 않는다」를 적고, 무엇을 더 봐야 하는지를 새 Question 으로 낸 뒤 이 질문은 닫는다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:virtualization-layer-saturation-during-refresh" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-throttling-vs-contention.md", "status": "초안", "studioId": "116b806c-b176-401c-9363-1489fffb721c", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "CPU pinning 전후로 Keycloak 지연과 vCPU 스케줄링 변동이 달라지는가", "kind": "question", "slug": "pinning-before-and-after", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-10", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-7", "final/document.md#14-실제-linux에서-확인할-수-있는-것-14-7" ], "known": "§24.7 은 CPU pinning 이 특정 vCPU thread 를 특정 Host logical CPU 에 제한하는 것이고, 적절히 쓰면 scheduling 변동을 줄일 수 있지만 잘못 설정하면 특정 CPU 에 workload 가 집중될 수 있다고 적었다. 그래서 pinning 여부만 보지 말고 실제 per-CPU utilization 과 affinity 를 함께 확인해야 한다고 밝혔다. §14.7 은 `PSR` 이 thread 가 최근 실행된 logical CPU 를 보여 주고 pinning 을 하지 않았다면 스케줄링에 따라 달라질 수 있다고 적었다. §27 은 pinning 이 현재 workload 에서 실제 이점을 주는지는 실험으로 확인한다고 적었다.", "unknown": "pinning 전후로 Keycloak latency 가 달라지는지, `PSR` 변동이 실제로 줄어드는지, 줄어드는 대신 §24.7 이 말한 대로 특정 CPU 로 workload 가 몰리는지.", "next-verification": "pinning 없이 Keycloak 부하를 걸어 latency 와 `ps -eLo pid,tid,psr,pcpu,comm | grep qemu` (§14.7) 의 `PSR` 변동과 per-CPU 사용량을 남긴다. vCPU thread 를 고정한 뒤 같은 부하를 다시 걸어 같은 세 가지를 남기고 두 실행을 나란히 놓는다 (§27 · §24.7).", "decision-criterion": "pinning 뒤 latency 가 좋아지고 per-CPU 사용량이 특정 CPU 로 몰리지 않으면, pinning 을 쓸지 말지를 Decision 으로 넘긴다 — 그 Decision 이 감수할 비용은 §24.7 이 적은 「잘못 설정하면 특정 CPU 에 workload 가 집중된다」이다. 두 실행에서 latency 차이가 없으면 이 workload 에서는 pinning 이 이점을 주지 않는다고 적고 닫는다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:vcpu-thread-migration-without-pinning" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-pinning-before-and-after.md", "status": "초안", "studioId": "62319064-17ef-4b2f-bf8b-e363cd0e36a6", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Keycloak 작업의 VM Exit 분포는 idle · CPU-bound · I/O-bound 와 어떻게 다른가", "kind": "question", "slug": "exit-distribution-for-keycloak-workload", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-11", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-9", "final/document.md#14-실제-linux에서-확인할-수-있는-것-14-9" ], "known": "§24.9 는 VM Exit 이 정상적인 가상화 동작이라 존재한다는 것 자체는 문제가 아니고, 특정 workload 에서 Exit 이 지나치게 빈번하고 처리 비용이 커질 때 성능에 영향을 줄 수 있다고 적었다. 볼 때는 Exit 횟수만이 아니라 Exit reason · workload 종류 · 처리 위치가 KVM 인지 QEMU userspace 인지 · application latency 와 Exit 증가가 함께 나타나는지를 같이 보라고 적었다. §14.9 는 지원되는 명령과 표시되는 Exit reason 이 kernel · perf 버전 · CPU architecture 및 설정에 따라 다를 수 있다고 단서를 달았다. §27 은 가능하면 `perf kvm` 또는 KVM tracepoint 로 Exit reason 분포를 비교하라고 적었다.", "unknown": "Keycloak workload 구간의 Exit reason 분포가 idle · CPU-bound · I/O-bound 구간과 얼마나 다른지, 그 차이가 같은 구간의 Keycloak latency 와 같이 움직이는지.", "next-verification": "OQ-4 에서 `perf kvm` 또는 KVM tracepoint 가 이 환경에서 열린다는 것을 먼저 확인한다. 열리면 idle · CPU-bound · I/O-bound · Keycloak 정상 요청 · Keycloak 부하 다섯 구간의 Exit reason 분포를 받고, 같은 구간의 Keycloak latency 를 나란히 적는다 (§27 · §24.9 가 함께 보라고 한 네 항목).", "decision-criterion": "Keycloak 구간의 Exit 분포가 다른 구간과 다르고 그 차이가 latency 와 같이 움직이면 그 측정이 Case 가 되고 닫는다. 분포가 다르지 않거나 latency 와 따로 움직이면, 이 workload 에서 Exit overhead 는 조사 대상이 아니라고 적고 §25 의 「과도한 VM Exit」 행을 뒤로 미루는 근거로 남긴 뒤 닫는다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu", "question:vm-exit-distribution-by-workload" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-exit-distribution-for-keycloak-workload.md", "status": "초안", "studioId": "d103bb81-45df-402f-86e5-e41d66ed7f8d", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 호스트의 NUMA 토폴로지는 가상 머신 성능을 고려해야 할 구조인가", "kind": "question", "slug": "host-numa-topology", "readiness": "OPEN", "source": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question-oq-12", "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제-24-11" ], "known": "§24.11 은 멀티소켓 또는 NUMA 구조 Host 에서 vCPU 가 실행되는 NUMA node 와 VM memory 가 위치한 node 의 관계가 성능에 영향을 줄 수 있다고 적고, vCPU 가 Node 0 에서 실행되는데 필요한 memory 가 주로 Node 1 에 배치되어 있으면 remote memory access 가 발생할 수 있다는 예를 들었다. 같은 절이 이 문서에서는 문제의 존재와 CPU affinity 와의 관계까지만 기록하고 상세한 memory placement 와 NUMA tuning 은 메모리 가상화 CONCEPT 에서 다룬다고 범위를 그었다. §27 은 이 물음의 종료 기준을 스스로 적었다 — 단일 NUMA node 면 현재 실험에서 우선순위를 낮추고, 다중 NUMA node 면 vCPU/memory placement 를 별도 CASE 후보로 올린다.", "unknown": "이 Host 가 단일 NUMA node 인지 다중 NUMA node 인지, 다중이라면 두 VM 의 vCPU 와 memory 가 어느 node 에 배치되어 있는지.", "next-verification": "Host 의 NUMA topology 를 확인해 node 수를 적는다. 다중으로 나오면 §24.11 이 말한 vCPU 가 실행되는 node 와 VM memory 가 배치된 node 의 관계까지 같이 적는다 (§27 OQ-12). SSOT 는 이 확인에 쓸 명령을 적지 않았으므로 쓰는 명령과 그 출력을 함께 증거로 남긴다.", "decision-criterion": "단일 NUMA node 로 나오면 §27 이 적은 대로 현재 실험에서 우선순위를 낮추고 닫는다. 다중 NUMA node 로 나오면 vCPU/memory placement 를 별도 CASE 후보로 올리고, 이 프로젝트가 메모리 가상화 SSOT 를 가질 때 §24.11 과 함께 그쪽으로 넘긴다.", "relations": [ "concept:kvm-vcpu-to-physical-cpu" ], "publication": "게시됨", "file": "cpu-virtualization/question/question-host-numa-topology.md", "status": "초안", "studioId": "688c6c02-c1bd-4cd2-a615-2396db145386", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "decision": [] } }, "memory-virtualization": { "topic": "memory-virtualization", "title": "메모리 가상화 — VM 에 준 RAM 이 실제로 있는 곳", "readerQuestion": "VM 에 준 RAM 은 실제로 어디에 어떻게 있고, Guest 가 느리거나 죽을 때 그것이 어느 계층의 메모리 문제인지 무엇을 보고 가르는가?", "kinds": { "case": [], "concept": [ { "title": "Guest 메모리 주소가 물리 RAM 에 닿기까지 — GVA · GPA · HPA", "kind": "concept", "slug": "guest-memory-address-translation", "readiness": "READY", "source": [ "final/document.md#29-이-문서에서-먼저-고정할-전체-구조", "final/document.md#30-일반-linux의-virtual-memory부터-시작한다", "final/document.md#31-page와-physical-frame", "final/document.md#32-virtual-address-=-page-+-offset", "final/document.md#33-guest-page-table", "final/document.md#34-mmu-실제-주소-변환을-수행하는-cpu-하드웨어", "final/document.md#35-tlb-주소-변환-결과의-cpu-cache", "final/document.md#36-bare-metal과-vm의-차이", "final/document.md#37-ept-extended-page-tables", "final/document.md#38-왜-ept가-필요한가", "final/document.md#39-shadow-page-table과-ept의-의미", "final/document.md#40-qemu는-guest-ram을-어떻게-준비하는가", "final/document.md#41-kvm_set_user_memory_region", "final/document.md#42-configured-memory와-실제-physical-ram-사용량은-같지-않을-수-있다", "final/document.md#43-guest-page-table-자체도-메모리에-있다", "final/document.md#44-정상-memory-access는-매번-vm-exit하지-않는다", "final/document.md#79-전체-memory-virtualization-실행-경로", "final/document.md#80-전체-memory-virtualization-관리-경로", "final/document.md#82-핵심-claim-registry", "final/document.md#87-최종-기준-그림", "final/document.md#88-결론" ], "basis-version": "x86-64 Intel EPT(second-level address translation) · AMD 는 NPT 계열로 대응 · Linux KVM 의 `KVM_SET_USER_MEMORY_REGION` · QEMU/libvirt · 기본 page 4 KiB. SSOT 가 커널·QEMU·libvirt 버전을 한 번도 적지 않아 특정 버전에 고정하지 않는다 — 여기 적힌 것은 이 문서가 서술한 구성이고, 버전이 바뀌어 서술이 낡았는지는 §83 의 확인을 실제 Host 에서 돌릴 때 드러난다.", "classification": "§29 가 이 부에서 먼저 고정할 구조로 GVA → GPA → HPA 를 놓았고 §87 이 같은 그림을 최종 기준으로 다시 그렸다. 이 경로는 제2부의 다른 다섯 글이 서는 바닥이다 — fault 가 어느 계층에서 났는지도, huge page 가 두 변환 단계 중 어디에 걸리는지도, NUMA 배치가 무엇을 옮기는지도 이 경로를 먼저 그려야 말이 된다. 실행 경로(§79)와 관리 경로(§80)를 갈라 놓는 것도 이 글의 일이다 — QEMU 가 backing 을 마련하고 KVM 이 region 을 등록하지만 매 접근을 처리하는 것은 CPU MMU 라는 것이 §41 과 §44 의 결론이다. 근거는 문서가 서술한 메커니즘이고 이 Host 에서 잰 값은 없다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. 이 글에 대해서는 §83 OQ-2 와 OQ-3 이 재는 것 — VM 의 configured/current memory 와 QEMU process 의 Host resident memory — 이 §42 가 말한 세 값의 차이를 이 Host 에서 확정한다.", "relations": [ "concept:page-fault-layers-in-a-vm", "concept:huge-pages-in-a-vm", "concept:memory-pressure-reclaim-swap-oom", "concept:numa-locality-for-vcpu-and-memory", "question:vm-configured-vs-current-memory", "question:qemu-resident-memory-distribution", "reference:memory-symptom-needs-layer-separation", "concept:kvm-vcpu-to-physical-cpu" ], "ssot-assets": [ "guest-memory-address-translation-path" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-guest-memory-address-translation.md", "status": "초안", "studioId": "2f2ffafc-91ff-4971-a6a8-7c0e7d844ca2", "assets": [ "guest-memory-address-translation-path" ], "assetFiles": [ "guest-memory-address-translation-path" ], "evidenceFiles": [] }, { "title": "VM 에서 page fault 는 세 계층에서 따로 일어난다", "kind": "concept", "slug": "page-fault-layers-in-a-vm", "readiness": "READY", "source": [ "final/document.md#35-tlb-주소-변환-결과의-cpu-cache", "final/document.md#45-guest-page-fault", "final/document.md#46-page-fault의-대표적인-원인", "final/document.md#47-ept-violation", "final/document.md#48-guest-page-fault와-ept-violation-비교", "final/document.md#49-host-page-fault도-별도로-존재한다", "final/document.md#82-핵심-claim-registry", "final/document.md#86-문제를-진단할-때의-분류" ], "basis-version": "x86-64 Intel EPT 기준의 second-stage translation · Linux Guest/Host kernel 의 page fault 처리 · AMD 는 NPT 계열로 대응. SSOT 가 커널 버전을 적지 않아 특정 버전에 고정하지 않는다.", "classification": "§48 의 비교표와 §49 의 세 갈래(Guest Page Fault · Host Page Fault · EPT 관련 사건)는 제2부에서 가장 여러 번 다시 쓰이는 구분이다 — §86 의 진단 분류가 그 위에 서 있고, §83 의 OQ-13 과 OQ-14 가 각각 Guest 쪽과 Host 쪽 fault 를 재라고 말한다. 정상 경로를 그리는 글과 갈라 둔 이유는 물음이 다르기 때문이다 — 그쪽은 정상일 때 무엇이 일어나는가를, 이쪽은 접근이 완료되지 않을 때 어느 계층이 그것을 받는가를 말한다. §35 가 TLB Miss 와 Page Fault 를 먼저 갈라 놓은 것도 여기 들어간다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. Guest 쪽 fault 지표도 Host 쪽 major fault 도 재지 않았다. §46 의 다섯 원인 중 무엇이 이 환경에서 실제로 일어나는지는 OQ-13 이, Host 쪽과 storage latency 의 상관은 OQ-14 가 받는다.", "relations": [ "concept:guest-memory-address-translation", "concept:memory-pressure-reclaim-swap-oom", "question:guest-page-fault-vs-workload", "question:host-major-fault-vs-storage-latency", "reference:memory-symptom-needs-layer-separation" ], "ssot-assets": [ "page-fault-layers-in-a-vm" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-page-fault-layers-in-a-vm.md", "status": "초안", "studioId": "e80853fa-98b8-4cc3-a2df-427c7147794b", "assets": [ "page-fault-layers-in-a-vm" ], "assetFiles": [ "page-fault-layers-in-a-vm" ], "evidenceFiles": [] }, { "title": "Huge Page 를 VM 에서 볼 때 갈라지는 세 자리", "kind": "concept", "slug": "huge-pages-in-a-vm", "readiness": "READY", "source": [ "final/document.md#50-huge-page가-필요한-이유", "final/document.md#51-huge-page와-tlb-coverage", "final/document.md#52-vm에서-huge-page를-볼-때-주의할-점", "final/document.md#53-thp-transparent-huge-pages", "final/document.md#54-thp의-trade-off", "final/document.md#55-hugetlb", "final/document.md#56-thp와-hugetlb-비교", "final/document.md#82-핵심-claim-registry" ], "basis-version": "Linux THP(`/sys/kernel/mm/transparent_hugepage/enabled`) · HugeTLB pool · x86-64 의 4 KiB / 2 MiB / 1 GiB page. §53 이 THP 정책은 kernel·distribution·Host 설정에 따라 다르므로 실제 시스템에서 확인하라고 적었고 SSOT 는 그 버전을 적지 않았다. §51 의 예시 숫자는 특정 CPU 의 실제 TLB 용량이 아니라는 단서가 원문에 붙어 있다.", "classification": "§52 가 세운 세 자리 — Guest page table 단계 · Host backing · EPT 매핑 — 가 이 글이 존재하는 이유다. 「Huge Page 를 쓴다」는 말 하나로는 셋 중 어디를 말하는지 정해지지 않고, 그 구분이 없으면 OQ-4 가 읽은 THP 정책 값도 OQ-5 가 본 backing 설정도 무엇에 대한 값인지 말할 수 없다. THP 와 HugeTLB 의 비교(§56)와 THP 의 감수 비용(§54)도 같은 물음 아래 있어 함께 둔다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. 이 Host 의 THP 정책도 HugePages_Total 도 VM 의 memory backing 설정도 읽지 않았다. §54 가 말한 compaction latency 영향은 측정이 필요하다고 원문이 직접 적었다.", "relations": [ "concept:guest-memory-address-translation", "question:host-thp-policy", "question:vm-ram-backed-by-hugetlb", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-huge-pages-in-a-vm.md", "status": "초안", "studioId": "efce9a6e-5f5d-45ec-86e5-056d8cb1b8d2", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Host 메모리 압박이 Guest 와 스토리지까지 내려가는 경로", "kind": "concept", "slug": "memory-pressure-reclaim-swap-oom", "readiness": "READY", "source": [ "final/document.md#57-memory-overcommit", "final/document.md#58-cpu-overcommit과-memory-overcommit의-차이", "final/document.md#59-host-memory-pressure와-reclaim", "final/document.md#60-host-swap이-vm에-미치는-영향", "final/document.md#61-guest-swap과-host-swap", "final/document.md#62-memory-pressure와-storage-contention의-연결", "final/document.md#71-oom", "final/document.md#72-guest-oom과-host-oom", "final/document.md#81-cpu-network-storage-memory-연결", "final/document.md#82-핵심-claim-registry" ], "basis-version": "Linux memory reclaim(file-backed clean page · anonymous page) · swap · OOM Killer · cgroup memory limit · QEMU 의 Guest RAM backing. SSOT 가 커널 버전도 Host RAM 도 적지 않는다.", "classification": "§58 이 이 부에서 가장 오해되기 쉬운 자리를 앞에 세웠다 — CPU 가 모자라면 scheduler 가 시간을 나누지만 RAM 이 모자라면 「지금 존재해야 하는 page 를 어디에 둘 것인가」가 남는다. 그 답이 reclaim · swap · ballooning · OOM 이고, §60 이 그 결과로 Guest 의 단순한 memory load 가 Host 의 swap-in I/O 대기로 바뀔 수 있다고 적었다. §62 와 §81 은 그 사슬을 storage contention 과 application latency 까지 이었다. OQ-6 · OQ-7 · OQ-14 셋이 이 경로 위에서만 읽힌다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. 이 Host 의 RAM 도 swap 설정도 두 VM 의 configured memory 합도 SSOT 에 없다. 따라서 이 환경이 overcommit 상태인지조차 아직 사실이 아니다 — OQ-2 가 그 값을 받고, 압박이 실제로 Guest latency 를 밀어 올리는지는 OQ-7 이 받는다.", "relations": [ "concept:guest-memory-address-translation", "concept:page-fault-layers-in-a-vm", "concept:virtio-balloon-memory-reclaim", "question:swap-activity-in-guest-and-host", "question:host-memory-pressure-vs-guest-latency", "question:vm-configured-vs-current-memory", "reference:memory-symptom-needs-layer-separation" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-memory-pressure-reclaim-swap-oom.md", "status": "초안", "studioId": "647d6d11-5bb2-4028-a530-b10c8925aa11", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "virtio-balloon 이 Guest 메모리를 회수하고 돌려주는 방식", "kind": "concept", "slug": "virtio-balloon-memory-reclaim", "readiness": "READY", "source": [ "final/document.md#64-ballooning이-필요한-이유", "final/document.md#65-virtio-balloon-구조", "final/document.md#66-balloon-inflate", "final/document.md#67-balloon-page-반환의-의미", "final/document.md#68-balloon-deflate", "final/document.md#69-ballooning을-과도하게-하면-guest가-압박을-받는다", "final/document.md#70-ballooning과-memory-hotplug", "final/document.md#82-핵심-claim-registry" ], "basis-version": "virtio-balloon — Guest kernel 쪽 driver 와 QEMU 쪽 device 가 virtqueue 로 맞물린 구성 · libvirt 의 balloon target 설정. §67 이 Host 쪽 실제 release 동작은 QEMU/KVM 버전과 backing 종류·설정에 따라 달라질 수 있다고 적었고 SSOT 는 그 버전을 적지 않았다. `virtio-mem` 같은 다른 동적 memory 관리 방식이 있다는 사실까지만 §70 에 있다.", "classification": "Host 는 Guest 안에서 어느 memory 가 중요한지 모른다는 것이 §64 의 출발점이고, 그래서 무작정 swap-out 하는 대신 Guest kernel 과 협력해 회수한다는 것이 이 장치의 존재 이유다. Guest 안의 driver 와 QEMU 쪽 device 가 virtqueue 로 맞물린 별도 메커니즘이라 압박 경로 안의 한 절로 넣으면 inflate 와 deflate 의 방향조차 놓을 자리가 없다. OQ-8 과 OQ-9 가 이 글을 필요로 한다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. 이 프로젝트의 VM 에 virtio-balloon 이 붙어 있는지조차 SSOT 에 적혀 있지 않다 — 그것을 OQ-8 이 받고, target 을 바꿨을 때 Guest 가 쓸 수 있는 메모리가 어떻게 따라 움직이는지는 OQ-9 가 받는다. §67 이 남긴 「Host-side release 는 버전과 설정에 따라 다를 수 있다」도 재지 않았다.", "relations": [ "concept:memory-pressure-reclaim-swap-oom", "question:virtio-balloon-configured", "question:balloon-target-vs-guest-available-memory", "reference:memory-symptom-needs-layer-separation" ], "ssot-assets": [ "virtio-balloon-inflate-deflate" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-virtio-balloon-memory-reclaim.md", "status": "초안", "studioId": "ebdf93d7-2dcb-4fc8-91b9-2364ac8196e6", "assets": [ "virtio-balloon-inflate-deflate" ], "assetFiles": [ "virtio-balloon-inflate-deflate" ], "evidenceFiles": [] }, { "title": "NUMA 에서는 vCPU 배치와 메모리 배치를 함께 본다", "kind": "concept", "slug": "numa-locality-for-vcpu-and-memory", "readiness": "READY", "source": [ "final/document.md#73-numa", "final/document.md#74-local-memory와-remote-memory", "final/document.md#75-vcpu와-numa의-연결", "final/document.md#76-vcpu-pinning만으로는-numa-최적화가-끝나지-않는다", "final/document.md#77-guest-numa", "final/document.md#78-numa는-실제-장비-topology부터-확인한다", "final/document.md#81-cpu-network-storage-memory-연결", "final/document.md#82-핵심-claim-registry" ], "basis-version": "multi-socket NUMA x86-64 · Linux `lscpu` 와 `numactl --hardware` · `numastat -p ` · libvirt `virsh vcpupin` 과 `virsh vcpuinfo`. SSOT 가 이 Host 의 NUMA node 수도 커널 버전도 적지 않아 topology 는 측정 전까지 미정이다.", "classification": "CPU 부의 개념이 vCPU 가 QEMU vCPU thread 로 Host scheduler 위에서 돈다는 데까지 갔고, 그 문서의 question:host-numa-topology 가 「상세한 memory placement 와 NUMA tuning 은 메모리 가상화 CONCEPT 에서 다룬다」고 범위를 넘겼다. 넘겨받은 자리가 여기다 — §75 가 thread 가 도는 node 와 backing page 가 있는 node 를 잇고, §76 이 vCPU pinning 만으로는 끝나지 않는다는 결론을 낸다. 주소 변환 개념과 갈라 둔 이유는 이것이 변환 방식이 아니라 배치 문제이고, 재는 명령도 종료 조건도 다르기 때문이다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. SSOT 제2부는 개념 서술이고 §83 이 OQ-1~OQ-14 로 아직 돌리지 않은 확인 목록을 적어 두었다. §88 이 그은 경계대로 이 글은 구조가 어떻게 동작하는지까지만 말하고 이 서버에서 실제로 어떤 값이 나오는지는 사실로 확정하지 않는다. 이 Host 가 단일 node 인지 다중 node 인지가 정해지지 않았고, 그것이 정해지기 전에는 §76 이 말한 어긋남이 이 환경에서 성립하는지조차 알 수 없다. topology 는 CPU 부의 question:host-numa-topology 가 받고, QEMU 메모리가 어느 node 에 있는지는 OQ-11 이, remote access 가 latency 를 바꾸는지는 OQ-12 가 받는다.", "relations": [ "concept:guest-memory-address-translation", "concept:kvm-vcpu-to-physical-cpu", "question:host-numa-topology", "question:qemu-memory-numa-placement", "question:numa-remote-access-vs-workload-latency", "reference:memory-symptom-needs-layer-separation" ], "ssot-assets": [ "numa-vcpu-and-memory-placement" ], "publication": "게시됨", "file": "memory-virtualization/concept/concept-numa-locality-for-vcpu-and-memory.md", "status": "초안", "studioId": "68811272-5352-4409-aa20-7e22e601ede8", "assets": [ "numa-vcpu-and-memory-placement" ], "assetFiles": [ "numa-vcpu-and-memory-placement" ], "evidenceFiles": [] } ], "reference": [ { "title": "메모리 실험 결과에는 Host · VM · Workload 조건을 함께 남긴다", "kind": "reference", "slug": "record-the-conditions-with-every-memory-experiment", "readiness": "READY", "source": [ "final/document.md#85-실험-시-반드시-같이-기록할-것", "final/document.md#84-권장-실험-순서", "final/document.md#83-실제-환경에서-확인할-open-question" ], "classification": "§85 가 실험마다 남길 조건을 Host · VM · Workload 세 묶음으로 못박았다. 이유도 함께 적혀 있다 — 조건을 남기지 않으면 「Memory pressure 에서 느려졌다」는 결과를 다른 환경에 재사용하기 어렵다. 제2부의 열두 Question 전부가 같은 규칙에 걸리므로 각 글에 조건 목록을 되풀이하지 않고 여기 한 편으로 두고 가리킨다. 원 사건의 이름을 지워도 규칙이 남는다는 점에서 Case 요약이 아니다.", "scope": "메모리 관련 측정을 남기는 모든 실험. Host 는 CPU model · core/thread 수 · RAM · NUMA topology · swap 설정 · kernel version · THP policy · physical storage, VM 은 vCPU · configured RAM · current RAM · memory backing 설정 · balloon device · guest swap · guest kernel, Workload 는 application · heap/memory 설정 · request concurrency · DB workload · 측정 시간을 적는다.", "exceptions": "단일 값을 한 번 읽고 끝나는 확인(예: THP 정책 문자열 하나)에는 Workload 묶음이 비어 있어도 된다. 반대로 baseline 과 부하 구간을 비교하는 실험에서는 세 묶음을 두 시점 모두에 남긴다. SSOT 는 이 조건 목록을 이 프로젝트의 실제 장비 값으로 채운 적이 없다 — 목록이 규칙이고 값은 아직 없다.", "relations": [ "concept:guest-memory-address-translation", "concept:huge-pages-in-a-vm", "concept:memory-pressure-reclaim-swap-oom", "reference:memory-symptom-needs-layer-separation", "question:host-memory-pressure-vs-guest-latency", "question:numa-remote-access-vs-workload-latency" ], "publication": "게시됨", "file": "memory-virtualization/reference/reference-record-the-conditions-with-every-memory-experiment.md", "status": "초안", "studioId": "ded41b52-ec08-4231-a54c-86d6c80d38f0", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "메모리 증상 하나로 계층을 단정하지 않는다", "kind": "reference", "slug": "memory-symptom-needs-layer-separation", "readiness": "READY", "source": [ "final/document.md#86-문제를-진단할-때의-분류", "final/document.md#63-swap-used만-보고-장애를-판단하면-안-된다", "final/document.md#78-numa는-실제-장비-topology부터-확인한다", "final/document.md#88-결론", "final/document.md#61-guest-swap과-host-swap", "final/document.md#72-guest-oom과-host-oom" ], "classification": "§86 은 memory latency 나 OOM 을 보고 한 번에 「메모리 부족」이라고 결론내지 말고 Guest Virtual Memory · Virtualization Translation · Host Memory · Dynamic Memory · NUMA 다섯 갈래로 먼저 가르라고 적었다. 같은 규칙이 SSOT 안에서 세 번 더 나온다 — §63 은 Swap Used 값 하나로, §78 은 topology 만 보고, §88 은 Guest 하나의 `free -h` 만 보고 판단하지 말라고 한다. 다섯 갈래는 이 주제의 여섯 개념을 가로지르는 라우팅이라 어느 개념 안에 넣어도 나머지 넷을 가리키지 못한다.", "scope": "메모리 증상(latency 증가 · swap 관측 · OOM · fault 증가)을 원인으로 옮기려는 모든 판독. 가르는 축은 다섯이다 — Guest Virtual Memory(page fault · guest reclaim · guest swap · guest OOM), Virtualization Translation(EPT 관련 사건 · TLB pressure · huge-page/mapping 특성), Host Memory(host reclaim · host swap · host major fault · host OOM), Dynamic Memory(balloon target · guest pressure · hotplug/virtio-mem 여부), NUMA(vCPU placement · memory placement · remote access).", "exceptions": "cgroup memory limit 이 걸린 환경에서는 Host 전체 RAM 이 남아 있어도 그 경계에서 OOM 이 나므로 「Host Memory 갈래가 아니다」로 바로 넘기면 안 된다(§72). 단일 NUMA node Host 에서는 NUMA 갈래의 우선순위를 낮춰도 된다고 §78 이 적었지만, 그것도 topology 를 잰 뒤의 이야기다. 이 규칙은 어느 갈래인지를 좁힐 뿐 원인을 확정하지 않는다 — 확정은 §85 의 조건을 남긴 측정이 한다.", "relations": [ "concept:page-fault-layers-in-a-vm", "concept:memory-pressure-reclaim-swap-oom", "concept:virtio-balloon-memory-reclaim", "concept:numa-locality-for-vcpu-and-memory", "reference:record-the-conditions-with-every-memory-experiment", "question:swap-activity-in-guest-and-host", "question:guest-page-fault-vs-workload" ], "publication": "게시됨", "file": "memory-virtualization/reference/reference-memory-symptom-needs-layer-separation.md", "status": "초안", "studioId": "63fa33e5-9957-4d28-8d3c-c75735a73bd6", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "question": [ { "title": "이 호스트의 가상 머신들은 설정한 메모리와 지금 잡고 있는 메모리가 얼마나 다른가", "kind": "question", "slug": "vm-configured-vs-current-memory", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-2", "final/document.md#42-configured-memory와-실제-physical-ram-사용량은-같지-않을-수-있다", "final/document.md#57-memory-overcommit" ], "known": "§42 는 VM 에 16 GiB 를 설정했다고 해서 시작 순간 Host RAM 16 GiB 가 반드시 즉시 물리적으로 점유되는 것은 아니라고 적고, configured memory · Guest 가 현재 실제 사용하는 memory · Host 에서 현재 resident 한 physical memory 셋이 같지 않을 수 있다고 밝혔다. 그 차이를 만드는 것으로 Host 의 demand paging · backing 종류 · HugeTLB · memory locking · preallocation · overcommit 정책을 들었다. §57 은 configured 총량이 Host physical RAM 을 넘는 구성이 가능한 이유를 configured capacity 와 현재 working set/resident memory 가 같지 않을 수 있다는 데서 찾았다. §83 OQ-2 는 확인 명령으로 Host 쪽 `virsh dominfo ` · `virsh dumpxml ` · `virsh dommemstat ` 와 Guest 쪽 `free -h` · `cat /proc/meminfo` 를 적고 Host 의 QEMU process 상태와 비교하라고 했다. 이 Host 의 physical RAM 도 VM 들의 configured memory 도 SSOT 어디에도 적혀 있지 않다.", "unknown": "이 Host 의 physical RAM 과 각 VM 의 configured memory, 그리고 그 합이 Host RAM 을 넘는지. 넘든 넘지 않든 지금 각 Guest 가 실제로 쓰고 있는 memory 와 Host 에서 그 VM 몫으로 resident 한 memory 가 configured 값과 얼마나 벌어져 있는지.", "next-verification": "각 VM 에 대해 Host 에서 `virsh dominfo ` 로 configured/current memory 를, `virsh dumpxml ` 로 memory backing 설정을, `virsh dommemstat ` 로 balloon 계열 값을 적는다. 같은 시각에 각 Guest 에서 `free -h` 와 `cat /proc/meminfo` 를 찍고 Host 의 `free -h` 도 함께 남긴다 (§83 OQ-2). QEMU process 쪽 RSS 는 question:qemu-resident-memory-distribution 이 받는다. 기록할 조건은 reference:record-the-conditions-with-every-memory-experiment 를 따른다.", "decision-criterion": "세 값(configured · Guest 사용량 · Host resident)을 VM 마다 한 표로 적으면 닫는다 — §42 가 말한 차이가 이 Host 에서 얼마인지가 답이다. configured 합이 Host RAM 을 넘으면 이 환경이 overcommit 상태라는 사실을 확정한 것이 되고, 그 상태에서 무엇이 일어나는지는 question:swap-activity-in-guest-and-host 와 question:host-memory-pressure-vs-guest-latency 가 받는다. 넘지 않으면 §57 의 시나리오는 이 환경에 적용되지 않는다고 적고 닫는다.", "relations": [ "concept:guest-memory-address-translation", "concept:memory-pressure-reclaim-swap-oom", "question:qemu-resident-memory-distribution", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-vm-configured-vs-current-memory.md", "status": "초안", "studioId": "67285d51-7eaf-4540-9577-cfd0b273b40e", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "QEMU 프로세스가 실제로 붙잡고 있는 호스트 메모리는 얼마이고 어떻게 나뉘어 있는가", "kind": "question", "slug": "qemu-resident-memory-distribution", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-3", "final/document.md#40-qemu는-guest-ram을-어떻게-준비하는가", "final/document.md#41-kvm_set_user_memory_region", "final/document.md#42-configured-memory와-실제-physical-ram-사용량은-같지-않을-수-있다" ], "known": "§40 은 QEMU 가 Host userspace process 이고 Guest RAM 도 자신의 Host Virtual Address Space 에 마련한다고 적었다 — RAM 하드웨어에 「물리 주소 X 부터 8 GiB 를 달라」고 요구하는 것이 아니라 QEMU HVA → Host Page Table → HPA 로 관리된다. §41 은 그 영역과 Guest GPA 범위의 대응을 `KVM_SET_USER_MEMORY_REGION` 으로 KVM 에 등록한다고 적었다. §83 OQ-3 은 확인 명령으로 `ps -ef | grep qemu` 와 `ps -o pid,rss,vsz,cmd -p ` 를, 필요하면 `cat /proc//status` 와 `cat /proc//smaps_rollup` 을 적고 configured memory 와 RSS/anonymous/huge-page 상태를 비교하라고 했다.", "unknown": "각 VM 의 QEMU process 가 지금 Host 에서 얼마나 resident 한지(RSS)와 virtual size(VSZ)가 얼마인지, 그 값이 configured memory 와 얼마나 벌어져 있는지, 그리고 그 backing 이 anonymous 인지 huge page 인지.", "next-verification": "실행 중인 VM 마다 `ps -ef | grep qemu` 로 PID 를 찾고 `ps -o pid,rss,vsz,cmd -p ` 를 찍는다. 이어서 `cat /proc//status` 와 `cat /proc//smaps_rollup` 을 남겨 anonymous 와 huge page 항목을 본다 (§83 OQ-3). 같은 실행에서 question:vm-configured-vs-current-memory 가 적은 configured 값을 옆에 놓고 비교한다.", "decision-criterion": "VM 마다 configured · RSS · VSZ 와 anonymous/huge-page 구성이 한 표에 적히면 닫는다. RSS 가 configured 에 크게 못 미치면 §42 가 말한 「configured ≠ resident」를 이 Host 에서 확인한 것이 되어 concept:guest-memory-address-translation 의 확인 사례로 흡수한다. huge page backing 이 보이면 question:vm-ram-backed-by-hugetlb 로 넘긴다.", "relations": [ "concept:guest-memory-address-translation", "question:vm-configured-vs-current-memory", "question:vm-ram-backed-by-hugetlb", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-qemu-resident-memory-distribution.md", "status": "초안", "studioId": "fa5b3782-9fcf-4113-8f51-a55c8023b2db", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 호스트의 THP 정책과 huge page 상태는 무엇인가", "kind": "question", "slug": "host-thp-policy", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-4", "final/document.md#53-thp-transparent-huge-pages", "final/document.md#56-thp와-hugetlb-비교" ], "known": "§53 은 THP 정책을 `cat /sys/kernel/mm/transparent_hugepage/enabled` 로 읽고 출력이 `always [madvise] never` 같은 꼴이라고 적으면서, 현재 정책은 kernel·distribution·Host 설정에 따라 다르므로 실제 시스템에서 확인하라고 했다. §56 은 Host 확인 명령으로 `grep -i huge /proc/meminfo` 와 같은 THP 파일을 들고 `AnonHugePages` 와 `HugePages_Total` 이 같은 의미가 아니라고 적었다. §83 OQ-4 는 확인 항목으로 THP policy · AnonHugePages · HugePages_Total · HugePages_Free · Hugepagesize 다섯을 적었다.", "unknown": "이 Host 의 THP 정책이 always 인지 madvise 인지 never 인지, 그리고 다섯 항목의 실제 값. HugeTLB pool 이 잡혀 있는지(HugePages_Total 이 0 인지)도 아직 모른다.", "next-verification": "Host 에서 `cat /sys/kernel/mm/transparent_hugepage/enabled` 와 `grep -i huge /proc/meminfo` 를 찍어 §83 OQ-4 의 다섯 항목을 그대로 적는다. 같은 명령을 각 Guest 에서도 찍어 Guest 쪽 정책과 구분한다 — §52 가 Guest 단계와 Host backing 을 하나의 설정으로 취급하지 말라고 적었다.", "decision-criterion": "다섯 항목의 값이 Host 와 Guest 각각에 대해 적히면 닫는다. HugePages_Total 이 0 이 아니면 그 pool 을 VM 이 쓰고 있는지를 question:vm-ram-backed-by-hugetlb 로 넘긴다. THP 가 always 인데 latency-sensitive workload 를 돌리고 있으면 §54 가 말한 compaction 영향을 측정할지 여부를 Decision 으로 넘긴다 — 이 질문 자체는 정책 값을 확정하는 데서 끝난다.", "relations": [ "concept:huge-pages-in-a-vm", "question:vm-ram-backed-by-hugetlb", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-host-thp-policy.md", "status": "초안", "studioId": "50730203-df5f-4604-8535-7e93ab6fb724", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "가상 머신 RAM 이 HugeTLB 로 명시적으로 backing 되어 있는가", "kind": "question", "slug": "vm-ram-backed-by-hugetlb", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-5", "final/document.md#55-hugetlb", "final/document.md#52-vm에서-huge-page를-볼-때-주의할-점" ], "known": "§55 는 HugeTLB 를 관리자가 미리 준비한 명시적 Huge Page pool 을 VM 이나 application 이 명시적으로 쓰는 방식으로 적고, 사전 확보로 예측 가능성을 높이는 대신 일반 memory allocation 의 유연성이 줄어드는 trade-off 가 있다고 밝혔다. §52 는 VM 에 변환 단계가 둘이라 Guest page-table 단계 · Host backing · EPT 매핑을 구분해야 하고 Guest 와 Host 의 page-size 선택을 하나의 설정으로 취급하면 안 된다고 적었다. §83 OQ-5 는 `virsh dumpxml ` 로 libvirt memory backing 설정을 확인하고 Host `/proc/meminfo` 및 QEMU `smaps` 계열과 교차 검증하라고 했다.", "unknown": "각 VM 의 libvirt 설정에 memory backing 항목이 있는지, 있다면 HugeTLB 를 가리키는지. 그리고 그것이 Host `/proc/meminfo` 의 HugePages 사용량 및 QEMU smaps 의 huge-page 항목과 맞는지.", "next-verification": "VM 마다 `virsh dumpxml ` 를 남기고 memory backing 관련 요소를 그대로 인용한다. 같은 시각에 Host `grep -i huge /proc/meminfo` 와 `cat /proc//smaps_rollup` 을 찍어 세 자료를 나란히 놓는다 (§83 OQ-5).", "decision-criterion": "세 자료가 서로 맞으면 이 환경의 backing 종류를 확정하고 닫는다. 설정에 backing 이 없고 HugePages_Total 도 0 이면 이 VM 들은 명시적 HugeTLB backing 을 쓰지 않는다고 적고 닫는다 — 그 경우 §54 의 THP 쪽 특성만 남는다. 설정과 Host 값이 어긋나면 그 어긋남이 Case 가 된다.", "relations": [ "concept:huge-pages-in-a-vm", "question:host-thp-policy", "question:qemu-resident-memory-distribution", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-vm-ram-backed-by-hugetlb.md", "status": "초안", "studioId": "f460e9a2-35ef-46ff-81cf-b36627a1b231", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "지금 게스트와 호스트에서 swap 이 실제로 오가고 있는가", "kind": "question", "slug": "swap-activity-in-guest-and-host", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-6", "final/document.md#63-swap-used만-보고-장애를-판단하면-안-된다", "final/document.md#61-guest-swap과-host-swap" ], "known": "§63 은 Swap Used 값 하나로 memory pressure 가 심하다고 단정할 수 없고 과거에 swap-out 된 cold page 가 남아 있을 수도 있다고 적으면서, 더 중요한 물음으로 지금 swap-in/out 이 지속되는가 · reclaim pressure 가 증가하는가 · major fault 가 증가하는가 · storage latency 가 같이 증가하는가 넷을 들고 Guest 와 Host 를 동시에 확인하라고 했다. 확인 명령은 `free -h` 와 `vmstat 1` 이다. §61 은 Guest Swap 이 Guest kernel 에서 `/dev/vda` 로 내려가는 경로이고 Host Swap 은 QEMU memory backing 이 Host kernel 에 눌리는 경로라 둘이 다르며, Guest 가 여유 있어 보이는데 Host 에서 swap/reclaim 이 심할 수도 있다고 적었다. §83 OQ-6 도 같은 두 명령을 Guest 와 Host 양쪽에 적었다.", "unknown": "지금 이 환경에서 swap-in/out 이 실제로 오가고 있는지, 오간다면 Guest 쪽인지 Host 쪽인지 둘 다인지. Swap Used 가 0 이 아니더라도 그것이 남아 있는 cold page 인지 진행 중인 활동인지.", "next-verification": "Guest 와 Host 양쪽에서 같은 시각에 `free -h` 를 한 번 찍고 `vmstat 1` 을 일정 시간 돌려 `si`/`so` 열이 계속 0 인지 본다 (§83 OQ-6 · §63). Guest 는 VM 마다 따로 찍는다. 같은 창에서 §63 이 든 나머지 셋 — reclaim pressure · major fault · storage latency — 도 함께 남긴다.", "decision-criterion": "관측 구간 내내 Guest 와 Host 모두 `si`/`so` 가 0 이면 지금은 swap 이 오가지 않는다고 적고 닫는다 — Swap Used 값이 0 이 아니어도 그렇게 적는다. 한쪽에서 swap 이 오가면 그 방향(§61 의 두 경로 중 어느 쪽인지)을 적고 그 구간의 storage latency 및 Guest latency 와 함께 놓아 question:host-memory-pressure-vs-guest-latency 로 넘긴다.", "relations": [ "concept:memory-pressure-reclaim-swap-oom", "concept:page-fault-layers-in-a-vm", "question:host-memory-pressure-vs-guest-latency", "question:host-major-fault-vs-storage-latency", "reference:memory-symptom-needs-layer-separation" ], "publication": "게시됨", "file": "memory-virtualization/question/question-swap-activity-in-guest-and-host.md", "status": "초안", "studioId": "d3e8501f-e1b5-4f8f-aa9a-89f9c89a308e", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "호스트 메모리 압박이 게스트 애플리케이션 지연을 실제로 밀어 올리는가", "kind": "question", "slug": "host-memory-pressure-vs-guest-latency", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-7", "final/document.md#59-host-memory-pressure와-reclaim", "final/document.md#60-host-swap이-vm에-미치는-영향", "final/document.md#62-memory-pressure와-storage-contention의-연결" ], "known": "§59 는 Host RAM 수요가 available physical memory 에 가까워지면 reclaim 이 돌고, file-backed clean page 는 버렸다 다시 읽으면 되지만 anonymous page 는 swap 같은 backing 이 필요하다고 적었다. §60 은 Guest 가 단순히 RAM 에 접근한다고 생각하는 사이에 Host 쪽에서는 backing page 가 RAM 에 없어 Host Page Fault → swap-in I/O → RAM 복원 → Guest 실행 계속으로 바뀔 수 있다고 적었다. §62 는 그 결과 Guest swap I/O · Host swap I/O · DB I/O · filesystem writeback 이 한 물리 장치로 몰려 storage contention 과 application latency 로 이어질 수 있고, CPU 사용률이 낮다고 memory/storage 문제가 없는 것은 아니라고 밝혔다. §83 OQ-7 은 실험 개념을 baseline → Guest latency 측정 → Host memory pressure 유도 → Host reclaim/swap 관측 → Guest latency 재측정으로 적고 CPU 와 storage 도 동시에 관측하라고 했다.", "unknown": "이 Host 에서 memory pressure 를 유도했을 때 reclaim 과 swap 이 실제로 도는지, 돈다면 같은 구간의 Guest application latency 가 baseline 대비 얼마나 달라지는지, 그리고 그 변화가 CPU 쪽이 아니라 memory/storage 쪽 지표와 같은 방향으로 움직이는지.", "next-verification": "baseline 구간에서 Guest application latency 와 Host `vmstat 1` · storage latency · CPU 를 같은 시각에 기록한다. 그 다음 Host 에 memory pressure 를 유도하고 같은 네 가지를 다시 기록한 뒤, pressure 를 걷고 세 번째 구간을 찍는다 (§83 OQ-7). 세 구간 모두에 reference:record-the-conditions-with-every-memory-experiment 의 Host · VM · Workload 조건을 남긴다. Guest 쪽 swap 은 question:swap-activity-in-guest-and-host 와 같은 방법으로 함께 찍는다.", "decision-criterion": "pressure 구간에서 Host reclaim/swap 이 돌았는데도 Guest latency 가 baseline 과 다르지 않으면, 이 구성에서는 그 정도의 압박이 Guest 까지 오지 않는다고 적고 닫는다. latency 가 오르면 그 세 구간 표가 Case 가 되고 이 질문은 그 Case 가 닫는다. 압박을 어디까지 허용할지 — swappiness 를 바꿀지, VM 배치를 바꿀지, balloon 을 쓸지 — 는 그 Case 가 나온 뒤 Decision 으로 넘긴다.", "relations": [ "concept:memory-pressure-reclaim-swap-oom", "concept:page-fault-layers-in-a-vm", "question:swap-activity-in-guest-and-host", "question:host-major-fault-vs-storage-latency", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-host-memory-pressure-vs-guest-latency.md", "status": "초안", "studioId": "a05fe2a6-eb7c-4bcc-a7da-58e729436468", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 가상 머신들에 virtio-balloon 이 붙어 있는가", "kind": "question", "slug": "virtio-balloon-configured", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-8", "final/document.md#65-virtio-balloon-구조", "final/document.md#64-ballooning이-필요한-이유" ], "known": "§65 는 virtio-balloon 을 Guest kernel 쪽 driver 와 QEMU 쪽 device 가 virtqueue 로 맞물린 구성으로 그리고, Guest RAM 자체를 제공하는 장치가 아니라 이미 있는 backing 을 Host 와 Guest 가 협력해 회수·반환하는 데 쓰는 가상 장치라고 적었다. §64 는 Host 가 Guest 안에서 어느 memory 가 중요한지 완전히 알지 못하므로 무작정 swap-out 하기보다 Guest kernel 과 협력하는 편이 유리할 수 있다는 것을 이 장치의 존재 이유로 들었다. §83 OQ-8 은 `virsh dumpxml ` 로 확인하고 Guest 에서도 관련 driver/device 상태를 확인하라고 하면서, 환경에 따라 driver 이름과 표시 방식이 달라질 수 있으니 실제 장비에서 검증하라는 단서를 달았다.", "unknown": "각 VM 의 libvirt 설정에 balloon device 가 있는지, 있다면 Guest 안에서 해당 driver 가 실제로 올라와 있는지. 이 환경에서 그 driver 가 어떤 이름으로 보이는지도 SSOT 에 없다.", "next-verification": "VM 마다 `virsh dumpxml ` 를 남기고 balloon 관련 요소를 그대로 인용한다. 각 Guest 에서 balloon 관련 driver/device 상태를 확인해 실제로 보이는 이름과 함께 적는다 (§83 OQ-8). `virsh dommemstat ` 출력도 같이 남긴다 — question:vm-configured-vs-current-memory 가 같은 명령을 찍으므로 한 번에 받는다.", "decision-criterion": "설정과 Guest 쪽 상태가 둘 다 적히면 닫는다. 붙어 있지 않으면 이 환경에서는 ballooning 이 동작하지 않는다고 적고 question:balloon-target-vs-guest-available-memory 는 열지 않은 채로 둔다 — 장치가 없으면 그 실험이 성립하지 않는다. 붙어 있으면 그 질문으로 넘긴다.", "relations": [ "concept:virtio-balloon-memory-reclaim", "question:balloon-target-vs-guest-available-memory", "question:vm-configured-vs-current-memory" ], "publication": "게시됨", "file": "memory-virtualization/question/question-virtio-balloon-configured.md", "status": "초안", "studioId": "63aef96b-03ef-4dbd-9ba6-9e61c6e695e1", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "balloon target 을 바꾸면 게스트가 쓸 수 있는 메모리는 어떻게 따라 움직이는가", "kind": "question", "slug": "balloon-target-vs-guest-available-memory", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-9", "final/document.md#66-balloon-inflate", "final/document.md#68-balloon-deflate", "final/document.md#69-ballooning을-과도하게-하면-guest가-압박을-받는다" ], "known": "§66 은 inflate 하면 Guest 안의 balloon 이 커져 Guest usable memory 가 줄고 Host 가 회수할 수 있는 backing 이 는다고 적었고, §68 은 target 을 줄이면 balloon page 가 반환되어 Guest usable memory 가 는다고 적었다. §69 는 working set 이 큰데 과도하게 inflate 하면 Guest available memory 감소 → Guest memory pressure → reclaim → page cache 회수 → Guest swap → 심하면 Guest OOM 으로 이어질 수 있고, Host RAM 을 확보하려는 조치가 Guest storage I/O 와 application latency 를 올릴 수 있다고 밝혔다. §83 OQ-9 는 Host/libvirt memory setting → Guest `free -h` / `/proc/meminfo` → Guest reclaim/swap 변화 순으로 관측하고 과도한 ballooning 시의 latency/swap/OOM 가능성은 별도 실험으로 보라고 했다.", "unknown": "이 환경에서 balloon target 을 바꿨을 때 Guest 의 available memory 가 얼마나 따라 움직이는지, 그 반영이 즉시인지 지연이 있는지, 그리고 어느 지점부터 Guest reclaim/swap 이 시작되는지.", "next-verification": "question:virtio-balloon-configured 가 balloon 이 붙어 있다고 확정한 뒤에 연다. baseline 에서 Guest `free -h` 와 `/proc/meminfo` 와 `vmstat 1` 을 찍고, Host 에서 balloon target 을 한 단계 낮춘 뒤 같은 셋을 다시 찍는다. 단계를 몇 번 반복해 target 과 Guest available memory 의 대응을 표로 만든다 (§83 OQ-9). 과도 inflate 구간은 §69 가 경고한 대로 별도 실험으로 분리하고 Guest application latency 를 같이 잰다.", "decision-criterion": "target 값과 Guest available memory 가 표로 대응되고 reclaim/swap 이 시작되는 지점이 적히면 닫는다. Guest swap 이나 OOM 까지 갔으면 그 구간이 Case 가 되고, 운영에서 balloon 을 쓸지와 target 하한을 얼마로 둘지는 그 Case 가 나온 뒤 Decision 으로 넘긴다.", "relations": [ "concept:virtio-balloon-memory-reclaim", "concept:memory-pressure-reclaim-swap-oom", "question:virtio-balloon-configured", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-balloon-target-vs-guest-available-memory.md", "status": "초안", "studioId": "6a60abe7-ea2c-46c2-bb9f-8281bfbe9644", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "QEMU 메모리는 vCPU 가 도는 NUMA node 와 같은 node 에 있는가", "kind": "question", "slug": "qemu-memory-numa-placement", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-11", "final/document.md#75-vcpu와-numa의-연결", "final/document.md#76-vcpu-pinning만으로는-numa-최적화가-끝나지-않는다", "final/document.md#78-numa는-실제-장비-topology부터-확인한다" ], "known": "§75 는 Guest vCPU 가 Host 에서 QEMU vCPU thread 이고, VM 의 vCPU thread 가 Node 0 CPU 에서 실행되는데 그 VM 의 Host physical backing page 가 Node 1 에 있으면 Guest 에서는 단순한 memory load 인 것이 실제 하드웨어에서는 NUMA interconnect 를 건널 수 있다고 적었다. §76 은 vCPU 를 pinning 해도 memory 가 다른 node 에 배치되어 있으면 remote access 가 많아질 수 있으므로 vCPU placement 와 memory placement/binding 을 함께 봐야 한다고 밝혔다. §78 은 `numastat -p ` 로 QEMU process 별 memory distribution 을, `virsh vcpupin` 과 `virsh vcpuinfo` 로 vCPU placement 를 본다고 적었다. §83 OQ-11 은 `numastat -p ` 결과를 vCPU placement 와 비교해 vCPU → Node 0 / Memory → Node 0 인지 vCPU → Node 0 / Memory → Node 1 인지 확인하라고 했다.", "unknown": "이 Host 에서 각 VM 의 QEMU memory 가 어느 NUMA node 에 얼마나 나뉘어 있는지, 그리고 그 분포가 그 VM 의 vCPU thread 가 도는 node 와 맞는지 어긋나는지. Host 가 다중 NUMA node 인지 자체가 아직 확정되지 않았고 그것은 CPU 부의 question:host-numa-topology 가 받는다.", "next-verification": "question:host-numa-topology 가 이 Host 를 다중 NUMA node 로 확정한 뒤에 연다. VM 마다 `numastat -p ` 로 node 별 memory 분포를 찍고, 같은 시각에 `virsh vcpuinfo ` 와 `virsh vcpupin ` 로 vCPU 배치를 적어 나란히 놓는다 (§78 · §83 OQ-11).", "decision-criterion": "node 별 memory 분포와 vCPU 배치가 VM 마다 한 표로 적히면 닫는다. 둘이 같은 node 로 모여 있으면 §76 이 말한 어긋남이 이 환경에 없다고 적고 닫는다. 어긋나 있으면 그 표가 Case 가 되고, 그 어긋남이 실제 latency 를 바꾸는지는 question:numa-remote-access-vs-workload-latency 가 받는다. memory binding 을 걸지 여부는 그 뒤 Decision 으로 넘긴다. 단일 NUMA node 로 나오면 이 질문은 이 환경에 적용되지 않는다고 적고 닫는다.", "relations": [ "concept:numa-locality-for-vcpu-and-memory", "question:host-numa-topology", "question:numa-remote-access-vs-workload-latency", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-qemu-memory-numa-placement.md", "status": "초안", "studioId": "1b59e6de-16f1-42b2-81bb-01d6198e34bf", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "NUMA remote access 가 이 작업의 지연을 실제로 바꾸는가", "kind": "question", "slug": "numa-remote-access-vs-workload-latency", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-12", "final/document.md#74-local-memory와-remote-memory", "final/document.md#77-guest-numa" ], "known": "§74 는 remote access 가 local access 와 동일한 비용이라고 가정할 수 없으며 추가 latency/bandwidth 비용이 있을 수 있다고 적었다. §77 은 큰 VM 에서는 Guest 에게 NUMA topology 를 노출하고 가능하면 Guest 가 인식하는 topology 와 실제 Host placement 가 합리적으로 대응되도록 구성할 수 있다고 적었다. §83 OQ-12 는 NUMA node 가 2개 이상인 경우에만 우선순위를 높이라고 하면서 실험을 local placement baseline → latency/throughput/memory metrics → remote-heavy placement → 동일 workload 비교로 적고, 단순 topology 만 보고 성능 문제라고 단정하지 말라는 단서를 달았다.", "unknown": "이 Host 에서 local placement 와 remote-heavy placement 를 각각 구성했을 때 같은 workload 의 latency 와 throughput 이 실제로 다른지, 다르다면 얼마나 다른지. Guest NUMA 를 노출한 구성인지도 SSOT 에 적혀 있지 않다.", "next-verification": "question:host-numa-topology 가 다중 node 로 확정하고 question:qemu-memory-numa-placement 가 현재 배치를 적은 뒤에 연다. local placement 로 맞춘 구성에서 같은 workload 를 돌려 latency · throughput · memory 지표를 기록하고, remote-heavy placement 로 바꿔 같은 workload 를 같은 조건으로 다시 돌린다 (§83 OQ-12). 두 구간 모두에 reference:record-the-conditions-with-every-memory-experiment 의 세 묶음을 남긴다.", "decision-criterion": "두 배치의 latency/throughput 이 측정 오차 안에서 다르지 않으면 이 workload 에서는 NUMA locality 가 우선순위가 아니라고 적고 닫는다. 차이가 나면 그 비교표가 Case 가 되고, vCPU pinning 과 memory binding 을 운영 구성으로 채택할지는 그 Case 가 나온 뒤 Decision 으로 넘긴다. 단일 NUMA node 로 나오면 §83 이 적은 대로 우선순위를 낮추고 닫는다.", "relations": [ "concept:numa-locality-for-vcpu-and-memory", "question:qemu-memory-numa-placement", "question:host-numa-topology", "reference:record-the-conditions-with-every-memory-experiment" ], "publication": "게시됨", "file": "memory-virtualization/question/question-numa-remote-access-vs-workload-latency.md", "status": "초안", "studioId": "380d4975-3be5-451d-aede-2e24c5a2a09e", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "게스트 page fault 증가는 workload 변화를 따라가는가", "kind": "question", "slug": "guest-page-fault-vs-workload", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-13", "final/document.md#45-guest-page-fault", "final/document.md#46-page-fault의-대표적인-원인" ], "known": "§45 는 Guest Page Fault 가 GVA → GPA 단계에서 접근을 완료할 수 없을 때 나고 Guest Kernel 이 page 를 확보해 매핑을 갱신한 뒤 instruction 을 재시도한다고 적으면서, Page Fault 자체가 프로그램 오류를 뜻하지 않는다고 밝혔다. §46 은 대표 원인으로 demand paging · swap-in · permission fault · copy-on-write · invalid access 다섯을 들고 Page Fault 와 Segmentation Fault 가 다르다고 적었다. §83 OQ-13 은 Guest 에서 page-fault 관련 지표를 관측하되 정상 demand paging 인지 · COW 인지 · Guest swap-in 인지 · application working-set 증가인지를 분리하고, Page Fault 증가만으로 오류라고 판단하지 말라고 했다.", "unknown": "이 환경의 Guest 에서 workload 가 늘 때 page fault 지표가 실제로 함께 오르는지, 오른다면 minor 인지 major 인지, 그리고 §46 의 다섯 원인 중 어느 쪽으로 설명되는지.", "next-verification": "Guest 에서 idle 구간과 workload 구간을 나눠 page-fault 관련 지표를 같은 방법으로 기록한다 — `vmstat 1` 로 시간에 따른 변화를 보고 프로세스 수준은 `/proc//stat` 계열로 minor/major 를 가른다. 같은 구간에 Guest 의 swap 활동(question:swap-activity-in-guest-and-host 와 같은 방법)과 application 의 working set 을 함께 남겨 §83 OQ-13 이 든 네 갈래를 분리한다.", "decision-criterion": "workload 구간의 fault 증가가 minor 위주이고 swap-in 이 없으면 정상 demand paging 으로 설명된다고 적고 닫는다 — §45 가 말한 대로 그것은 오류가 아니다. major fault 가 함께 오르면 Guest swap-in 을 의심하고 그 구간을 question:swap-activity-in-guest-and-host 로 넘긴다. 어느 쪽으로도 설명되지 않으면 그 관측이 Case 가 된다.", "relations": [ "concept:page-fault-layers-in-a-vm", "question:swap-activity-in-guest-and-host", "question:host-major-fault-vs-storage-latency", "reference:memory-symptom-needs-layer-separation" ], "publication": "게시됨", "file": "memory-virtualization/question/question-guest-page-fault-vs-workload.md", "status": "초안", "studioId": "074a1cb4-cea8-4dad-bc4c-899692ff9aa9", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "호스트 major fault 와 스토리지 지연은 같은 시간축에서 함께 움직이는가", "kind": "question", "slug": "host-major-fault-vs-storage-latency", "readiness": "OPEN", "source": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-14", "final/document.md#49-host-page-fault도-별도로-존재한다", "final/document.md#62-memory-pressure와-storage-contention의-연결" ], "known": "§49 는 QEMU 도 Host 의 일반 userspace process 이므로 QEMU memory backing 에 Host virtual-memory 관리가 적용되고 demand allocation·reclaim/swap 때문에 Host 쪽에서도 page fault 가 날 수 있다고 적으면서, VM 메모리 분석에서는 Guest Page Fault · Host Page Fault · EPT 관련 사건을 적어도 셋으로 구분해야 한다고 밝혔다. §62 는 Guest swap I/O · Host swap I/O · DB I/O · filesystem writeback 이 한 물리 장치로 몰릴 수 있고 Host memory pressure → reclaim/swap → storage I/O 증가 → storage contention → DB latency → application latency 로 이어질 수 있다고 적었다. §83 OQ-14 는 Host memory pressure 실험 시 Host fault · swap activity · storage latency · Guest application latency 를 같은 시간축으로 비교하라고 했다.", "unknown": "Host 에 memory pressure 가 걸린 구간에서 Host major fault 와 swap activity 와 storage latency 가 실제로 같은 방향으로 움직이는지, 그리고 그 움직임이 Guest application latency 와 시간적으로 겹치는지.", "next-verification": "question:host-memory-pressure-vs-guest-latency 의 실험과 같은 실행에서 받는다 — baseline · pressure · 회복 세 구간 각각에 Host 의 major fault 와 swap 활동(`vmstat 1`), storage latency, Guest application latency 를 같은 타임스탬프로 남긴다 (§83 OQ-14). 네 계열을 한 시간축에 놓고 본다.", "decision-criterion": "네 계열이 같은 구간에서 함께 오르면 §62 가 그린 사슬이 이 환경에서 이어진다는 것을 확인한 것이 되고 그 시계열이 Case 가 된다. major fault 는 오르는데 storage latency 가 따라 오르지 않으면 이 장치 구성에서는 그 사슬이 여기서 끊긴다고 적고 닫는다. 어느 쪽이든 storage 쪽 대응 — 장치 분리나 swap 위치 변경 — 은 그 뒤 Decision 으로 넘긴다.", "relations": [ "concept:page-fault-layers-in-a-vm", "concept:memory-pressure-reclaim-swap-oom", "question:host-memory-pressure-vs-guest-latency", "question:swap-activity-in-guest-and-host", "reference:memory-symptom-needs-layer-separation" ], "publication": "게시됨", "file": "memory-virtualization/question/question-host-major-fault-vs-storage-latency.md", "status": "초안", "studioId": "a2cbc828-59ab-4e70-916a-d053e71960ae", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "decision": [] } }, "network-virtualization": { "topic": "network-virtualization", "title": "네트워크 가상화 — Guest 의 packet 이 Host Physical NIC 까지 가는 길", "readerQuestion": "Guest 애플리케이션이 보낸 packet 은 어느 계층을 거쳐 Host Physical NIC 까지 가고, 요청이 느리거나 닿지 않을 때 그것이 network 가상화의 어느 자리 문제인지 무엇을 보고 가르는가?", "kinds": { "case": [], "concept": [ { "title": "Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge", "kind": "concept", "slug": "guest-packet-path-to-physical-nic", "readiness": "READY", "source": [ "final/document.md#94-전체-네트워크-계층", "final/document.md#121-이-ssot에서-파생될-concept", "final/document.md#125-최종-기준-구조", "final/document.md#89-문서-목적", "final/document.md#90-virsh-libvirt-virtio-구분", "final/document.md#91-virtio-net은-정확히-어디에-있는가", "final/document.md#92-frontend와-backend", "final/document.md#93-guest-os는-왜-qemu가-아니라-virtio-net을-사용하는가", "final/document.md#95-physical-nic의-역할", "final/document.md#96-linux-bridge의-역할", "final/document.md#97-routing의-역할", "final/document.md#98-nat의-역할", "final/document.md#99-tap의-역할", "final/document.md#100-virtqueue의-역할", "final/document.md#101-guest-tcp-ip-stack의-역할", "final/document.md#102-packet이-keycloak까지-올라오는-과정", "final/document.md#103-qemu-virtio-device-model의-역할", "final/document.md#104-왜-tap-→-vhost-net-→-qemu-→-virtqueue-라고-일반화하면-안-되는가", "final/document.md#105-control-path와-data-path", "final/document.md#106-qemu가-userspace인데-packet이-qemu를-안-거칠-수-있는-이유", "final/document.md#107-vhost-net-최적화", "final/document.md#108-vhost-net은-qemu를-제거하지-않는다", "final/document.md#109-fast-path와-slow-control-path", "final/document.md#110-data-copy-최적화", "final/document.md#111-interrupt-notification-최적화", "final/document.md#112-multi-queue-최적화", "final/document.md#113-offload-최적화", "final/document.md#114-linux-bridge가-항상-host-tcp-ip-stack을-거치는-것은-아니다", "final/document.md#115-host-physical-nic로-나갈-때-virtio를-다시-거치지-않는다", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-4", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-5", "final/document.md#124-핵심-claim" ], "basis-version": "Linux KVM/QEMU/libvirt 의 virtio-net frontend + vhost-net kernel backend + TAP + Linux Bridge 구성. §94 가 「가장 기본적인 구조」로 잡은 것이 이 조합이고, 같은 절이 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 적었으므로 이 글은 그 조합 안에서만 유효하다. SSOT 가 커널·QEMU·libvirt 버전을 한 번도 적지 않아 특정 버전에 고정하지 않는다 — 여기 적힌 것은 이 문서가 서술한 구성이고, 버전이 바뀌어 서술이 낡았는지는 §122 의 확인을 실제 Host 에서 돌릴 때 드러난다. §110 이 copy 동작을 kernel version · QEMU version · vhost configuration · offload · NIC capability 에 따라 달라진다고 못박은 것이 그 경계다.", "classification": "§121 이 virsh · libvirt · QEMU · virtio · virtio-net · Frontend/Backend · virtqueue · QEMU virtio Device Model · vhost-net · TAP · Linux Bridge · Routing · NAT · Physical NIC · Guest TCP/IP Stack · Socket · Data Path/Control Path · Fast Path · Multi-Queue · Offload · Packet tracing 을 한 목록으로 묶고 「이 요소들이 하나의 packet 실행 경로를 설명하므로 하나의 CONCEPT 로 관리한다」고 적었다. 제1부의 §19 가 CPU 실행 경로에 대해 같은 지시를 했고 그 부도 개념 하나로 내려앉았다. 경로 중간을 잘라 내면 인과가 끊긴다 — virtqueue 만 떼면 무엇과 무엇 사이의 queue 인지 말할 수 없고, vhost-net 만 떼면 무엇을 우회하는지 말할 수 없다. 이 글이 확정하는 것은 구조가 어떻게 동작하는가와 그 구조에서 어긋날 수 있는 자리(§117.4·§117.5)까지다. §103 이 나눈 두 역할(장치 관리 · packet 처리)이 이 글의 척추이고, §104 · §108 · §114 · §115 는 그 척추를 잘못 일반화한 그림 넷을 차례로 지운다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. 제3부는 개념 서술이고 §122 가 OQ-1~OQ-7 로 아직 돌리지 않은 확인 목록을 적어 두었다. 이 Host 의 network 가 Bridge 인지 NAT 인지(OQ-1), TAP 이 무엇인지(OQ-2), vhost-net 을 실제로 쓰는지(OQ-3), multi-queue 가 켜져 있는지(OQ-5)를 확인하기 전까지 이 글은 「이 구조에서는 이렇게 동작한다」까지만 말하고 「이 서버가 그 구조다」라고는 말하지 않는다. §116 이 이 테스트 환경에 얹어 그린 펼친 경로도 같은 이유로 확인 대상이며, 후보 대장에 SSOT-116-test-environment-packet-path 로 NEEDS_EVIDENCE 를 적어 두었다.", "relations": [ "reference:bisect-the-packet-path-with-capture-points", "reference:verify-the-network-path-before-blaming-the-application", "question:vm-network-mode-bridge-nat-or-routed", "question:tap-interface-to-vm-mapping", "question:is-vhost-net-actually-in-use", "question:qemu-backend-vs-vhost-net-on-this-host", "question:virtio-net-multi-queue-enabled", "question:actual-packet-path-nginx-to-keycloak", "question:network-virtualization-cpu-cost-under-load", "concept:kvm-vcpu-to-physical-cpu" ], "ssot-assets": [ "packet-control-and-data-paths" ], "publication": "게시됨", "file": "network-virtualization/concept/concept-guest-packet-path-to-physical-nic.md", "status": "초안", "studioId": "5b1de31c-0495-4226-8607-73ed7284b314", "assets": [ "packet-control-and-data-paths" ], "assetFiles": [ "packet-control-and-data-paths" ], "evidenceFiles": [] } ], "reference": [ { "title": "packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다", "kind": "reference", "slug": "bisect-the-packet-path-with-capture-points", "readiness": "READY", "source": [ "final/document.md#119-실제-packet-path-추적", "final/document.md#118-실제-linux에서-확인할-명령어", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-1", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-2", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-3", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-6", "final/document.md#113-offload-최적화", "final/document.md#114-linux-bridge가-항상-host-tcp-ip-stack을-거치는-것은-아니다", "final/document.md#99-tap의-역할" ], "classification": "§119 가 Host 의 physical NIC · bridge · tap/vnet 과 Guest 의 interface 에 각각 `tcpdump -ni` 를 걸고 어디까지 보이는지로 의심 구간을 좁히는 절차를 적었다. 세 가지 판독을 예로 들었다 — Physical NIC O · Bridge O · TAP X 이면 Host Bridge/TAP mapping 을, TAP O · Guest NIC X 이면 virtio/vhost/Guest NIC 계층을, Guest NIC O · Socket X 이면 Guest routing/firewall/listen 상태를 의심한다. §117.1~.3 이 그 절차가 다루는 증상(연결 오류 · routing 오류 · NAT/firewall 오류)을 대고 §118 이 각 지점에서 무엇을 실행할지를 댄다. 원 프로젝트의 이름을 지워도 규칙이 남는다는 점에서 Case 요약이 아니고, OQ-1 · OQ-2 · OQ-6 셋이 모두 이 규칙 위에서 돌아가므로 세 글에 되풀이하지 않고 한 편으로 두고 가리킨다.", "scope": "KVM/QEMU/libvirt 로 만든 VM 이 밖과 통신하지 못하거나 특정 구간에서만 실패할 때, 그리고 실제 packet 경로를 처음 확인할 때. capture 지점은 Host 쪽 physical NIC · bridge · tap/vnet 과 Guest 쪽 interface 넷이고, 그 이름은 `ip link` · `bridge link` · `ip tuntap show` · `virsh domiflist ` · `virsh net-list --all` · `virsh net-dumpxml ` · `ip route` · `ip rule` 로 먼저 확정한다(§118). 판독은 어느 지점까지 보였는가로만 하고, 보이지 않은 첫 지점의 앞 구간을 의심 구간으로 삼는다.", "exceptions": "offload(GSO · GRO · TSO · Checksum offload)가 켜져 있으면 tcpdump 에 보이는 packet size 와 checksum 이 실제 wire 와 다르게 보일 수 있다(§113 · §117.6) — 크기와 checksum 이 이상하다는 이유만으로 결함으로 읽지 않는다. Bridge 가 단순 L2 forwarding 만 하는 구성에서는 frame 이 Host 의 L3 TCP/IP stack 을 거치지 않으므로 Host 쪽 L3 관측에서 안 보이는 것이 정상이다(§114). 네 지점이 모두 보이는데도 느린 경우는 이 규칙이 답하지 않는다 — 그때는 reference:verify-the-network-path-before-blaming-the-application 으로 넘긴다. 이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없어 규칙은 SSOT 가 서술한 것이고 이 Host 의 출력으로 확인된 것이 아니다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:verify-the-network-path-before-blaming-the-application", "question:vm-network-mode-bridge-nat-or-routed", "question:tap-interface-to-vm-mapping", "question:actual-packet-path-nginx-to-keycloak" ], "publication": "게시됨", "file": "network-virtualization/reference/reference-bisect-the-packet-path-with-capture-points.md", "status": "초안", "studioId": "68a848c7-eaff-4421-ad25-de21673ca40c", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다", "kind": "reference", "slug": "verify-the-network-path-before-blaming-the-application", "readiness": "READY", "source": [ "final/document.md#120-keycloak-refresh-token-실험과의-관계", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-7", "final/document.md#124-핵심-claim", "final/document.md#89-문서-목적", "final/document.md#116-현재-keycloak-k3s-테스트-환경과-연결", "final/document.md#102-packet이-keycloak까지-올라오는-과정" ], "classification": "§120 은 Refresh Token 경쟁 자체는 virtio-net 문제가 아니지만 Client → Nginx → VM1/VM2 → K3s → Keycloak → PostgreSQL/Redis 경로를 공유하므로 network virtualization 문제가 실험 결과에 영향을 줄 수 있다고 적고, Node1 요청만 지연 · VM2 packet loss · Host bridge misconfiguration · NAT/conntrack issue · Host CPU contention 으로 인한 vhost 처리 지연을 Refresh Token 경쟁이나 DB lock 으로 오해하지 않도록 network path 를 별도로 검증하라고 못박았다. §124 의 Claim 17 이 같은 것을 한 줄로 적었고, §117.7 은 반대 방향까지 덧붙였다 — vhost-net · QEMU thread · softirq 도 Host CPU 를 쓰므로 network 문제처럼 보이는 것이 CPU scheduling 문제일 수도 있다. reference:bisect-the-packet-path-with-capture-points 가 network 안에서 어느 hop 인지를 가른다면 이 규칙은 그것이 network 인지 아닌지를 가르므로 둘은 다른 물음에 답한다.", "scope": "여러 노드가 같은 network path 를 공유하는 실험의 결과를 원인에 귀속할 때. 특히 노드별로만 나타나는 지연, 특정 VM 에서만 나는 실패, 부하 구간에서만 커지는 latency 를 애플리케이션 동시성이나 저장소 lock 으로 결론내기 전에 적용한다. 검증 순서는 경로가 무엇인지(question:actual-packet-path-nginx-to-keycloak) · 그 경로가 끊기지 않았는지(reference:bisect-the-packet-path-with-capture-points) · network 처리가 Host CPU 를 얼마나 쓰는지(question:network-virtualization-cpu-cost-under-load) 셋이고, 셋을 애플리케이션 실험과 같은 시간축에 기록한다.", "exceptions": "Keycloak 은 virtqueue · vhost-net · TAP · Bridge · Physical NIC 를 직접 알지 못하고 Guest socket 위에서만 동작하므로(§102) 애플리케이션 로그만으로는 이 계층이 원인인지 아닌지를 가를 수 없다 — 이 규칙은 애플리케이션 쪽 관측을 늘려서는 적용되지 않는다. 반대로 network 계층이 깨끗해도 이 규칙이 애플리케이션 결함을 배제해 주지는 않는다. §116 이 그린 이 환경의 경로는 아직 확인된 것이 아니라 기준 구조를 얹은 그림이고, K3s 안의 CNI · Service · Pod network 는 §116 이 별도 계층으로 미뤄 두어 이 규칙의 범위 밖이다. 이 저장소에는 이 규칙으로 원인을 실제로 가른 실험이 아직 없다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:bisect-the-packet-path-with-capture-points", "question:actual-packet-path-nginx-to-keycloak", "question:network-virtualization-cpu-cost-under-load", "question:virtualization-layer-saturation-during-refresh" ], "publication": "게시됨", "file": "network-virtualization/reference/reference-verify-the-network-path-before-blaming-the-application.md", "status": "초안", "studioId": "ca36f0db-9028-4761-91a8-afb7eb30f2b9", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "question": [ { "title": "이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가", "kind": "question", "slug": "vm-network-mode-bridge-nat-or-routed", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-1", "final/document.md#96-linux-bridge의-역할", "final/document.md#97-routing의-역할", "final/document.md#98-nat의-역할", "final/document.md#114-linux-bridge가-항상-host-tcp-ip-stack을-거치는-것은-아니다", "final/document.md#94-전체-네트워크-계층" ], "known": "§96 은 Linux Bridge 를 Host Kernel 안의 L2 software switch 로, Destination MAC 을 보고 port 를 고르며 MAC learning 을 한다고 적었다. §97 은 Routing 을 L3·IP 기반으로 서로 다른 IP network 를 잇는 것으로, §98 은 NAT 을 packet 의 IP/Port 를 바꾸는 것으로 놓고 VM 이 private subnet 을 쓰면 Host 가 NAT gateway 처럼 동작할 수 있다는 예(192.168.122.10 → 203.0.113.10)를 들었다. 그 셋을 두고 §98 은 VM network 를 분석할 때 Bridge 기반인가 · Routing 기반인가 · NAT 기반인가를 먼저 구분하라고 적었다. §114 는 Bridge 가 단순 L2 forwarding 을 하면 frame 이 Host 의 L3 stack 을 반드시 거치는 것은 아니고 Routing · NAT · Host-local termination · Firewall 이 걸릴 때 L3/Netfilter 경로가 개입한다고 밝혔다. §94 는 이 문서가 기준으로 삼은 구조가 virtio-net + vhost-net + TAP + Linux Bridge 이고 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 적었다. 이 Host 의 network 구성이 셋 중 무엇인지는 SSOT 어디에도 적혀 있지 않다.", "unknown": "이 Host 의 VM network 가 Bridge 기반인지 NAT 기반인지 Routing 기반인지, libvirt virtual network 로 정의되어 있는지 Host 의 bridge 에 직접 붙어 있는지, 그리고 그 구성에서 VM 을 떠난 frame 이 Host 의 L3/Netfilter 경로를 지나는지 지나지 않는지.", "next-verification": "§122 OQ-1 이 적은 다섯을 그대로 돌린다 — `virsh net-list --all` 로 정의된 virtual network 를 열거하고, 나온 이름마다 `virsh net-dumpxml ` 로 forward mode 와 bridge 이름을 읽고, `ip link` 로 interface 목록을, `bridge link` 로 어떤 interface 가 어느 bridge 에 enslave 되어 있는지를, `ip route` 로 routing table 을 적는다. 출력은 그대로 증거로 남긴다.", "decision-criterion": "세 구성 중 무엇인지가 출력으로 확정되면 닫는다. Bridge 로 나오면 §96 과 §114 의 L2 forwarding 서술이 이 Host 에 적용된다고 적고, NAT 으로 나오면 §98 의 주소 변환이 경로에 들어간다고 적고, Routing 이면 §97 의 L3 결정이 들어간다고 적는다. 어느 쪽이든 그 결과가 question:actual-packet-path-nginx-to-keycloak 의 capture 지점을 정하고, §94 가 기준으로 삼은 구조와 다르면 이 부의 서술 가운데 어느 절이 이 Host 에 적용되지 않는지를 함께 적는다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:bisect-the-packet-path-with-capture-points", "question:tap-interface-to-vm-mapping", "question:actual-packet-path-nginx-to-keycloak" ], "publication": "게시됨", "file": "network-virtualization/question/question-vm-network-mode-bridge-nat-or-routed.md", "status": "초안", "studioId": "38716d7f-1aa1-48d8-ab4c-3fc505332128", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가", "kind": "question", "slug": "tap-interface-to-vm-mapping", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-2", "final/document.md#99-tap의-역할", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-1", "final/document.md#118-실제-linux에서-확인할-명령어" ], "known": "§99 는 TAP 이 물리 장치가 아니라 Host Linux Kernel 이 제공하는 가상 Ethernet interface(tap0 · vnet0 같은 이름)이고 VM 의 Ethernet frame 과 Host Linux networking 을 잇는 접점이라고 적었다. 수신은 Linux Bridge → TAP → VM, 송신은 VM → TAP → Linux Bridge 다. 확인 명령으로 `ip link` · `ip tuntap show` · `bridge link` · `virsh domiflist ` 을 들었고 §118 이 같은 명령을 계층별 목록으로 다시 적었다. §117.1 은 TAP/Bridge 연결 오류의 증상으로 VM 외부 통신 불가 · Host ↔ VM 통신 불가 · 특정 VM 만 통신 불가 셋을 들었다. 두 VM 의 interface 이름도 어느 bridge 에 붙어 있는지도 SSOT 에는 없다.", "unknown": "VM1 과 VM2 의 Host 쪽 interface 이름이 각각 무엇인지, 각 interface 의 MAC 과 model 이 무엇인지, 그리고 그 둘이 같은 bridge 에 붙어 있는지 서로 다른 곳에 붙어 있는지.", "next-verification": "`virsh domiflist vm1` 과 `virsh domiflist vm2` 로 각 VM 의 interface · type · source · model · MAC 을 적고, `ip link` 로 Host 에 실재하는 이름과 대조하고, `bridge link` 로 어느 bridge 의 port 인지를 적는다 (§122 OQ-2). 두 VM 의 결과를 한 표로 남긴다.", "decision-criterion": "VM 마다 interface 이름 · MAC · 붙어 있는 bridge 를 한 표로 적으면 닫는다. 이 표는 reference:bisect-the-packet-path-with-capture-points 가 요구하는 capture 지점의 이름을 대는 것이라, 표가 없으면 question:actual-packet-path-nginx-to-keycloak 의 tcpdump 를 어느 interface 에 걸어야 하는지 정할 수 없다. 두 VM 이 서로 다른 bridge 에 붙어 있으면 §117.1 의 「특정 VM 만 통신 불가」를 진단할 때 그 사실을 먼저 본다고 적는다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:bisect-the-packet-path-with-capture-points", "question:vm-network-mode-bridge-nat-or-routed", "question:actual-packet-path-nginx-to-keycloak" ], "publication": "게시됨", "file": "network-virtualization/question/question-tap-interface-to-vm-mapping.md", "status": "초안", "studioId": "397c4789-0272-449b-86d6-2c4a3a122401", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가", "kind": "question", "slug": "is-vhost-net-actually-in-use", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-3", "final/document.md#103-qemu-virtio-device-model의-역할", "final/document.md#104-왜-tap-→-vhost-net-→-qemu-→-virtqueue-라고-일반화하면-안-되는가", "final/document.md#106-qemu가-userspace인데-packet이-qemu를-안-거칠-수-있는-이유", "final/document.md#107-vhost-net-최적화", "final/document.md#108-vhost-net은-qemu를-제거하지-않는다", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-4" ], "known": "§103 은 QEMU 의 virtio Device Model 이 Host Userspace 의 QEMU process 안에 있고, 장치 생성/설정/관리와 실제 packet datapath 처리라는 두 역할을 나눠 봐야 한다고 적었다. datapath 는 QEMU backend 를 직접 쓰면 TAP → QEMU virtio backend → virtqueue → Guest 이고, vhost-net 을 쓰면 TAP → vhost-net → virtqueue → Guest 다. §104 는 그래서 `TAP → vhost-net → QEMU → virtqueue` 를 일반적인 경로로 그리면 안 된다고 못박았고, §106 은 장치의 생성/관리 주체와 runtime datapath 처리 주체가 다르다는 것을 CPU 가상화(QEMU 가 vCPU 를 만들어도 Guest instruction 은 KVM/VMX 가 실행한다)에 빗대 설명했다. §108 은 vhost-net 을 써도 QEMU 가 lifecycle · device 생성 · feature negotiation · queue configuration · backend 연결 · device reset 을 계속 맡는다고 적었다. §117.4 는 높은 packet rate 에서 QEMU userspace 가 datapath 를 직접 처리하면 CPU overhead 가 커질 수 있다고 밝혔다. 이 Host 가 둘 중 어느 backend 를 쓰는지는 SSOT 에 없다.", "unknown": "이 Host 에서 vhost 커널 모듈이 올라와 있는지, 두 VM 의 domain XML 과 QEMU arguments 가 vhost backend 를 쓰도록 되어 있는지, 그래서 지금 흐르는 packet 의 datapath 가 §103 이 그린 둘 가운데 어느 쪽인지.", "next-verification": "`lsmod | grep vhost` 로 모듈 적재를 보고(§122 OQ-3 · §118), 그것만으로는 그 VM 이 쓴다는 뜻이 아니므로 `virsh dumpxml vm1` · `virsh dumpxml vm2` 의 interface 절에서 driver name 을 읽고 QEMU 실행 인자를 함께 확인한다. Host 에 vhost 커널 스레드가 떠 있는지도 process 목록에서 확인해 VM 별로 짝지어 적는다.", "decision-criterion": "두 VM 각각에 대해 backend 가 vhost-net 인지 QEMU userspace 인지가 설정과 실행 상태로 확정되면 닫는다. vhost-net 이면 §125 의 「Data Path - vhost-net 사용」 그림이 이 Host 의 경로라고 적고, QEMU backend 면 「Data Path - QEMU backend 사용」 쪽이라고 적는다. 어느 쪽이든 그 결과가 question:qemu-backend-vs-vhost-net-on-this-host 의 비교 대상 하나를 고정하고, 후보 SSOT-116-test-environment-packet-path 의 NEEDS_EVIDENCE 를 푸는 세 확인 가운데 하나가 된다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "question:qemu-backend-vs-vhost-net-on-this-host", "question:network-virtualization-cpu-cost-under-load", "question:actual-packet-path-nginx-to-keycloak" ], "publication": "게시됨", "file": "network-virtualization/question/question-is-vhost-net-actually-in-use.md", "status": "초안", "studioId": "484fd832-c7d3-413e-897a-97892e4e10ac", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가", "kind": "question", "slug": "qemu-backend-vs-vhost-net-on-this-host", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-4", "final/document.md#107-vhost-net-최적화", "final/document.md#110-data-copy-최적화", "final/document.md#111-interrupt-notification-최적화", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-4" ], "known": "§107 은 QEMU userspace 가 packet 마다 I/O 를 처리하면 Host Kernel ↔ QEMU Userspace 전환이 쌓이고 packet rate 가 높아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다고 적었다. 최적화 방향은 packet 마다 QEMU userspace 가 개입하던 것을 kernel backend 로 옮겨 context switch 와 userspace overhead 를 줄이는 것이다. §110 은 그 구조가 buffer descriptor 로 불필요한 copy 를 줄이도록 설계되어 있지만 항상 zero-copy 라고 일반화하면 안 되고 실제 copy 여부가 kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO 에 따라 달라질 수 있다고 밝혔다. §122 OQ-4 는 비교할 축으로 Latency · Throughput · QEMU CPU · Host CPU · Context Switch · Packet rate 여섯을 적었다. 이 Host 에서 두 backend 를 재 본 값은 없다.", "unknown": "같은 workload 를 두 backend 로 돌렸을 때 여섯 축이 실제로 얼마나 달라지는지, 그리고 그 차이가 이 실험의 결과를 다르게 읽어야 할 만큼인지 아니면 측정 흔들림 안인지.", "next-verification": "question:is-vhost-net-actually-in-use 로 현재 backend 를 먼저 확정한 뒤, 같은 VM 을 다른 backend 로 바꿔 구성하고 동일한 workload 를 양쪽에 건다. 두 구성 각각에서 §122 OQ-4 의 여섯 축을 같은 시각에 기록한다 — Latency 와 Throughput 과 packet rate 는 부하 도구가 재는 값을, QEMU CPU 와 Host CPU 와 context switch 는 Host 에서 process/스레드 단위로 잰다. 부하를 걸기 전 같은 여섯을 한 번 찍어 기준값으로 둔다.", "decision-criterion": "두 구성의 여섯 축을 한 표로 나란히 적으면 닫는다. 차이가 기준값 흔들림 안이면 이 Host 의 packet rate 에서는 backend 선택이 결과를 바꾸지 않는다고 적고 닫는다. 차이가 나면 그 표가 Case 가 되고, 어느 backend 로 실험을 고정할지는 그 Case 뒤에 Decision 으로 넘긴다. 어느 쪽이든 §110 이 말한 조건들(kernel/QEMU version · offload · NIC capability)을 함께 적지 않으면 다른 환경에 재사용할 수 없다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "question:is-vhost-net-actually-in-use", "question:network-virtualization-cpu-cost-under-load", "reference:verify-the-network-path-before-blaming-the-application" ], "publication": "게시됨", "file": "network-virtualization/question/question-qemu-backend-vs-vhost-net-on-this-host.md", "status": "초안", "studioId": "bded6560-dc8d-473d-966c-5b037bb84c4c", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가", "kind": "question", "slug": "virtio-net-multi-queue-enabled", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-5", "final/document.md#112-multi-queue-최적화", "final/document.md#100-virtqueue의-역할", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-5" ], "known": "§112 는 queue 하나만 쓰면 특정 vCPU 나 처리 경로에 부하가 몰릴 수 있고 virtio-net 은 multi-queue 를 쓸 수 있다고 적었다. RX Queue 0~3 을 vCPU 0~3 에 대응시킨 예를 들었고 목적을 packet processing 병렬화 · single queue bottleneck 완화 · multi-core 활용으로 놓았으며, 효과가 workload · CPU affinity · IRQ placement · queue configuration 에 따라 달라진다고 밝혔다. §100 은 virtqueue 가 Guest 와 Host backend 가 I/O buffer 를 주고받는 descriptor 기반 shared queue 이고 네트워크에서는 보통 TX/RX 를 쓴다고 적었다. §117.5 는 single queue bottleneck 의 확인 대상으로 virtio multi-queue · IRQ distribution · per-vCPU CPU usage · RSS/RPS/XPS 를 들었다. 이 VM 들의 queue 수는 SSOT 에 없다.", "unknown": "두 VM 의 virtio-net 에 설정된 queue 수가 몇인지, Guest 가 실제로 몇 개를 쓰고 있는지, 그리고 그 queue 들의 IRQ 가 vCPU 에 흩어져 있는지 한 vCPU 에 몰려 있는지.", "next-verification": "§122 OQ-5 가 적은 넷을 확인한다 — QEMU/libvirt 의 NIC configuration(`virsh dumpxml` 의 interface 절에 적힌 queue 수), Guest 에서 `ethtool` 로 본 channel 수, 실제 queue count, 그리고 Guest 의 IRQ 분포. 두 VM 을 같은 방식으로 적고 vCPU 수와 나란히 남긴다.", "decision-criterion": "VM 마다 설정된 queue 수 · Guest 가 쓰는 queue 수 · IRQ 분포를 한 표로 적으면 닫는다. queue 가 하나로 나오면 §117.5 의 single queue bottleneck 이 이 환경에서 구조적으로 가능하다고 적고, 그것이 실제로 병목인지는 부하를 건 뒤 question:network-virtualization-cpu-cost-under-load 의 per-vCPU 사용량이 답한다. 여럿으로 나오고 IRQ 도 흩어져 있으면 이 축은 현재 실험에서 우선순위를 낮추고 닫는다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "question:network-virtualization-cpu-cost-under-load", "question:is-vhost-net-actually-in-use" ], "publication": "게시됨", "file": "network-virtualization/question/question-virtio-net-multi-queue-enabled.md", "status": "초안", "studioId": "1a996f8d-b04e-49d2-88ef-4877e21f7c0e", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가", "kind": "question", "slug": "actual-packet-path-nginx-to-keycloak", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-6", "final/document.md#116-현재-keycloak-k3s-테스트-환경과-연결", "final/document.md#119-실제-packet-path-추적", "final/document.md#94-전체-네트워크-계층", "final/document.md#125-최종-기준-구조" ], "known": "§116 은 이 테스트 환경의 경로를 Client → Host Physical NIC → Host Nginx → Host Network → VM1/VM2 → K3s → Keycloak 으로 놓고, VM network 까지 펼치면 Physical NIC → Host Network Stack/Bridge/Route/NAT → TAP(vm1)/TAP(vm2) → vhost-net → virtqueue → virtio-net → Guest Network Stack → K3s networking → Keycloak 이 된다고 적었다. §94 와 §125 가 같은 경로를 수신·송신 양방향으로 그렸다. §119 는 그 경로를 확인하는 방법으로 Host 에서 physical NIC · bridge · tap/vnet 에, Guest 에서 guest interface 에 각각 `tcpdump -ni` 를 걸고 어디까지 보이는지로 의심 구간을 좁히라고 적었다. §116 이 그린 펼친 경로는 이 Host 에서 확인된 것이 아니라 기준 구조를 이 환경에 얹은 그림이다.", "unknown": "Host Nginx 를 지난 packet 이 실제로 어느 bridge 와 어느 TAP 을 거쳐 어느 VM 의 interface 로 들어가는지, 그리고 그 경로가 §116 이 그린 그림과 같은지 다른지. K3s 안에서 Keycloak Pod 까지 가는 구간은 §116 이 별도 계층으로 미뤄 둔 부분이라 이 물음이 닫는 범위 밖이다.", "next-verification": "question:vm-network-mode-bridge-nat-or-routed 와 question:tap-interface-to-vm-mapping 으로 capture 지점의 이름을 먼저 확정한다. 그다음 Host 에서 `sudo tcpdump -ni ` · `sudo tcpdump -ni ` · `sudo tcpdump -ni ` 을, Guest 에서 `sudo tcpdump -ni ` 를 동시에 걸고 Host Nginx 를 통해 Keycloak 요청을 한 번 보낸다 (§122 OQ-6 · §119). 네 지점의 O/X 를 그대로 적는다. offload 가 켜져 있으면 §113 대로 packet size 와 checksum 이 wire 와 다르게 보일 수 있으므로 그 상태를 함께 적는다.", "decision-criterion": "네 지점의 capture 결과로 실제 경로를 한 줄로 적으면 닫는다. §116 이 그린 그림과 같으면 그 그림을 이 Host 에서 확인된 경로로 승격하고 후보 SSOT-116-test-environment-packet-path 를 다시 판정한다. 다르면 어느 hop 이 다른지를 적고 §119 의 표대로 그 구간을 의심 구간으로 넘긴다. 중간 지점에서 끊기면 그것은 이 물음의 답이 아니라 장애이므로 reference:bisect-the-packet-path-with-capture-points 로 넘긴다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:bisect-the-packet-path-with-capture-points", "question:vm-network-mode-bridge-nat-or-routed", "question:tap-interface-to-vm-mapping", "reference:verify-the-network-path-before-blaming-the-application" ], "publication": "게시됨", "file": "network-virtualization/question/question-actual-packet-path-nginx-to-keycloak.md", "status": "초안", "studioId": "600a2621-f6d8-42df-9629-7db65011545d", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가", "kind": "question", "slug": "network-virtualization-cpu-cost-under-load", "readiness": "OPEN", "source": [ "final/document.md#122-open-question-oq-7", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-7", "final/document.md#107-vhost-net-최적화", "final/document.md#111-interrupt-notification-최적화", "final/document.md#120-keycloak-refresh-token-실험과의-관계" ], "known": "§117.7 은 vhost-net · QEMU thread · softirq 도 Host CPU 를 쓰므로 network 문제처럼 보여도 CPU scheduling 문제일 수 있다고 적었다. §107 은 packet rate 가 높아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다고, §111 은 packet 마다 과도한 interrupt/notification 이 나면 overhead 가 커져 batching 과 interrupt moderation 이 중요하다고 밝혔다. §120 은 Node1 요청만 지연 · VM2 packet loss · Host bridge misconfiguration · NAT/conntrack issue · Host CPU contention 으로 인한 vhost 처리 지연을 Refresh Token 경쟁이나 DB lock 으로 오해하지 않도록 network path 를 따로 검증하라고 적었다. §122 OQ-7 은 관찰 대상으로 QEMU CPU · vhost thread · softirq · Host CPU · Guest CPU · network latency 여섯을 적었다. 이 여섯 가운데 vhost thread 와 softirq 는 제1부·제2부 어디에도 나오지 않아 CPU 가상화 쪽 물음이 재는 지표와 겹치지 않는다.", "unknown": "Keycloak load test 구간에서 vhost 커널 스레드와 softirq 가 Host CPU 를 얼마나 쓰는지, 그 사용량이 QEMU vCPU thread 사용량과 어떻게 나뉘는지, 그리고 그것이 network latency 와 같은 시간축에서 함께 움직이는지.", "next-verification": "Keycloak load test 를 돌리면서 §122 OQ-7 의 여섯을 같은 시각에 기록한다 — Host 에서 QEMU process 와 vhost 커널 스레드의 CPU 사용량을 스레드 단위로, softirq 시간을, Host 전체 CPU 를 적고, 각 Guest 에서 Guest CPU 를, 부하 도구에서 network latency 를 적는다. 부하를 걸기 전 같은 여섯을 한 번 찍어 기준값으로 둔다. Guest 의 steal time 과 QEMU vCPU thread 쪽은 question:virtualization-layer-saturation-during-refresh 가 이미 재므로 같은 실험 구간에서 두 기록을 함께 남긴다.", "decision-criterion": "부하 구간의 vhost thread 와 softirq 사용량이 기준값과 다르지 않고 network latency 도 움직이지 않으면, 이 부하 수준에서는 network 가상화가 Host CPU 를 지연에 영향을 줄 만큼 쓰지 않는다고 적고 닫는다. 셋 중 하나라도 움직이면 그 표가 Case 가 되고, vhost thread 를 어느 CPU 에 둘지나 multi-queue 를 켤지는 그 Case 뒤에 Decision 으로 넘긴다. 어느 쪽이든 이 결과가 없으면 §120 이 경고한 오귀속(network 지연을 Refresh Token 경쟁으로 읽는 것)을 배제했다고 말할 수 없다.", "relations": [ "concept:guest-packet-path-to-physical-nic", "reference:verify-the-network-path-before-blaming-the-application", "question:qemu-backend-vs-vhost-net-on-this-host", "question:virtio-net-multi-queue-enabled", "question:virtualization-layer-saturation-during-refresh" ], "publication": "게시됨", "file": "network-virtualization/question/question-network-virtualization-cpu-cost-under-load.md", "status": "초안", "studioId": "79ac61d6-cbe6-483b-9961-02ca8c02b5c2", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "decision": [] } }, "storage-virtualization": { "topic": "storage-virtualization", "title": "스토리지 가상화 — Guest 의 write() 와 fsync() 가 Host 물리 NVMe 까지 가는 길", "readerQuestion": "Guest 애플리케이션의 write() 와 fsync() 는 어느 계층을 거쳐 Host 의 물리 NVMe 까지 가고, 느리거나 데이터가 남지 않았을 때 그것이 storage 가상화의 어느 자리 문제인지 무엇을 보고 가르는가?", "kinds": { "case": [], "concept": [ { "title": "Guest 의 write() 가 virtqueue 에 실리기까지 — VFS · Filesystem · Page Cache · Block Layer · virtio-blk", "kind": "concept", "slug": "guest-block-io-path-to-virtqueue", "readiness": "READY", "source": [ "final/document.md#128-전체-구조", "final/document.md#129-guest-application-read-write-에서-시작", "final/document.md#130-vfs-공통-파일-인터페이스-계층", "final/document.md#131-filesystem-ext4-xfs-파일-세계를-block-공간에-배치", "final/document.md#132-inode", "final/document.md#133-page-cache-write-가-바로-ssd-write는-아니다", "final/document.md#134-guest-block-i-o-layer", "final/document.md#135-dev-vda-guest가-보는-가상-block-device", "final/document.md#136-dev-vda-와-filesystem-관계", "final/document.md#137-virtio-blk-guest의-가상-block-device-driver", "final/document.md#138-virtio-blk와-virtqueue", "final/document.md#139-virtqueue의-실제-의미", "final/document.md#166-storage-i-o-completion", "final/document.md#127-문서-목적", "final/document.md#172-storage-virtualization-canonical-flow", "final/document.md#173-network-virtualization과-비교", "final/document.md#177-최종-요약" ], "basis-version": "QEMU/KVM 의 virtio-blk frontend + virtqueue 구성. Guest 는 ext4 나 XFS 를 쓰고 buffered I/O 로 `write()` 하는 경우를 기준으로 삼는다 — §130 이 ext4 와 XFS 를 같은 자리에 놓았고 §133 이 「일반적인 buffered I/O」를 전제로 Page Cache 를 설명했다. SSOT 가 커널·QEMU·libvirt 버전을 한 번도 적지 않아 특정 버전에 고정하지 않는다. 이 글이 멈추는 경계도 SSOT 가 그었다 — §127 이 qcow2 내부 L1/L2 table · blk-mq tag allocator · NVMe submission/completion queue 를 별도 문서로 미뤘고, §134 도 `bio` · request · queue · `blk-mq` 가 실제로 존재한다고만 적고 내부로 들어가지 않는다.", "classification": "제4부에서 경로가 시작하는 구간이다. §129 부터 §139 까지가 한 줄기로 이어진다 — 애플리케이션은 `write(fd, buffer, size);` 를 부르고, VFS 가 그 fd 를 어느 filesystem 구현으로 보낼지 정하고, ext4/XFS 가 파일 세계를 block 공간에 배치하고, Page Cache 가 dirty page 로 받아 두었다가 writeback 하고, Block I/O Layer 가 그것을 READ/WRITE/FLUSH/DISCARD 요청으로 바꾸고, `/dev/vda` 를 통해 virtio-blk driver 가 Virtio block request 로 구성해 virtqueue 에 게시한다. 중간을 잘라 내면 인과가 끊긴다 — Page Cache 만 떼면 `write()` 성공이 왜 SSD 영속화가 아닌지 말할 수 없고, virtqueue 만 떼면 무엇과 무엇 사이의 queue 인지 말할 수 없다. §128 과 §172 와 §177 이 그린 canonical flow 의 Guest 절반이 이 글이고, 나머지 셋(backend 형태 · 완료의 뜻 · Host block stack)은 그 그림의 어느 구간을 맡는지로 갈린다. §166 이 completion 도 같은 virtqueue 로 돌아온다고 적어 이 글의 마지막 절이 된다.", "missing-verification": "이 테스트 Host 에서 잰 값이 하나도 없다. §175 의 OQ-1 이 이 Host 의 `/dev/vda` 가 무엇에 붙어 있는지를 아직 확인하지 않았다고 적어 두었고, Guest 의 filesystem 이 ext4 인지 XFS 인지도 SSOT 어디에도 없다. 이 글은 「이 구조에서는 이렇게 동작한다」까지만 말하고 「이 서버가 그 구조다」라고는 말하지 않는다. 실제 요청 수나 latency 를 재려면 question:guest-fsync-latency-vs-host-storage-latency 가 먼저 돌아야 한다.", "relations": [ "concept:qemu-block-backend-forms", "concept:write-completion-is-not-durability", "concept:host-block-stack-under-the-vm", "reference:confirm-the-disk-backend-on-the-host", "question:vm-disk-backend-mapping", "question:guest-fsync-latency-vs-host-storage-latency", "concept:guest-packet-path-to-physical-nic" ], "ssot-assets": [ "guest-block-io-to-virtqueue" ], "publication": "게시됨", "file": "storage-virtualization/concept/concept-guest-block-io-path-to-virtqueue.md", "status": "초안", "studioId": "3b05c1f0-13e9-414a-97a6-2078fb4bab26", "assets": [ "guest-block-io-to-virtqueue" ], "assetFiles": [ "guest-block-io-to-virtqueue" ], "evidenceFiles": [] }, { "title": "/dev/vda 뒤에 있는 것 — qcow2 · RAW · Host block device", "kind": "concept", "slug": "qemu-block-backend-forms", "readiness": "READY", "source": [ "final/document.md#140-vm-boundary를-넘으면-qemu가-등장", "final/document.md#141-qemu가-물리-ssd를-직접-제어하는-것은-아니다", "final/document.md#142-qcow2-host에서는-파일-guest에서는-디스크", "final/document.md#143-qcow2-virtual-size와-실제-host-사용량", "final/document.md#144-raw-image", "final/document.md#145-host-block-device를-직접-backend로-사용-가능", "final/document.md#146-실제-연결-확인", "final/document.md#128-전체-구조", "final/document.md#172-storage-virtualization-canonical-flow", "final/document.md#174-핵심-claim" ], "basis-version": "QEMU block backend 세 형태 — qcow2 파일 · RAW 파일 · Host block device — 를 libvirt 로 정의한 VM 기준. §142 는 `/var/lib/libvirt/images/keycloak-node1.qcow2` 를, §145 는 `/dev/nvme0n1p3` 를 예로 들었다. SSOT 가 QEMU·libvirt 버전을 적지 않아 특정 버전에 고정하지 않고, §127 이 qcow2 내부 L1/L2 table 을 범위 밖으로 두었으므로 이 글은 backend 형태의 구분과 그 구분이 무엇을 바꾸는지까지만 설명한다.", "classification": "§128 이 핵심 문장으로 뽑은 것이 이 글의 물음이다 — Guest 는 `/dev/vda` 를 실제 block device 처럼 보지만 Host 에서는 그 disk 가 qcow2 파일일 수도, RAW 파일일 수도, 실제 block device 일 수도 있다. 세 갈래가 각각 무엇을 바꾸는지가 SSOT 에 따로 적혀 있다 — qcow2 는 Copy-on-Write · sparse allocation · snapshot 에 유리하지만 metadata/mapping 처리가 있고(§144), virtual size 와 Host 실제 할당량이 갈리며(§143), 파일 backend 이면 Guest filesystem 아래에 Host filesystem/storage stack 이 한 번 더 놓인다(§141). C1 과 갈라 두는 이유는 이 구간에서만 경로가 셋으로 분기하기 때문이다 — 경로를 그리는 글에 이 분기를 넣으면 세 갈래 각각의 결과가 한 글의 각주가 된다. §144 가 「RAW = 무조건 빠름 / qcow2 = 무조건 느림」으로 일반화하지 말라고 못박은 것이 이 글이 닫는 자리다.", "missing-verification": "이 Host 의 backend 가 셋 중 무엇인지 SSOT 에 없다. §175 의 OQ-1 · OQ-2 · OQ-3 · OQ-5 넷이 그 확인을 아직 돌리지 않은 상태로 적혀 있고, §143 이 든 100 GB/3GB 나 1GB→10GB→40GB 는 예시 값이지 이 장비에서 잰 값이 아니다. 성능 비교도 이 저장소에 없다 — §144 가 cache mode · storage backend · workload pattern · queue depth · snapshot chain · underlying filesystem · physical device 에 따라 달라진다고만 적었다.", "relations": [ "concept:guest-block-io-path-to-virtqueue", "concept:write-completion-is-not-durability", "concept:host-block-stack-under-the-vm", "reference:confirm-the-disk-backend-on-the-host", "question:vm-disk-backend-mapping", "question:disk-image-format-and-actual-host-usage", "question:host-block-device-under-the-disk-image" ], "publication": "게시됨", "file": "storage-virtualization/concept/concept-qemu-block-backend-forms.md", "status": "초안", "studioId": "892b6087-8961-486c-b4d9-d3dd46bc2605", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "완료라는 말의 네 가지 뜻 — write · writeback · flush · 전원 장애 생존", "kind": "concept", "slug": "write-completion-is-not-durability", "readiness": "READY", "source": [ "final/document.md#147-vm에서는-page-cache가-두-번-나타날-수-있다", "final/document.md#148-write-완료와-영속화는-다르다", "final/document.md#149-direct-i-o", "final/document.md#150-fsync-가-필요한-이유", "final/document.md#151-flush", "final/document.md#152-가장-위험한-상황-거짓-완료", "final/document.md#153-qemu-cache-mode", "final/document.md#154-cache=none", "final/document.md#155-cache=writeback", "final/document.md#156-writeback-=-위험-이라고-단정하면-안-되는-이유", "final/document.md#157-device-side-cache", "final/document.md#170-postgresql-예시-wal과-durability", "final/document.md#133-page-cache-write-가-바로-ssd-write는-아니다", "final/document.md#174-핵심-claim" ], "basis-version": "Linux `O_DIRECT` 와 QEMU/libvirt disk 의 `cache=none` · `cache=writeback` 두 설정 기준. §153 이 「대표적으로 볼 수 있는 설정」으로 이 둘만 들었으므로 다른 cache mode 값은 이 글의 범위가 아니고, SSOT 가 QEMU 버전을 적지 않아 버전별 차이도 다루지 않는다. §151 이 실제 ordering/durability semantics 는 더 복잡하다고 스스로 밝힌 만큼 이 글은 WRITE 와 FLUSH 의 구분까지만 말한다.", "classification": "§148 이 네 단계를 한 줄로 세웠다 — `write()` 완료 ≠ writeback 완료 ≠ fsync/flush 완료 ≠ 전원 장애에도 안전한 durability. 그 네 자리마다 VM 에서만 생기는 사정이 붙는다. Page Cache 가 Guest 와 Host 양쪽에 두 번 나타날 수 있고(§147), Direct I/O 는 Page Cache 우회이지 자동 durability 보장이 아니며(§149), `cache=none` 은 이중 caching 을 줄이지만 즉시 durable media 반영을 뜻하지 않고(§154), `cache=writeback` 이 Guest 의 `fsync()`/FLUSH 를 무시한다는 뜻도 아니다(§155). Host Page Cache 를 우회해도 device 쪽 volatile write cache 가 남는다(§157). 이 글이 닫는 것은 §152 다 — Guest 에게 `FLUSH 완료` 라고 응답했는데 실제로는 Host RAM 에만 있는 상태는 성능 문제가 아니라 durability contract 가 깨지는 correctness 문제다. C1·C2·C4 가 경로를 말한다면 이 글은 그 경로 위에서 「완료」라는 응답이 무엇을 보장하는지를 말하므로 물음이 다르다. §170 의 PostgreSQL WAL 예시가 그 보장이 깨질 때 무엇이 어긋나는지를 보여 준다.", "missing-verification": "이 Host 의 disk cache mode 가 무엇인지 SSOT 에 없다 — §175 OQ-4 가 그 확인을 적어 두었다. 거짓 완료(§152)가 이 환경에서 실제로 일어나는지도, device 가 power-loss protection 을 갖췄는지도 재지 않았다. §157 이 device flush/FUA semantics 와 power-loss protection 여부가 「중요할 수 있다」고만 적은 자리가 그대로 남아 있다. `fsync()` latency 값은 question:guest-fsync-latency-vs-host-storage-latency 가 잰 뒤에야 이 글에 들어온다.", "relations": [ "concept:guest-block-io-path-to-virtqueue", "concept:qemu-block-backend-forms", "concept:host-block-stack-under-the-vm", "reference:a-speedup-that-removed-durability-is-not-an-optimization", "question:qemu-disk-cache-mode", "question:guest-fsync-latency-vs-host-storage-latency" ], "ssot-assets": [ "write-completion-boundaries" ], "publication": "게시됨", "file": "storage-virtualization/concept/concept-write-completion-is-not-durability.md", "status": "초안", "studioId": "8fafaeea-8746-4537-87a4-679a3a91aa4c", "assets": [ "write-completion-boundaries" ], "assetFiles": [ "write-completion-boundaries" ], "evidenceFiles": [] }, { "title": "VM 아래에 한 번 더 있는 Host block stack — blk-mq · I/O Scheduler · NVMe", "kind": "concept", "slug": "host-block-stack-under-the-vm", "readiness": "READY", "source": [ "final/document.md#158-host-block-layer", "final/document.md#159-여러-vm이-하나의-nvme를-공유하면", "final/document.md#160-blk-mq-multi-queue-block-layer", "final/document.md#161-i-o-scheduler", "final/document.md#162-none", "final/document.md#163-실제-i-o-scheduler-확인", "final/document.md#164-nvme-driver와-physical-device", "final/document.md#165-nvme와-ssd-구분", "final/document.md#167-storage-contention", "final/document.md#141-qemu가-물리-ssd를-직접-제어하는-것은-아니다", "final/document.md#172-storage-virtualization-canonical-flow" ], "basis-version": "현대 Linux 의 `blk-mq` 기반 block layer 와 NVMe driver 기준. scheduler 는 §161 이 든 `none` · `mq-deadline` · `bfq` 셋이고 §163 의 확인 예시 출력은 `[none] mq-deadline` 이다. SSOT 가 커널 버전을 적지 않아 고정하지 않고, §127 이 blk-mq tag allocator 와 NVMe submission/completion queue 를 별도 문서로 미뤘으므로 이 글은 queue 가 여럿이라는 구조와 dispatch 정책이 있다는 데까지만 설명한다.", "classification": "§158 의 한 문장이 이 글이 존재하는 이유다 — Host Block Layer 는 그 I/O 가 VM 안 PostgreSQL 에서 시작했는지 Host process 에서 시작했는지를 본질적으로 구분해서 처리하는 계층이 아니고, 모두 Host block request 다. 그래서 VM 두 대와 Nginx 와 Host 기타 프로세스의 요청이 한 queue 로 들어오고(§159), `blk-mq` 가 CPU 마다 queue 를 두어 병렬로 처리하고(§160), I/O Scheduler 가 들어온 순서 그대로 dispatch 하지 않을 수 있다(§161). 그 결과가 §167 의 Storage Contention 이고 SSOT 는 그것을 CPU Contention 과 다른 자원 경쟁으로 못박았다 — 하나는 Host logical CPU 실행 시간 경쟁이고 하나는 IOPS/bandwidth/queue/device 처리시간 경쟁이다. C2 가 backend 형태를 말한다면 이 글은 그 backend 아래에서 요청이 어떻게 줄을 서고 누구와 섞이는지를 말한다. §165 의 SSD 와 NVMe 구분(저장장치 종류 대 PCIe 기반 protocol/interface)이 이 계층의 이름을 정리한다.", "missing-verification": "이 Host 의 I/O Scheduler 도, VM 들이 같은 물리 장치를 쓰는지도 SSOT 에 없다 — §175 의 OQ-5 · OQ-6 · OQ-7 이 그 확인을 적어 두었다. §159 가 그린 VM1·VM2·Nginx 동시 I/O 도 이 환경에서 실제로 겹치는지 재지 않았고, §167 의 「VM1 에서 대량 I/O 가 발생하면 VM2 의 storage latency 가 증가할 수 있다」는 구조적 가능성이지 관측이 아니다.", "relations": [ "concept:guest-block-io-path-to-virtqueue", "concept:qemu-block-backend-forms", "concept:write-completion-is-not-durability", "reference:read-storage-before-blaming-cpu-for-latency", "question:host-block-device-under-the-disk-image", "question:host-io-scheduler", "question:vm1-storage-load-vs-vm2-latency" ], "ssot-assets": [ "vms-sharing-one-nvme" ], "publication": "게시됨", "file": "storage-virtualization/concept/concept-host-block-stack-under-the-vm.md", "status": "초안", "studioId": "ecaaa37d-7b33-4cbf-9bc5-4c6caad14ee5", "assets": [ "vms-sharing-one-nvme" ], "assetFiles": [ "vms-sharing-one-nvme" ], "evidenceFiles": [] } ], "reference": [ { "title": "지연 원인을 CPU 로 읽기 전에 storage 계층을 따로 잰다", "kind": "reference", "slug": "read-storage-before-blaming-cpu-for-latency", "readiness": "READY", "source": [ "final/document.md#168-cpu가-정상이어도-storage-때문에-느릴-수-있다", "final/document.md#167-storage-contention", "final/document.md#169-storage-관측-명령어", "final/document.md#174-핵심-claim", "final/document.md#177-최종-요약" ], "classification": "§168 이 규칙을 그대로 적었다 — PostgreSQL 이 storage completion 을 기다리고 있으면 CPU usage 가 높지 않을 수도 있어서 CPU 30% 인데 request latency 2초 가 가능하고, 따라서 CPU 지표만으로 latency 원인을 판단하면 안 된다. §167 이 그 앞에서 CPU Contention 과 Storage Contention 을 다른 자원 경쟁으로 갈라 두었고, §169 가 무엇을 볼지의 도구를 대고, §177 이 CPU usage 만 보지 말고 함께 볼 여덟 가지를 나열한다. §174 Claim 6 이 같은 것을 한 줄로 접었다 — Storage 성능은 Guest 내부만으로 결정되지 않는다. 원 프로젝트의 이름을 지워도 규칙이 남으므로 Case 요약이 아니고, 제2부의 reference:memory-symptom-needs-layer-separation 이 메모리 증상 안에서 다섯 갈래를 가른다면 이 규칙은 CPU 냐 storage 냐를 가르므로 답하는 물음이 다르다.", "scope": "요청 latency 나 처리량 저하의 원인을 자원에 귀속하려는 모든 판독. 특히 CPU usage 가 낮은데 latency 가 큰 구간, DB 가 낀 경로, VM 여러 대가 한 물리 장치를 쓰는 환경에 적용한다. 같은 시간축에 남길 것은 §177 이 적은 여덟이다 — Guest I/O latency · Host I/O queue · Host storage latency · QEMU backend · cache mode · I/O Scheduler · NVMe · 다른 VM 의 Storage load. 도구는 §169 가 댄다 — Guest 에서 `lsblk` · `mount` · `df -h` · `cat /proc/mounts` · `iostat -xz 1`, Host 에서 `virsh domblklist ` · `qemu-img info ` · `lsblk` · `cat /sys/block//queue/scheduler` · `iostat -xz 1` · `iotop`.", "exceptions": "이 규칙은 어느 자원인지를 좁힐 뿐 원인을 확정하지 않는다. storage 지표가 깨끗해도 CPU 쪽이 아니라는 뜻은 아니고, 제1부가 적은 vCPU contention 과 steal time 은 이 규칙 밖에서 따로 본다. `iostat -xz 1` 이 보여 주는 device utilization 성격의 지표는 NVMe 처럼 병렬성이 큰 장치에서 포화도로 그대로 읽히지 않는다 — §160 이 NVMe 가 높은 queue depth 와 병렬성을 지원한다고 적은 것이 그 이유다. Host 에서 잰 값은 어느 VM 의 I/O 인지 구분해 주지 않는다(§158) — VM 별로 가르려면 §169 의 `iotop` 이나 VM 쪽 관측을 같은 시각에 함께 찍어야 한다. 이 저장소에는 이 규칙으로 원인을 실제로 가른 측정이 아직 없다.", "relations": [ "concept:host-block-stack-under-the-vm", "concept:guest-block-io-path-to-virtqueue", "reference:confirm-the-disk-backend-on-the-host", "question:vm1-storage-load-vs-vm2-latency", "question:guest-fsync-latency-vs-host-storage-latency", "reference:memory-symptom-needs-layer-separation" ], "publication": "게시됨", "file": "storage-virtualization/reference/reference-read-storage-before-blaming-cpu-for-latency.md", "status": "초안", "studioId": "b1cda8c4-d31d-4ae4-a4d9-4103a0ab3109", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "빨라진 구성이 durability contract 를 지운 것은 아닌지 먼저 가른다", "kind": "reference", "slug": "a-speedup-that-removed-durability-is-not-an-optimization", "readiness": "READY", "source": [ "final/document.md#171-성능과-durability의-trade-off", "final/document.md#152-가장-위험한-상황-거짓-완료", "final/document.md#156-writeback-=-위험-이라고-단정하면-안-되는-이유", "final/document.md#148-write-완료와-영속화는-다르다", "final/document.md#157-device-side-cache", "final/document.md#150-fsync-가-필요한-이유", "final/document.md#170-postgresql-예시-wal과-durability", "final/document.md#174-핵심-claim" ], "classification": "§171 이 규칙 문장을 그대로 적었다 — `fsync()` 를 없애서 빨라졌다면 그것이 최적화가 아니라 durability contract 를 제거한 것일 수 있다. 그 판단이 왜 성능 문제가 아닌지는 §152 가 댄다. Guest 에게 `FLUSH 완료` 라고 응답했는데 실제로는 Host RAM 에만 있으면 PostgreSQL 은 durability 가 확보되었다고 판단하고, 직후 Host 전원이 나가면 RAM 의 data 가 사라진다 — 성능 문제가 아니라 correctness 문제다. §156 이 반대 방향의 오독까지 막는다. writeback 이라는 이름만 보고 위험하다고 단정하는 것이 아니라 Guest 의 flush/fsync semantics 가 전체 backend/storage stack 에서 올바르게 보존되는지를 보는 것이 정확한 표현이다. 규칙이 향하는 대상이 설정 선택과 성능 개선의 평가라 개념 본문의 각주로 두면 다음 프로젝트가 다시 찾지 못한다.", "scope": "storage 관련 설정이나 코드를 바꿔 write/commit latency 가 개선됐을 때, 그리고 cache mode · Direct I/O · `fsync()` 호출 · filesystem mount option 을 고르기 전에 적용한다. 확인 순서는 무엇이 빨라졌는지가 아니라 어느 경계가 사라졌는지다 — §148 의 네 단계(`write()` 완료 · writeback 완료 · fsync/flush 완료 · 전원 장애에도 안전한 상태) 중 어디까지 보장되는지를 먼저 적고, §156 이 그린 chain(Guest 가 요구한 durability → Guest Filesystem → Guest Block Layer → virtio → QEMU/backend → Host Storage → Device)에서 그 의미가 끊기는 자리가 있는지를 본다. DB workload 에서는 §170 처럼 애플리케이션이 어떤 durability protocol 을 쓰는지도 함께 적는다.", "exceptions": "durability 를 실제로 포기해도 되는 데이터가 있다 — 다시 만들 수 있는 캐시나 파생 파일이 그렇고, 그때는 빨라진 것이 정당한 선택이다. 이 규칙이 요구하는 것은 포기하지 말라는 것이 아니라 포기한 사실을 적으라는 것이다. 반대로 `cache=none` 이나 Direct I/O 를 골랐다는 사실만으로 durability 가 확보되지도 않는다 — Host Page Cache 우회는 즉시 durable media 반영이 아니고(§149 · §154), device 쪽 volatile write cache 가 그 뒤에 또 있다(§157). §151 이 실제 ordering/durability semantics 는 더 복잡하다고 밝혔으므로 이 규칙으로 특정 설정이 안전하다고 결론내지 않는다. 이 저장소에는 durability 를 실제로 재 본 실험이 없다 — 규칙은 SSOT 가 서술한 것이고 이 Host 에서 확인된 것이 아니다.", "relations": [ "concept:write-completion-is-not-durability", "concept:qemu-block-backend-forms", "question:qemu-disk-cache-mode", "question:guest-fsync-latency-vs-host-storage-latency", "reference:read-storage-before-blaming-cpu-for-latency" ], "publication": "게시됨", "file": "storage-virtualization/reference/reference-a-speedup-that-removed-durability-is-not-an-optimization.md", "status": "초안", "studioId": "decbab8d-9c98-45c6-b5b8-e6162e407299", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Guest 안에서 본 disk 로 backend 를 단정하지 않는다", "kind": "reference", "slug": "confirm-the-disk-backend-on-the-host", "readiness": "READY", "source": [ "final/document.md#145-host-block-device를-직접-backend로-사용-가능", "final/document.md#146-실제-연결-확인", "final/document.md#143-qcow2-virtual-size와-실제-host-사용량", "final/document.md#144-raw-image", "final/document.md#135-dev-vda-guest가-보는-가상-block-device", "final/document.md#142-qcow2-host에서는-파일-guest에서는-디스크", "final/document.md#169-storage-관측-명령어" ], "classification": "§145 가 규칙 문장을 그대로 적었다 — 「Guest 에 `/dev/vda` 가 있다」는 정보만으로 backend 구조를 알 수 없다. §135 도 Guest Linux 가 `/dev/vda` 를 하나의 block device 로 인식하지만 그것이 Host 의 실제 SSD 라는 뜻은 아니라고 적었고, §142 는 같은 대상을 Host 관점(파일 하나)과 Guest 관점(디스크)에서 보면 둘 다 맞다고 놓았다. §146 이 그 확정 절차를 댄다 — Guest 에서 `lsblk`, Host 에서 `virsh domblklist ` 로 Target 과 Source 를 잇는다. 이 규칙이 없으면 §143 의 virtual size 와 §144 의 성능 일반화가 둘 다 잘못된 전제 위에서 읽힌다. 제3부의 reference:bisect-the-packet-path-with-capture-points 가 network 경로를 확정하는 자리에 있는 것과 같은 위치이고, OQ-1 · OQ-2 · OQ-3 · OQ-5 넷이 모두 이 규칙 위에서 돌아가므로 네 글에 되풀이하지 않고 한 편으로 두고 가리킨다.", "scope": "VM 의 disk 성능·용량·durability 를 판단하기 전에, 그리고 Guest 안에서 잰 storage 수치를 해석하기 전에 적용한다. 확정할 것은 셋이다 — `/dev/vda` 가 붙은 Source 가 무엇인지(`virsh domblklist `), 그것이 qcow2 인지 RAW 인지 Host block device 인지(`qemu-img info `), 그리고 파일이라면 어느 Host filesystem 과 어느 block device 위에 있는지(§169 의 `lsblk`). 용량을 볼 때는 `qemu-img info` 의 virtual size 와 실제 allocation 을 구분해서 본다(§143).", "exceptions": "backend 가 Host block device 라면(§145) qcow2 쪽 확인 — virtual size 와 실제 할당량의 차이, mapping/metadata 처리 — 은 적용되지 않는다. 반대로 backend 를 확정했다고 성능이 예측되지도 않는다. §144 가 「RAW = 무조건 빠름 / qcow2 = 무조건 느림」으로 일반화하지 말라고 못박고 cache mode · storage backend · workload pattern · queue depth · snapshot chain · underlying filesystem · physical device 를 함께 들었으므로, 이 규칙은 무엇 위에서 재고 있는지를 확정할 뿐 결과를 대신 말하지 않는다. 이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없다.", "relations": [ "concept:qemu-block-backend-forms", "concept:guest-block-io-path-to-virtqueue", "question:vm-disk-backend-mapping", "question:disk-image-format-and-actual-host-usage", "question:host-block-device-under-the-disk-image", "reference:read-storage-before-blaming-cpu-for-latency" ], "publication": "게시됨", "file": "storage-virtualization/reference/reference-confirm-the-disk-backend-on-the-host.md", "status": "초안", "studioId": "274c5636-33f6-4c19-a54b-d2a96af31289", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "question": [ { "title": "이 호스트의 /dev/vda 는 어떤 backend 에 붙어 있는가", "kind": "question", "slug": "vm-disk-backend-mapping", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-1", "final/document.md#135-dev-vda-guest가-보는-가상-block-device", "final/document.md#145-host-block-device를-직접-backend로-사용-가능", "final/document.md#146-실제-연결-확인", "final/document.md#140-vm-boundary를-넘으면-qemu가-등장" ], "known": "§135 는 virtio-blk 를 쓰는 VM 에서 `/dev/vda` · `/dev/vdb` 같은 이름이 보이고 Guest Linux 가 그것을 하나의 block device 로 인식하지만 그것이 Host 의 실제 SSD 라는 뜻은 아니라고 적었다. §145 는 backend 가 반드시 파일일 필요도 없어서 `/dev/vda` 아래에 qcow2 file · RAW file · Host block device 셋이 올 수 있고, 그래서 「Guest 에 `/dev/vda` 가 있다」는 정보만으로 backend 구조를 알 수 없다고 못박았다. §140 은 VM 경계를 넘으면 QEMU 의 virtio-blk Device Model 과 Block Backend 가 그 연결을 맡는다고 적었고, §146 은 확인 방법으로 Guest 의 `lsblk` 와 Host 의 `virsh domblklist ` 를 들고 Target/Source 표 예시(`vda` → `/var/lib/libvirt/images/vm1.qcow2`)를 보였다. 이 Host 의 VM 이 어떤 Source 에 붙어 있는지는 SSOT 어디에도 없다.", "unknown": "이 Host 의 각 VM 에 어떤 disk 가 몇 개 붙어 있는지, 각 Target(`vda` 등)의 Source 가 무엇인지, 그리고 그 Source 가 파일인지 Host block device 인지.", "next-verification": "§175 OQ-1 이 적은 둘을 그대로 돌린다 — 각 Guest 에서 `lsblk` 로 보이는 block device 와 partition 을 적고, Host 에서 `virsh domblklist ` 로 Target 과 Source 를 적는다. VM 마다 한 행으로 남기고 출력은 그대로 증거로 둔다.", "decision-criterion": "VM 마다 Target ↔ Source 대응이 출력으로 확정되면 닫는다. Source 가 파일이면 question:disk-image-format-and-actual-host-usage 와 question:host-block-device-under-the-disk-image 로 이어지고, Host block device 면 §145 의 갈래가 이 환경이라고 적고 qcow2 쪽 후속 물음 둘은 이 Host 에 적용되지 않는다고 적는다. 어느 쪽이든 그 결과가 reference:confirm-the-disk-backend-on-the-host 가 요구하는 첫 항목을 채운다.", "relations": [ "concept:qemu-block-backend-forms", "concept:guest-block-io-path-to-virtqueue", "reference:confirm-the-disk-backend-on-the-host", "question:disk-image-format-and-actual-host-usage", "question:host-block-device-under-the-disk-image" ], "publication": "게시됨", "file": "storage-virtualization/question/question-vm-disk-backend-mapping.md", "status": "초안", "studioId": "1f76d54b-bb17-4174-8128-0c2d71d4256f", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 disk image 는 qcow2 인가 RAW 인가, 그리고 Guest 가 보는 크기와 Host 가 실제로 쓰는 크기는 얼마나 다른가", "kind": "question", "slug": "disk-image-format-and-actual-host-usage", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-3", "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-2", "final/document.md#143-qcow2-virtual-size와-실제-host-사용량", "final/document.md#144-raw-image", "final/document.md#142-qcow2-host에서는-파일-guest에서는-디스크" ], "known": "§142 는 같은 대상이 Host 에서는 파일 하나이고 Guest 에서는 `/dev/vda` 라는 디스크이며 둘 다 맞다고 놓았다. §143 은 qcow2 가 가상 disk size 와 실제 Host 할당량이 다를 수 있다고 적고, Guest 가 보는 공간 100 GB 에 Host 실제 할당 3GB 인 그림과 Guest 가 데이터를 기록하면서 Actual 이 1GB → 10GB → 40GB 로 늘 수 있다는 예를 들었다. 확인 명령으로 `qemu-img info vm1.qcow2` 를 들고 `virtual size` 와 실제 allocation 을 구분해서 봐야 한다고 했다. §144 는 RAW 가 qcow2 보다 구조가 단순하고 qcow2 는 Copy-on-Write · sparse allocation · snapshot 등에 유리하지만 metadata/mapping 처리가 있다고 적으면서, 「RAW = 무조건 빠름 / qcow2 = 무조건 느림」으로 일반화하면 안 된다고 못박았다. §175 OQ-2 는 `qemu-img info /path/to/disk-image` 를, OQ-3 은 `qemu-img info ` · `du -h ` · `ls -lh ` 셋을 들고 세 명령이 보여주는 의미가 서로 다를 수 있으므로 비교하라고 했다. 이 Host 의 image 형식도 크기도 SSOT 에 없다.", "unknown": "각 VM 의 disk image 가 qcow2 인지 RAW 인지, 그리고 `qemu-img info` 의 virtual size 와 `du -h` 가 보여주는 실제 점유량과 `ls -lh` 가 보여주는 파일 크기 셋이 이 Host 에서 얼마나 벌어져 있는지.", "next-verification": "question:vm-disk-backend-mapping 이 확정한 Source 경로마다 `qemu-img info ` 로 file format 과 virtual size 와 disk size 를 적고, 같은 경로에 `du -h ` 와 `ls -lh ` 를 돌려 세 값을 한 행에 나란히 남긴다 (§175 OQ-2 · OQ-3). VM 이 여럿이면 한 표로 만든다.", "decision-criterion": "image 마다 형식과 세 크기가 한 표로 적히면 닫는다. qcow2 이고 세 값이 벌어져 있으면 §143 이 말한 차이가 이 Host 에서 얼마인지를 확정한 것이고, 그 차이가 시간에 따라 어떻게 자라는지는 별도 측정으로 넘긴다. RAW 이면 §144 의 갈래가 이 환경이라고 적고 sparse 여부만 세 값의 차이로 판정한다. 어느 쪽이든 성능 결론은 여기서 내지 않는다 — §144 가 형식만으로 일반화하지 말라고 적었고, 성능은 question:vm1-storage-load-vs-vm2-latency 와 question:guest-fsync-latency-vs-host-storage-latency 가 잰다.", "relations": [ "concept:qemu-block-backend-forms", "reference:confirm-the-disk-backend-on-the-host", "question:vm-disk-backend-mapping", "question:host-block-device-under-the-disk-image" ], "publication": "게시됨", "file": "storage-virtualization/question/question-disk-image-format-and-actual-host-usage.md", "status": "초안", "studioId": "ae69e2e1-1a3b-4ae3-ae2a-572af07b95d7", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 VM 들의 QEMU disk cache mode 는 무엇인가", "kind": "question", "slug": "qemu-disk-cache-mode", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-4", "final/document.md#153-qemu-cache-mode", "final/document.md#154-cache=none", "final/document.md#155-cache=writeback", "final/document.md#156-writeback-=-위험-이라고-단정하면-안-되는-이유", "final/document.md#147-vm에서는-page-cache가-두-번-나타날-수-있다" ], "known": "§153 은 QEMU/libvirt disk 에서 대표적으로 볼 수 있는 설정으로 `cache=none` 과 `cache=writeback` 을 들고, 이름만 보고 「none = cache 자체가 없음 / writeback = 무조건 위험」으로 해석하면 부정확하며 핵심은 QEMU 가 Host Page Cache 와 write completion/flush semantics 를 어떤 방식으로 사용할 것인가라고 적었다. §154 는 `cache=none` 을 Host Page Cache 를 우회하는 방향의 I/O 구성으로 놓아 이중 caching 을 줄일 수 있지만 Host Page Cache 우회가 즉시 durable media 반영을 뜻하지는 않는다고 했다. §155 는 `cache=writeback` 이 Host Page Cache 를 사용할 수 있는 구성이고 일반 write 는 Host RAM 에서 빠르게 completion 될 수 있지만 그것이 Guest 의 `fsync()`/FLUSH 를 무시한다는 뜻은 아니라고 적었다. §147 은 Guest buffered I/O + Host file-backed disk + Host Page Cache 를 함께 쓰면 같은 데이터가 Guest RAM 과 Host RAM 양쪽에 cache 될 수 있다고 밝혔다. §175 OQ-4 는 `virsh dumpxml ` 로 disk driver 설정의 cache 관련 값을 확인하라고 했다. 이 Host 의 설정 값은 SSOT 에 없다.", "unknown": "각 VM 의 disk driver 에 cache 값이 명시되어 있는지, 명시되어 있다면 무엇인지, 명시가 없다면 그 자리에서 실제로 무엇이 적용되는지.", "next-verification": "VM 마다 `virsh dumpxml ` 을 돌려 disk 요소의 driver 설정을 그대로 적는다 (§175 OQ-4). 출력의 cache 관련 값과 함께 같은 disk 의 Source 와 형식(question:vm-disk-backend-mapping · question:disk-image-format-and-actual-host-usage 의 결과)을 한 행에 둔다.", "decision-criterion": "VM 마다 cache 값이 출력으로 확정되면 닫는다. `cache=none` 이면 §154 의 서술이, `cache=writeback` 이면 §155 의 서술이 이 Host 에 적용된다고 적고, 어느 쪽이든 §156 이 요구한 것 — Guest 의 flush/fsync semantics 가 전체 chain 에서 보존되는가 — 은 이 값만으로 답하지 않는다고 함께 적는다. 값이 명시되어 있지 않으면 그 사실을 적고 실제 적용 값을 확인할 방법을 다음 검증으로 남긴다. 이 값을 어떻게 둘 것인지는 후보 대장의 SSOT-153-157-cache-mode-choice-not-made 가 NEEDS_DECISION 으로 들고 있다.", "relations": [ "concept:write-completion-is-not-durability", "reference:a-speedup-that-removed-durability-is-not-an-optimization", "question:guest-fsync-latency-vs-host-storage-latency", "question:vm-disk-backend-mapping" ], "publication": "게시됨", "file": "storage-virtualization/question/question-qemu-disk-cache-mode.md", "status": "초안", "studioId": "480f86ac-86fb-4290-9bf5-584763aa1363", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "disk image 는 최종적으로 어느 Host block device 위에 있는가", "kind": "question", "slug": "host-block-device-under-the-disk-image", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-5", "final/document.md#158-host-block-layer", "final/document.md#159-여러-vm이-하나의-nvme를-공유하면", "final/document.md#141-qemu가-물리-ssd를-직접-제어하는-것은-아니다", "final/document.md#163-실제-i-o-scheduler-확인" ], "known": "§141 은 backend 가 qcow2 파일이면 QEMU 가 결국 Host Linux 에 파일 I/O 를 요청하고 그것이 Host Filesystem → Host Block Layer → NVMe Driver → Physical NVMe 로 내려가므로 Guest storage stack 아래에 Host storage stack 이 한 번 더 존재할 수 있다고 적었다. §158 은 그 경로를 QEMU → `vm1.qcow2` → Host ext4/XFS → Host Block Layer → `/dev/nvme0n1` 로 그리고, Host Block Layer 는 그 I/O 가 VM 에서 시작했는지 Host process 에서 시작했는지를 본질적으로 구분해서 처리하는 계층이 아니라고 밝혔다. §159 는 여러 VM 의 QEMU 와 Nginx 와 Host 기타 프로세스가 같은 Host Block Layer 를 지나 하나의 NVMe 로 간다고 그렸다. §175 OQ-5 는 `lsblk` 와 `findmnt` 로 확인하라고 했다. 이 Host 의 filesystem 배치도 물리 장치도 SSOT 에 없다.", "unknown": "disk image 가 놓인 디렉터리가 어느 mount point 에 속하는지, 그 mount 가 어느 partition 과 어느 block device 위에 있는지, 그리고 VM 들의 image 가 같은 device 를 공유하는지 서로 다른 device 에 있는지.", "next-verification": "question:vm-disk-backend-mapping 이 확정한 Source 경로마다 `findmnt` 로 그 경로가 속한 mount 와 source device 를 적고, `lsblk` 로 그 device 의 partition·상위 device 관계를 적는다 (§175 OQ-5). VM 이 여럿이면 image 경로 → mount → partition → device 한 행씩으로 남긴다.", "decision-criterion": "image 마다 최종 block device 이름이 확정되면 닫는다. VM 들이 같은 device 를 공유하면 §159 가 그린 상황이 이 환경이라고 적고 question:vm1-storage-load-vs-vm2-latency 가 그것을 실제로 재는 물음이 된다. 서로 다른 device 면 그 사실을 적고 그 질문의 전제가 이 환경에 없다고 함께 적는다. 여기서 확정한 device 이름이 question:host-io-scheduler 의 `` 자리를 채운다.", "relations": [ "concept:host-block-stack-under-the-vm", "concept:qemu-block-backend-forms", "question:vm-disk-backend-mapping", "question:host-io-scheduler", "question:vm1-storage-load-vs-vm2-latency", "reference:confirm-the-disk-backend-on-the-host" ], "publication": "게시됨", "file": "storage-virtualization/question/question-host-block-device-under-the-disk-image.md", "status": "초안", "studioId": "eead2379-94fe-463a-9e5e-06a01bf2105d", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "이 호스트의 I/O Scheduler 는 무엇인가", "kind": "question", "slug": "host-io-scheduler", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-6", "final/document.md#161-i-o-scheduler", "final/document.md#162-none", "final/document.md#163-실제-i-o-scheduler-확인", "final/document.md#160-blk-mq-multi-queue-block-layer" ], "known": "§161 은 여러 I/O request 가 있다고 해서 항상 들어온 순서 그대로 device 에 전달되는 것은 아니고 I/O Scheduler 가 dispatch 정책을 갖는다고 적으며 대표적으로 볼 수 있는 것으로 `none` · `mq-deadline` · `bfq` 를 들었다. §162 는 `none` 이 복잡한 scheduling 정책을 최소화해 비교적 직접 device 쪽으로 dispatch 하는 방향이고 NVMe 처럼 device 자체가 강한 병렬성과 queueing 기능을 가진 경우 적합할 수 있지만, `none` 이 block layer 가 아무 일도 하지 않는다는 뜻은 아니라고 적었다. §160 은 `blk-mq` 가 CPU 마다 queue 를 두어 여러 CPU 가 병렬로 block I/O 를 처리하는 구조를 그렸다. §163 은 확인 명령으로 `cat /sys/block/nvme0n1/queue/scheduler` 를 들고 예시 출력 `[none] mq-deadline` 에서 대괄호 안이 현재 선택된 scheduler 라고 했으며, SATA/SCSI device 라면 `cat /sys/block/sda/queue/scheduler` 처럼 확인한다고 적었다. 이 Host 의 값은 SSOT 에 없다.", "unknown": "이 Host 에서 VM disk image 를 담고 있는 block device 의 현재 scheduler 가 무엇이고 선택 가능한 목록이 무엇인지, 그리고 장치가 여럿이면 장치마다 값이 다른지.", "next-verification": "question:host-block-device-under-the-disk-image 가 확정한 device 이름을 넣어 `cat /sys/block//queue/scheduler` 를 돌리고 출력을 그대로 적는다 (§175 OQ-6). 대괄호가 붙은 값이 현재 선택된 것이다. VM image 가 놓인 장치가 여럿이면 장치마다 적는다.", "decision-criterion": "device 마다 현재 scheduler 와 선택지가 출력으로 적히면 닫는다. `none` 이면 §162 의 서술이 이 Host 에 적용된다고 적고, `mq-deadline` 이나 `bfq` 면 dispatch 정책이 개입한다는 사실을 question:vm1-storage-load-vs-vm2-latency 의 해석 조건으로 넘긴다. scheduler 를 바꿀지 말지는 이 질문이 정하지 않는다 — 바꾼 전후를 비교한 측정이 나온 뒤 Decision 으로 넘긴다.", "relations": [ "concept:host-block-stack-under-the-vm", "question:host-block-device-under-the-disk-image", "question:vm1-storage-load-vs-vm2-latency", "reference:read-storage-before-blaming-cpu-for-latency" ], "publication": "게시됨", "file": "storage-virtualization/question/question-host-io-scheduler.md", "status": "초안", "studioId": "77aa0188-5c2b-4f47-bda7-7c66b084968d", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "VM1 의 storage 부하가 VM2 의 지연을 실제로 밀어 올리는가", "kind": "question", "slug": "vm1-storage-load-vs-vm2-latency", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-7", "final/document.md#167-storage-contention", "final/document.md#159-여러-vm이-하나의-nvme를-공유하면", "final/document.md#168-cpu가-정상이어도-storage-때문에-느릴-수-있다" ], "known": "§159 는 여러 VM 의 QEMU 와 Host 프로세스가 같은 Host Block Layer queue 로 들어와 device 로 dispatch 된다고 그렸다. §167 은 여러 VM 이 동일한 Physical NVMe 를 사용하면 storage resource 경쟁이 발생할 수 있고 VM1 에서 대량 I/O 가 발생하면 VM2 의 storage latency 가 증가할 수 있다고 적으면서, CPU Contention 이 Host logical CPU 실행 시간 경쟁이고 Storage Contention 은 IOPS/bandwidth/queue/device 처리시간 경쟁이라 둘은 다른 자원 경쟁이라고 못박았다. §168 은 storage completion 을 기다리는 동안 CPU usage 가 높지 않을 수 있어 CPU 30% 인데 request latency 2초 가 가능하다고 적었다. §175 OQ-7 은 VM1 에서 별도의 테스트 파일/디스크로 controlled I/O load 를 발생시키고 VM2 의 application latency 와 Host storage 지표를 동시에 보라고 했다. 이 Host 에서 그렇게 재 본 결과는 없다.", "unknown": "VM1 에 controlled I/O load 를 걸었을 때 VM2 의 application latency 가 baseline 대비 실제로 달라지는지, 달라진다면 같은 구간의 Host storage 지표가 같은 방향으로 움직이는지, 그리고 그 변화가 CPU 쪽 지표와는 무관한지.", "next-verification": "먼저 question:host-block-device-under-the-disk-image 로 두 VM 이 같은 device 를 쓰는지 확정한다. 그 다음 baseline 구간에서 VM2 의 application latency 와 Host `iostat -xz 1` 과 CPU 를 같은 시각에 기록하고, VM1 에서 별도의 테스트 파일/디스크로 controlled I/O load 를 발생시킨 뒤 같은 셋을 다시 기록하고, 부하를 걷은 회복 구간을 세 번째로 찍는다 (§175 OQ-7). 어느 VM 이 I/O 를 내는지는 §169 의 `iotop` 으로 함께 남긴다.", "decision-criterion": "세 구간 표에서 부하 구간에만 VM2 latency 와 Host storage 지표가 함께 오르면 §167 이 그린 경쟁이 이 환경에서 이어진다는 것을 확인한 것이고 그 시계열이 Case 가 된다. VM1 부하 중에도 VM2 latency 가 baseline 과 다르지 않으면 이 구성과 이 부하 수준에서는 경쟁이 관찰되지 않는다고 적고 닫는다. 장치를 분리할지 · scheduler 를 바꿀지 · I/O 를 제한할지는 그 Case 가 나온 뒤 Decision 으로 넘긴다.", "relations": [ "concept:host-block-stack-under-the-vm", "reference:read-storage-before-blaming-cpu-for-latency", "question:host-block-device-under-the-disk-image", "question:host-io-scheduler", "question:guest-fsync-latency-vs-host-storage-latency", "question:vcpu-contention-under-two-vm-load" ], "publication": "게시됨", "file": "storage-virtualization/question/question-vm1-storage-load-vs-vm2-latency.md", "status": "초안", "studioId": "ed64d4ff-aa01-48cc-ae68-6a683b025cde", "assets": [], "assetFiles": [], "evidenceFiles": [] }, { "title": "Guest 의 fsync() 지연과 Host storage 지연은 같이 오르는가", "kind": "question", "slug": "guest-fsync-latency-vs-host-storage-latency", "readiness": "OPEN", "source": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-8", "final/document.md#150-fsync-가-필요한-이유", "final/document.md#169-storage-관측-명령어", "final/document.md#170-postgresql-예시-wal과-durability", "final/document.md#171-성능과-durability의-trade-off", "final/document.md#148-write-완료와-영속화는-다르다" ], "known": "§150 은 `fsync(fd);` 가 변경 내용을 필요한 영속성 경계까지 반영하도록 요청하는 것이고 VM 에서는 그 의미가 Guest Filesystem → Guest Block Layer → virtio-blk → QEMU/Backend → Host Storage Stack → Physical Storage 전체 stack 으로 전달되어야 한다고 적었다. §148 은 `write()` 완료와 writeback 완료와 fsync/flush 완료와 전원 장애에도 안전한 durability 가 서로 다르다고 못박았다. §170 은 PostgreSQL 이 WAL 등의 durability protocol 을 쓰며 필요한 시점에 storage synchronization 을 수행하고, VM storage layer 가 flush/fsync semantics 를 제대로 보존하지 않으면 PostgreSQL 의 durability assumption 과 실제 storage behavior 가 어긋날 수 있다고 적었다. §171 은 특히 DB workload 에서 `fsync()` latency 가 transaction latency 와 연결될 수 있다고 했다. §169 는 Host 관측으로 `iostat -xz 1` 과 `iotop` 을 들었다. §175 OQ-8 은 Guest application/DB latency 와 Host `iostat` 를 시간축으로 함께 관찰하라고 했다. 이 Host 에서 잰 값은 없다.", "unknown": "이 Host 에서 Guest 의 `fsync()` 나 DB transaction latency 가 커지는 구간과 Host 쪽 storage latency 가 커지는 구간이 시간축에서 겹치는지, 겹친다면 두 값이 같은 크기로 움직이는지 Guest 쪽이 더 크게 벌어지는지.", "next-verification": "Guest 에서 application/DB latency 를 기록하면서 같은 시각에 Host 에서 `iostat -xz 1` 을 돌려 두 계열을 같은 타임스탬프로 남긴다 (§175 OQ-8). 부하가 없는 구간과 있는 구간을 모두 찍고, 어느 프로세스가 I/O 를 내는지는 §169 의 `iotop` 으로 함께 적는다. 이때의 cache mode 는 question:qemu-disk-cache-mode 의 결과를 조건으로 함께 기록한다.", "decision-criterion": "두 계열이 같은 구간에서 함께 오르면 §150 이 말한 전달 경로가 이 환경에서 이어진다는 것을 확인한 것이고 그 시계열이 Case 가 된다. Guest `fsync()` latency 는 오르는데 Host storage latency 가 따라 오르지 않으면 그 차이가 어느 계층에서 생기는지 — Guest 쪽 대기인지 QEMU/backend 쪽인지 — 를 다음 물음으로 남기고 닫는다. 어느 쪽이든 성능을 위해 durability 를 줄이는 방향은 reference:a-speedup-that-removed-durability-is-not-an-optimization 을 지나야 한다.", "relations": [ "concept:write-completion-is-not-durability", "concept:guest-block-io-path-to-virtqueue", "reference:a-speedup-that-removed-durability-is-not-an-optimization", "reference:read-storage-before-blaming-cpu-for-latency", "question:qemu-disk-cache-mode", "question:vm1-storage-load-vs-vm2-latency", "question:host-major-fault-vs-storage-latency" ], "publication": "게시됨", "file": "storage-virtualization/question/question-guest-fsync-latency-vs-host-storage-latency.md", "status": "초안", "studioId": "be3c2c58-1ed4-4eae-876a-3114faa61c94", "assets": [], "assetFiles": [], "evidenceFiles": [] } ], "decision": [] } } }, "candidates": [ { "id": "SSOT-02-19-execution-path-as-one-concept", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#2-전체-구조", "final/document.md#19-이-ssot에서-파생될-concept" ], "summary": "virsh · libvirt · QEMU · /dev/kvm · KVM Core · kvm_intel · VMX 를 거쳐 물리 CPU 에 닿는 실행 경로가 한 줄기로 이어진다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§19 가 이 경로를 하나의 CONCEPT 로 관리하라고 적었고, 경로 중간을 잘라 내면 인과가 끊겨 독립성 검사를 통과한다. 이 프로젝트에서 유일하게 독립 기록이 되는 후보다" }, { "id": "SSOT-03-component-roles", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#3-각-구성요소의-역할" ], "summary": "구성요소 일곱의 역할 — virsh 는 CLI 이고 VM 을 실행하는 것은 QEMU 프로세스다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "경로 위 정거장들의 설명이다. 따로 떼면 무엇으로 가는 길목인지 말할 수 없어 어느 것도 혼자 서지 않는다" }, { "id": "SSOT-04-vcpu-thread-mapping", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#4-vcpu와-vcpu-thread" ], "summary": "Guest 의 vCPU 하나에 Host 의 QEMU vCPU thread 하나가 대응한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "이 대응이 없으면 뒤의 스케줄링·contention·steal time 절이 무엇에 대한 이야기인지 성립하지 않는다. 개념의 한 절이다" }, { "id": "SSOT-05-host-scheduler-owns-vcpu-thread", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#5-host-linux-scheduler와-실제-cpu" ], "summary": "vCPU thread 도 다른 Host thread 와 같이 Linux Scheduler 가 실행할 logical CPU 를 정한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "같은 경로의 다음 칸이다. 독립 기록으로 빼면 앞뒤 절을 다시 설명해야 한다" }, { "id": "SSOT-06-kvm-run-and-vm-entry", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#6-kvm_run과-guest-실행" ], "summary": "vCPU thread 가 KVM_RUN 을 부르면 VM Entry 로 Guest 코드가 실제 CPU 에서 실행된다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "경로가 커널로 넘어가는 지점이다. VM Exit 절과 짝이라 떼면 왕복이 반쪽만 남는다" }, { "id": "SSOT-07-vm-exit-is-not-shutdown", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#7-vm-entry와-vm-exit" ], "summary": "VM Exit 은 VM 종료가 아니라 Guest 실행에서 Hypervisor 로 제어권이 넘어가는 전환이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "오해를 바로잡는 정의 한 절이다. 정의 하나로 독립 기록을 만들면 §8·§9·§24.9 가 갈 곳을 잃는다" }, { "id": "SSOT-08-what-causes-vm-exit", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#8-무엇이-실제로-vm-exit을-발생시키는가" ], "summary": "VM Exit 은 root 권한이 아니라 VMCS 의 VM-Execution Control 설정과 동작 종류가 정한다 — HLT · IN/OUT · CPUID · CR · MSR · Exception · External Interrupt", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "일곱 원인이 같은 질문에 같은 결론으로 답한다 — 무엇이 Exit 하는지는 VMX control 이 정한다. 개념 안의 표나 하위 절이지 일곱 편이 아니다" }, { "id": "SSOT-09-exit-handled-in-kvm-or-qemu", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#9-vm-exit-이후-처리" ], "summary": "Exit Reason 에 따라 KVM 안에서 끝나기도 하고 KVM_RUN 이 반환되어 QEMU 까지 올라가기도 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§8 과 한 왕복을 이루는 절이다. §24.9 의 「Exit 처리 위치가 KVM 인지 QEMU 인지 본다」도 여기에 기댄다" }, { "id": "SSOT-10-idle-guest-releases-cpu", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#10-guest가-idle이면-물리-cpu는-어떻게-되는가" ], "summary": "Guest 가 idle 이면 vCPU thread 가 block/sleep 되고 Host 는 그 CPU 시간을 다른 workload 에 쓴다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§8.1 의 HLT exiting 이 그대로 이어지는 결론이다. 원인 절과 결과 절을 다른 기록으로 나눌 이유가 없다" }, { "id": "SSOT-11-four-vcpu-is-not-four-cpus", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#11-vm의-4-vcpu는-정확히-무엇을-의미하는가" ], "summary": "4 vCPU 는 실행 컨텍스트 4개이지 물리 CPU 4개의 영구 예약이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§4·§5 에서 이미 나온 사실을 한 문장으로 못박은 자리다. 없애고 개념의 한 절로 넣어도 이해가 달라지지 않는다" }, { "id": "SSOT-12-overcommit-and-contention", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#12-cpu-contention과-overcommit" ], "summary": "vCPU 총합이 logical CPU 를 넘으면 vCPU thread 끼리 Host CPU 시간을 두고 경쟁한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§24.2·§24.3 이 같은 내용을 문제 목록 형태로 다시 적는다. 한 기록 안에서 한 번 설명하고 표로 잇는 편이 맞다" }, { "id": "SSOT-13-steal-time-is-a-clue", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#13-steal-time" ], "summary": "steal time 은 Host contention·overcommit 을 의심할 단서이지 단독으로 원인을 확정하는 지표가 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "지표 하나의 읽는 법이다. §24.4 와 §25 의 표 행이 같은 것을 말하므로 개념 안에서 한 번 설명한다" }, { "id": "SSOT-14-observation-commands", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#14-실제-linux에서-확인할-수-있는-것" ], "summary": "이 계층을 눈으로 확인하는 Linux 명령 아홉 — /proc/cpuinfo · lsmod · /dev/kvm · virsh list · ps -T · psr · steal time · perf kvm", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "Reference 가 되려면 적용 조건과 예외를 댈 수 있어야 하는데 이 저장소에는 이 명령들을 실제로 돌린 출력이 아직 없다. 지금은 개념의 「어디를 보면 이 경로가 보이는가」 절이다" }, { "id": "SSOT-15-layered-diagnosis-view", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#15-cpu-가상화-관점에서-장애를-보는-방법" ], "summary": "VM 안이 느릴 때 Guest · Host/QEMU · KVM · Hardware 로 계층을 나눠 본다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "이 관점으로 원인을 실제로 가른 사건이 이 저장소에 아직 하나도 없다. 근거 Case 가 없는 규칙은 Case 결론을 선언문으로 바꾼 것도 못 되므로 개념의 한 절로 둔다" }, { "id": "SSOT-16-kvm-layer-under-the-keycloak-experiment", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#16-현재-keycloak-k3s-실험과의-관계" ], "summary": "Keycloak 멀티 노드 실험 구조 아래에 KVM 계층이 하나 더 있고, 그래서 원인을 분리해야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§19 가 「Keycloak/K3s 실험 결과와 Host 자원 문제를 구분하는 기준」을 CONCEPT 범위에 넣었다. 이 개념이 왜 필요한지를 말하는 절이라 개념 안에 있어야 한다" }, { "id": "SSOT-18-bare-metal-vs-vm-cpu-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#18-bare-metal-k3s와-vm-기반-k3s의-차이" ], "summary": "bare-metal K3s 는 Host scheduler 직행이고 VM 기반 K3s 는 vCPU · QEMU thread · KVM/VMX 계층이 더 붙는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "같은 경로를 계층 유무로 견준 것이다. 경로를 설명한 글 안에서만 대비가 성립한다" }, { "id": "SSOT-24-cpu-failure-modes", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제" ], "summary": "Guest saturation · overcommit · contention · steal time · scheduling latency · vCPU 과다 할당 · 잘못된 pinning · 과도한 VM Exit · Host saturation — 구조적으로 가능한 문제와 각각의 확인 지표", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§28 이 CONCEPT 에서 확정할 범위를 「어떤 문제가 발생할 수 있는가 · 어떤 지표로 의심하나 · 어느 계층인가」로 그었고 이 절이 정확히 그것이다. 아홉 모드가 같은 물음에 같은 결론으로 답하므로 개념 안의 하위 절이지 아홉 편이 아니다" }, { "id": "SSOT-24-8-cgroup-throttling-boundary", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제" ], "summary": "K3s cgroup CPU limit 으로 인한 throttling 은 KVM 문제가 아니지만 같은 application latency 로 보여 진단 경계에 포함한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "이 개념이 다루는 경계의 바깥을 짚는 절이라 개념이 스스로 안고 있어야 한다. 따로 빼면 「CPU 가상화 문제가 아닌 것」만 담은 기록이 된다" }, { "id": "SSOT-24-11-numa-locality", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#24-cpu-가상화-계층에서-발생할-수-있는-문제" ], "summary": "NUMA node 사이의 remote memory access 가 성능에 영향을 줄 수 있다", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "문서가 스스로 「상세한 memory placement 와 NUMA tuning 은 메모리 가상화 CONCEPT 에서 다룬다」고 범위를 넘겼다. 이 프로젝트가 메모리 가상화를 담는 SSOT 를 가지면 그때 다시 판정한다. 지금 CPU 개념에 넣으면 그 글에서 이어 쓸 수 없는 문단이 하나 남는다" }, { "id": "SSOT-25-layer-diagnosis-table", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#25-cpu-문제를-계층별로-구분하는-진단표" ], "summary": "문제 11개를 주된 계층 · 대표 현상 · 우선 확인할 것으로 늘어놓은 진단표", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "표 자체가 §24 를 한 화면으로 접은 것이다. 문서도 「원인을 확정하는 것이 아니라 조사 범위를 줄이는 것」이라고 적었다. 개념 본문의 표로 들어간다" }, { "id": "SSOT-26-layers-to-separate-when-reading-the-experiment", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#26-현재-keycloak-실험에서-cpu-문제를-오판하지-않기-위한-기준" ], "summary": "Application/Auth · Storage · K3s · Guest · Virtualization · Host 여섯 경계를 분리해서 읽는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§15 의 계층 분리를 Keycloak 실험에 맞춰 다시 그린 것이다. 개념이 설명한 경로 위에 실험 요소를 얹은 그림이라 같은 글에 있어야 읽힌다" }, { "id": "SSOT-28-what-the-concept-confirms", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#28-concept-->-open-question-->-case-적용-기준" ], "summary": "CONCEPT 은 구조적 가능성과 지표와 계층까지만 확정하고, 현재 서버에서 실제로 발생하는지는 확정하지 않는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "이 개념이 무엇을 사실로 말하고 무엇을 말하지 않는지의 경계다. 그 경계를 다른 기록에 두면 이 글을 읽는 사람이 어디까지 믿어야 하는지 모른다" }, { "id": "SSOT-17-26-22-separate-concurrency-and-load-tests", "kindCandidate": "DECISION", "sourceRefs": [ "final/document.md#17-동시성-테스트와-부하-테스트를-분리해야-한다", "final/document.md#26-현재-keycloak-실험에서-cpu-문제를-오판하지-않기-위한-기준", "final/document.md#22-현재-단계의-핵심-claim" ], "summary": "refresh 경쟁은 CPU 여유 상태에서 concurrency 실험으로 먼저 보고, 자원 포화는 별도의 load/stress 실험으로 본다", "disposition": "NEEDS_DECISION", "dispositionReview": "CONFIRMED", "target": null, "reason": "문서는 「분리해서 수행하는 것이 원인 분석에 유리하다」까지다. 프로젝트가 실제로 그렇게 하기로 정한 기록도, 감수한 비용(실험이 두 벌이 되고 두 결과를 잇는 해석이 따로 필요하다)도 적혀 있지 않다. 권고를 Decision 으로 올리면 「기술이 존재한다」를 근거로 바꾸는 것과 같은 실수가 된다. 실험 계획이 정해지면 다시 판정한다" }, { "id": "SSOT-22-claims-1-11", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#22-현재-단계의-핵심-claim" ], "summary": "Claim 1~11 — virsh 의 역할부터 idle vCPU 의 CPU 반환까지, 메커니즘 서술을 한 문장씩으로 줄인 것", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:kvm-vcpu-to-physical-cpu", "reason": "§3~§11 의 서술을 선언문으로 바꾼 것이다. 선언문만 모은 기록은 근거를 가리키지 못한다. 개념 본문이 같은 것을 근거와 함께 이미 담는다" }, { "id": "SSOT-22-claims-12-13", "kindCandidate": "CASE", "sourceRefs": [ "final/document.md#22-현재-단계의-핵심-claim" ], "summary": "Claim 12·13 — contention/overcommit 이 Guest 성능에 영향을 주며, VM 기반 실험 환경의 CPU contention 이 Keycloak 실험 결과를 왜곡할 수 있다", "disposition": "NEEDS_EVIDENCE", "dispositionReview": "CONFIRMED", "target": null, "reason": "다른 Claim 과 달리 이 둘은 「이 환경에서 실제로 그러한가」를 말한다. 이 테스트 Host 에서 잰 값이 없어 개념 본문에서도 가능성으로만 쓰고, 측정하면 Case 후보로 다시 판정한다" }, { "id": "SSOT-20-oq-1-vcpu-contention-under-two-vm-load", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-1. 현재 테스트 Host 에서 VM 두 대에 부하를 주면 vCPU contention 이 실제로 발생하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vcpu-contention-under-two-vm-load", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 종료 기준이 없다던 앞의 판정은 §20 이 적은 확인 대상 다섯을 종료 기준으로 옮겨 적어 해소했다. OQ-7 과 한 글감으로 합칠지는 값을 잰 뒤에야 아는 것이라 지금은 각각 올리고 relations 로 잇는다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-20-oq-2-virtualization-layer-saturation-during-refresh", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-2. Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과에 영향을 줄 정도로 포화되는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:virtualization-layer-saturation-during-refresh", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 아는 것과 모르는 것은 실험 전에도 갈린다 — §16·§26 이 서술한 계층 구조와 §20 이 적은 관찰 대상 다섯이 known 이고, 이 Host 에서의 값이 unknown 이다. 종료 기준은 §20 이 스스로 밝힌 목적(refresh 경쟁과 Host resource contention 의 분리)에서 끌어 적었다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-20-oq-3-idle-vcpu-thread-appearance", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-3. Guest 가 idle 일 때 vCPU thread 는 실제 테스트 환경에서 어떻게 보이는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:idle-vcpu-thread-appearance", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 결과가 §10 의 서술과 같으면 개념으로 흡수되고 다르면 Case 가 된다던 앞의 판정은 버리는 이유가 아니라 그대로 종료 기준이다 — decision-criterion 에 그 갈림을 적었다. 확인 명령도 §20 이 이미 두 줄로 적어 두었다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-20-oq-4-vm-exit-distribution-by-workload", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-4. 실제 workload 에서 어떤 VM Exit 이 주로 발생하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm-exit-distribution-by-workload", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 도구가 이 환경에서 되는지부터 확인해야 한다는 앞의 판정은 버리는 이유가 아니라 next-verification 의 첫 단계다 — 안 되는 것으로 확인되는 것도 이 질문을 닫는 결과다. OQ-11 과는 종료 기준이 달라 합치지 않고 relations 로 잇는다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-20-oq-5-vcpu-thread-migration-without-pinning", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-5. pinning 을 하지 않은 상태에서 vCPU thread 는 Host logical CPU 사이를 실제로 이동하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vcpu-thread-migration-without-pinning", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 관찰 하나짜리 물음이지만 답에 따라 OQ-10 의 pinning 실험을 할 이유가 있는지가 갈린다 — 설계가 답에 달려 있다는 조건을 만족한다. 독립 Question 으로 남을지 OQ-10 의 관측이 될지를 재 봐야 안다던 앞의 판정은 decision-criterion 에 그대로 옮겼다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-20-oq-6-is-production-on-a-hypervisor", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#20-이-concept에서-파생되는-open-question" ], "summary": "OQ-6. 현재 운영 서버는 CPU 가상화 계층의 영향을 받는 구조인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:is-production-on-a-hypervisor", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 확인 전에는 아는 것과 모르는 것을 나눠 적을 수 없다던 앞의 판정을 뒤집었다 — §18 과 §20 이 그린 두 경로가 known 이고 운영 서버가 어느 쪽인지가 unknown 이다. 답에 따라 §25 의 어느 행을 운영 진단에 쓰는지가 갈리므로 설계가 답에 달린 Question 의 조건을 만족한다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-7-steal-time-increase-under-two-cpu-bound-vms", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-7. VM 두 대를 동시에 CPU-bound 로 만들면 Guest steal time 은 실제로 얼마나 증가하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:steal-time-increase-under-two-cpu-bound-vms", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. OQ-1 의 수치판이라 재고 나면 둘이 한 Question 인지 갈린다던 앞의 판정은 그대로다. 다만 그 판정은 값을 잰 뒤의 일이고, 지금 둘을 미리 한 글감으로 합치면 어느 쪽 종료 기준으로 닫혔는지가 남지 않는다. 각각 올리고 relations 로 잇는다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-8-throughput-vs-vcpu-count", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-8. vCPU 수를 늘릴수록 현재 테스트 Host 에서 Keycloak 처리량도 계속 증가하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:throughput-vs-vcpu-count", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 어디서 꺾이면 「과다 할당」으로 부를지 기준이 없다던 앞의 판정은 §24.6 에서 기준을 끌어 적어 해소했다 — 처리량이 더 오르지 않는 지점이 있으면 그것이 이 workload 의 상한이고, 세 구성이 같은 방향으로 오르면 상한에 닿지 않은 것이다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-9-throttling-vs-contention", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-9. K3s CPU limit 으로 생긴 throttling 과 Host vCPU contention 을 지표로 구분할 수 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:throttling-vs-contention", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 재현하기 전에는 구분이 되는지조차 모른다던 앞의 판정이 곧 이 종류의 전제다. Case 는 재현한 뒤에 쓰고, 그 전까지 무엇을 어떻게 재현해 무엇을 견줄지를 적어 두는 자리가 Question 이다. 견줄 지표는 §25 가 이미 두 행으로 갈라 적어 두었다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-10-pinning-before-and-after", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-10. CPU pinning 전후로 Keycloak latency 와 vCPU scheduling 변동이 달라지는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:pinning-before-and-after", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 측정 전에 Decision 으로 올리면 감수한 비용 없이 선택을 만들게 된다던 앞의 판정은 그대로 유효하다 — 그래서 Decision 이 아니라 Question 으로 올린다. 설계가 답에 달려 있고 다음 검증과 종료 기준이 있는 것이 이 종류의 조건이고 셋 다 갖췄다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-11-exit-distribution-for-keycloak-workload", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-11. Keycloak workload 의 VM Exit 분포는 idle · CPU-bound · I/O-bound 와 어떻게 다른가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:exit-distribution-for-keycloak-workload", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. OQ-4 와 같은 측정에 묶이는 것과 한 글감인 것은 다르다. OQ-4 는 workload 다섯의 분포를 견주는 물음이고 이것은 Keycloak 구간의 분포가 latency 와 같이 움직이는지를 묻는다 — 종료 기준이 달라 각각 올리고 relations 로 잇는다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-27-oq-12-host-numa-topology", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#27-문제-영역에서-파생되는-추가-open-question" ], "summary": "OQ-12. 현재 Host 의 NUMA topology 가 VM 성능을 고려해야 할 정도의 구조인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-numa-topology", "reason": "NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정했다. Question 은 답이 아직 없는 판단을 적는 종류라 이 Host 에서 잰 값이 하나도 없다는 것이 글감으로 올리지 못할 이유가 아니다 — 무엇을 알고 무엇을 모르는지, 무엇을 재면 닫히는지를 적어 두는 자리가 Question 이고, 값이 나오면 그때 Case 가 된다. 문서가 종료 기준을 스스로 적은 유일한 OQ 라 Question 으로 올리기에 조건이 가장 갖춰진 후보다. Host 를 확인하기 전에는 답이 없다는 것이 앞의 NEEDS_EVIDENCE 사유였는데, 답이 없는 상태를 그대로 적는 것이 Question 이다. 사용자가 §20·§27 의 OQ 열둘을 OQ 하나에 글감 하나로 올리기로 정했다." }, { "id": "SSOT-21-record-system-flow", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#21-open-question에서-case가-만들어지는-흐름" ], "summary": "SSOT → CONCEPT → OPEN QUESTION → CASE 로 이어지고 CASE 에서 다시 OPEN QUESTION 이 나온다는 기록 체계", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "CPU 가상화가 아니라 이 저장소가 기록을 잇는 방식을 설명한 절이다. 분석에는 남아야 하고 공개 기록으로는 읽을 사람이 없다" }, { "id": "SSOT-23-next-verification-plan", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#23-다음-단계" ], "summary": "VMX 확인부터 VM Exit 관찰까지 테스트 Host 에서 돌릴 검증 순서와, 그 뒤 네트워크 가상화로 넘어간다는 계획", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "다음에 무엇을 잴지의 진행 계획이다. 계획은 실행되면 Case 가 되고 그 전까지는 분석에 남는다" }, { "id": "SSOT-29-gva-gpa-hpa-two-translations", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#29-이-문서에서-먼저-고정할-전체-구조", "final/document.md#79-전체-memory-virtualization-실행-경로", "final/document.md#87-최종-기준-그림" ], "summary": "GVA → GPA → HPA. Guest 가 물리 주소라고 믿는 GPA 와 실제 Host RAM 의 HPA 사이에 변환이 한 번 더 있다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "§29 가 이 부에서 먼저 고정할 구조로 놓고 §87 이 같은 그림을 최종 기준으로 다시 그렸다. 이 부의 나머지 다섯 개념이 전부 이 경로 위의 자리라 이것을 빼면 어느 것도 혼자 서지 않는다" }, { "id": "SSOT-30-32-virtual-memory-basics", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#30-일반-linux의-virtual-memory부터-시작한다", "final/document.md#31-page와-physical-frame", "final/document.md#32-virtual-address-=-page-+-offset" ], "summary": "프로세스마다 독립된 virtual address space 가 있고, 매핑 단위는 4 KiB page 와 physical frame 이며, virtual address 는 page 와 offset 으로 갈린다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "KVM 고유 기능이 아니라 일반 Linux 의 주소 변환이다. 개념의 첫 절로 들어가면 되고 따로 읽을 이유가 없다" }, { "id": "SSOT-33-guest-page-table", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#33-guest-page-table" ], "summary": "Guest Kernel 이 프로세스마다 virtual page → guest physical frame 매핑을 관리하지만 매 접근마다 커널 코드가 table 을 뒤지는 것은 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "변환 경로의 한 단계다. 이 단계만 떼어 읽을 사람이 없다" }, { "id": "SSOT-34-mmu-performs-the-translation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#34-mmu-실제-주소-변환을-수행하는-cpu-하드웨어" ], "summary": "주소 변환을 실제로 수행하는 주체는 CPU 의 MMU 이고 Guest Kernel 은 table 을 구성·관리한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "「누가 만들고 누가 쓰는가」는 개념 본문의 한 절이다" }, { "id": "SSOT-35-tlb-caches-translations", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#35-tlb-주소-변환-결과의-cpu-cache" ], "summary": "TLB 는 최근 translation 결과를 CPU 가 캐시해 둔 것이라 hit 이면 page-table walk 를 건너뛴다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "변환 경로의 성능 특성이다. §43 의 nested walk 비용과 §51 의 TLB coverage 가 이것을 전제한다" }, { "id": "SSOT-35-tlb-miss-is-not-page-fault", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#35-tlb-주소-변환-결과의-cpu-cache" ], "summary": "TLB Miss 는 table 을 조회해 정상 매핑을 찾는 사건이고 Page Fault 는 현재 접근을 완료할 수 없는 사건이라 둘은 다르다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "「어느 계층의 사건인가」를 가르는 첫 구분이라 fault 계층 개념의 도입부에 들어간다. §82 의 CLAIM-MEM-07 이 같은 것을 한 문장으로 적었다" }, { "id": "SSOT-36-bare-metal-vs-vm-translation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#36-bare-metal과-vm의-차이" ], "summary": "bare-metal 은 page table 한 번으로 끝나지만 VM 에서는 Guest 가 얻은 physical address 가 Host physical address 가 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "EPT 가 왜 필요한지를 세우는 대조다. 개념 안에서 EPT 절 바로 앞에 온다" }, { "id": "SSOT-37-ept-second-stage-translation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#37-ept-extended-page-tables" ], "summary": "EPT 는 GPA → HPA 를 CPU 하드웨어가 수행하는 second-level address translation 이고 Guest Page Table 과 같은 table 이 아니다. AMD 에는 NPT 계열이 대응한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "주소 변환 경로의 두 번째 단계다. 이 개념의 핵심 절이지 독립 글이 아니다" }, { "id": "SSOT-38-ept-isolates-guest-physical-space", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#38-왜-ept가-필요한가" ], "summary": "VM 둘이 같은 GPA 를 써도 EPT 가 서로 다른 HPA 로 연결해 Guest physical address space 를 격리한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "EPT 절의 근거 예시다. 표 한 줄이나 예 하나로 들어간다" }, { "id": "SSOT-39-shadow-page-table-vs-ept", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#39-shadow-page-table과-ept의-의미" ], "summary": "하드웨어 second-level translation 이 없던 방식은 hypervisor 가 shadow mapping 을 유지해야 해 관리 비용이 컸고, EPT/NPT 는 그 두 단계를 하드웨어로 옮겼다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "EPT 가 무엇을 대신하는지를 설명하는 배경이다. 개념 안의 한 절이면 충분하다" }, { "id": "SSOT-40-qemu-backs-guest-ram-in-host-userspace", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#40-qemu는-guest-ram을-어떻게-준비하는가" ], "summary": "QEMU 는 Host userspace process 라 Guest RAM 도 자신의 Host Virtual Address Space 에 마련하고, RAM 하드웨어를 직접 제어하는 것이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "관리 경로의 시작이다. OQ-3 이 재려는 QEMU RSS 가 무엇인지도 이 절이 정한다" }, { "id": "SSOT-41-kvm-set-user-memory-region", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#41-kvm_set_user_memory_region", "final/document.md#80-전체-memory-virtualization-관리-경로" ], "summary": "QEMU 가 마련한 HVA 범위와 Guest GPA 범위의 대응을 `KVM_SET_USER_MEMORY_REGION` 으로 KVM 에 등록하고, 런타임 변환은 CPU 가 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "관리 경로(§80)와 실행 경로(§79)를 가르는 자리다. 개념이 그 둘을 같이 그린다" }, { "id": "SSOT-42-configured-memory-is-not-resident-memory", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#42-configured-memory와-실제-physical-ram-사용량은-같지-않을-수-있다" ], "summary": "configured memory · Guest 가 지금 쓰는 memory · Host 에서 지금 resident 한 physical memory 셋은 같지 않을 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "OQ-2 와 OQ-3 이 이 절을 재려고 만들어졌다. 개념이 셋의 구분을 세우고 두 Question 이 이 Host 의 값을 받는다" }, { "id": "SSOT-43-nested-page-table-walk-cost", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#43-guest-page-table-자체도-메모리에-있다" ], "summary": "Guest Page Table 자체도 Guest physical memory 에 있는 자료구조라 entry 를 읽는 데도 EPT 변환이 필요하고, 그래서 nested walk 에는 비용이 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "왜 TLB 가 중요한지를 잇는 절이다. 개념 안에서 TLB 절과 붙어 있어야 읽힌다" }, { "id": "SSOT-44-normal-memory-access-does-not-vm-exit", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#44-정상-memory-access는-매번-vm-exit하지-않는다", "final/document.md#79-전체-memory-virtualization-실행-경로" ], "summary": "정상 매핑이 있으면 CPU MMU 가 직접 변환하므로 Guest RAM 접근마다 VM Exit 이나 QEMU userspace 왕복이 생기지 않는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "CPU 부에서 VM Exit 을 읽은 사람이 가장 쉽게 틀리는 자리라 §44 가 「잘못된 이해」를 먼저 그렸다. 개념의 결론 절이다" }, { "id": "SSOT-45-guest-page-fault", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#45-guest-page-fault", "final/document.md#48-guest-page-fault와-ept-violation-비교", "final/document.md#49-host-page-fault도-별도로-존재한다" ], "summary": "Guest Page Fault 는 GVA → GPA 단계에서, EPT Violation 은 GPA → HPA 단계에서, Host Page Fault 는 QEMU backing 의 Host virtual memory 에서 각각 따로 일어난다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "§48 의 비교표와 §49 의 세 갈래는 이 부에서 가장 여러 번 다시 쓰이는 구분이다. §86 의 진단 분류가 그 위에 서 있고 OQ-13·OQ-14 가 각각 Guest 쪽과 Host 쪽을 재라고 말한다. 정상 경로를 그리는 글과 갈라 둔 이유는 물음이 다르기 때문이다 — 그쪽은 정상일 때 무엇이 일어나는가를, 이쪽은 완료되지 않을 때 어느 계층이 받는가를 말한다" }, { "id": "SSOT-46-page-fault-causes", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#46-page-fault의-대표적인-원인" ], "summary": "demand paging · swap-in · permission fault · copy-on-write · invalid access 다섯이 Page Fault 의 대표 원인이고, Page Fault 는 Segmentation Fault 와 다르다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "Guest Page Fault 절 아래의 하위 절이다. 다섯을 각각 글로 만들면 표 한 줄이 될 것이 다섯 편이 된다" }, { "id": "SSOT-47-ept-violation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#47-ept-violation" ], "summary": "Guest 쪽 변환은 성공했는데 그 GPA 의 second-stage 접근을 현재 EPT 조건으로 완료할 수 없으면 EPT Violation 이고 VM Exit 을 거쳐 KVM 이 받는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "같은 개념의 두 번째 계층이다. §48 의 비교표가 이 절과 §45 를 나란히 놓는다" }, { "id": "SSOT-48-guest-page-fault-vs-ept-violation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#48-guest-page-fault와-ept-violation-비교" ], "summary": "문제 위치 · 관련 table · 기본 관점 · 주요 처리 계층 · 앱 오류 여부 다섯 항목으로 Guest Page Fault 와 EPT Violation 을 갈라 놓은 비교표", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "개념 본문의 표다. 표 하나를 기록 하나로 만들지 않는다" }, { "id": "SSOT-49-host-page-fault", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#49-host-page-fault도-별도로-존재한다" ], "summary": "QEMU 도 Host 의 일반 userspace process 라 demand allocation·reclaim·swap 때문에 Host 쪽에서도 page fault 가 난다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "세 계층 가운데 셋째다. OQ-14 가 이 계층의 major fault 를 재려고 만들어졌다" }, { "id": "SSOT-50-51-huge-page-and-tlb-coverage", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#50-huge-page가-필요한-이유", "final/document.md#51-huge-page와-tlb-coverage", "final/document.md#52-vm에서-huge-page를-볼-때-주의할-점" ], "summary": "page 가 커지면 같은 범위를 더 적은 매핑으로 덮어 TLB pressure 와 page-table walk 부담이 줄 수 있고, VM 에서는 Guest 단계·Host backing·EPT 매핑 셋을 따로 봐야 한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "OQ-4 와 OQ-5 가 이 개념을 필요로 한다. THP 정책 하나를 읽어도 그것이 Guest 쪽인지 Host backing 쪽인지 모르면 값이 뜻을 갖지 않는다. §51 은 예시 숫자를 특정 CPU 의 실제 TLB 용량으로 읽지 말라는 단서까지 달았다" }, { "id": "SSOT-52-huge-page-has-two-stages-in-a-vm", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#52-vm에서-huge-page를-볼-때-주의할-점" ], "summary": "VM 에는 변환 단계가 둘이라 「Huge Page 를 쓴다」는 말만으로는 Guest page table 쪽인지 Host backing 쪽인지 EPT 매핑 쪽인지 정해지지 않는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "개념의 핵심 절이다. OQ-5 가 이 구분을 그대로 확인 항목으로 쓴다" }, { "id": "SSOT-53-thp", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#53-thp-transparent-huge-pages" ], "summary": "THP 는 조건이 맞는 영역에 Linux 가 Huge Page 를 투명하게 활용하려는 기능이고 정책은 `/sys/kernel/mm/transparent_hugepage/enabled` 에서 읽는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "개념 안의 한 절이다. 정책 값 자체는 OQ-4 가 이 Host 에서 읽는다" }, { "id": "SSOT-54-thp-tradeoff", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#54-thp의-trade-off" ], "summary": "Huge Page 에는 큰 contiguous 영역이 필요해 fragmentation 이 심하면 compaction 이 끼어들 수 있고, 그래서 THP 가 항상 성능을 높인다고 단정할 수 없다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "THP 절의 뒷면이다. 이익만 적고 비용을 빼면 개념이 반쪽이 된다" }, { "id": "SSOT-55-hugetlb", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#55-hugetlb" ], "summary": "HugeTLB 는 관리자가 미리 확보한 명시적 Huge Page pool 을 쓰는 방식이라 예측 가능성이 오르는 대신 일반 allocation 의 유연성이 준다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "THP 와 짝을 이루는 절이다. §56 의 비교표가 둘을 나란히 놓는다" }, { "id": "SSOT-56-thp-vs-hugetlb", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#56-thp와-hugetlb-비교" ], "summary": "관리 주체 · 애플리케이션 개입 · 유연성 · 사전 예약 · compaction 영향 · VM RAM backing 여섯 항목의 THP↔HugeTLB 비교표와 `AnonHugePages` ≠ `HugePages_Total`", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "개념 본문의 표다. OQ-4 가 그 표의 항목을 이 Host 에서 읽는다" }, { "id": "SSOT-57-memory-overcommit", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#57-memory-overcommit", "final/document.md#58-cpu-overcommit과-memory-overcommit의-차이", "final/document.md#59-host-memory-pressure와-reclaim" ], "summary": "configured 총량이 Host RAM 을 넘는 구성이 성립하는 이유는 configured capacity 와 현재 working set 이 같지 않기 때문이고, RAM 이 모자라면 CPU 처럼 시간을 나누는 것이 아니라 reclaim·swap·ballooning·OOM 이 개입한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "OQ-6·OQ-7·OQ-14 셋이 이 개념 위에서만 읽힌다. CPU overcommit 과 성격이 다르다는 §58 이 이 부 전체에서 가장 오해되기 쉬운 자리라 앞에서 한 번 세워야 한다" }, { "id": "SSOT-58-cpu-overcommit-vs-memory-overcommit", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#58-cpu-overcommit과-memory-overcommit의-차이" ], "summary": "CPU 가 모자라면 scheduler 가 실행 시간을 나누지만 RAM 이 모자라면 「지금 존재해야 하는 page 를 어디에 둘 것인가」가 남는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "개념의 도입 대조다. 한 절이면 되고 독립 글로 읽을 것이 아니다" }, { "id": "SSOT-59-host-reclaim", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#59-host-memory-pressure와-reclaim" ], "summary": "Host 수요가 available physical memory 에 가까워지면 reclaim 이 돌고, file-backed clean page 는 버렸다 다시 읽으면 되지만 anonymous page 는 swap 같은 backing 이 필요하다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "압박 경로의 첫 단계다. 개념 본문의 한 절이다" }, { "id": "SSOT-60-host-swap-turns-guest-ram-access-into-io", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#60-host-swap이-vm에-미치는-영향" ], "summary": "Guest 는 RAM 에 접근했다고 생각하는데 Host backing page 가 swap-out 되어 있으면 그 접근이 Host page fault 와 swap-in I/O 대기로 바뀐다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "이 개념이 존재하는 이유가 되는 절이다. OQ-7 이 이것을 실험으로 확인한다" }, { "id": "SSOT-61-guest-swap-is-not-host-swap", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#61-guest-swap과-host-swap" ], "summary": "Guest Swap 은 Guest kernel 이 `/dev/vda` 로 내려보내는 것이고 Host Swap 은 QEMU backing 이 Host kernel 에 눌리는 것이라 서로 다른 계층이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "계층 구분이라 개념 안에 있어야 한다. OQ-6 이 둘을 같은 시각에 재라고 요구하는 근거다" }, { "id": "SSOT-62-memory-pressure-reaches-storage", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#62-memory-pressure와-storage-contention의-연결", "final/document.md#81-cpu-network-storage-memory-연결" ], "summary": "Guest swap I/O · Host swap I/O · DB I/O · filesystem writeback 이 한 물리 장치로 몰릴 수 있어 memory pressure 가 storage contention 을 거쳐 application latency 까지 온다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "메모리를 CPU 사용률로 판단하지 않게 하는 절이다. OQ-14 가 이 연결을 같은 시간축에서 확인한다" }, { "id": "SSOT-63-swap-used-alone-is-not-a-verdict", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#63-swap-used만-보고-장애를-판단하면-안-된다" ], "summary": "Swap Used 값 하나로 memory pressure 를 단정할 수 없고 swap-in/out 지속 여부 · reclaim pressure · major fault · storage latency 를 Guest 와 Host 에서 함께 봐야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:memory-symptom-needs-layer-separation", "reason": "「지표 하나로 계층을 단정하지 않는다」는 규칙의 대표 사례라 그 Reference 의 한 행으로 들어간다. 규칙을 두 벌 쓰면 어느 쪽을 따르는지가 갈린다" }, { "id": "SSOT-71-oom-mechanism", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#71-oom" ], "summary": "reclaim 으로도 필요한 memory 를 확보하지 못하면 OOM 이 되고 OOM Killer 가 프로세스를 골라 종료할 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "압박 경로의 마지막 단계다. 개념 안에서 §72 와 붙어 있어야 한다" }, { "id": "SSOT-72-guest-oom-vs-host-oom", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#72-guest-oom과-host-oom" ], "summary": "Guest OOM 은 Guest 프로세스를 죽이지만 Host OOM 에서 QEMU 가 victim 이 되면 VM 전체가 멈추고, cgroup limit 이 있으면 Host RAM 이 남아도 그 경계에서 OOM 이 난다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "영향 범위가 다르다는 것이 이 개념의 결론이다. OOM 의 발생 계층을 확인하라는 §86 의 갈래도 여기서 나온다" }, { "id": "SSOT-64-65-virtio-balloon", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#64-ballooning이-필요한-이유", "final/document.md#65-virtio-balloon-구조" ], "summary": "Host 는 Guest 안에서 어느 memory 가 중요한지 모르므로 무작정 swap-out 하는 대신 Guest kernel 과 협력해 회수한다. virtio-balloon 은 그 협력용 가상 장치이고 RAM 자체를 제공하는 장치가 아니다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "OQ-8 과 OQ-9 가 이 개념을 필요로 한다. balloon 은 Guest 안의 driver 와 QEMU 쪽 device 가 virtqueue 로 맞물린 별도 메커니즘이라 압박 경로 안의 한 절로 넣으면 inflate/deflate 의 방향조차 설명할 자리가 없다" }, { "id": "SSOT-66-balloon-inflate", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#66-balloon-inflate" ], "summary": "Host 가 balloon 을 inflate 하면 Guest 안의 balloon 이 커져 Guest usable memory 가 줄고 Host 가 회수할 수 있는 backing 이 는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "개념의 핵심 동작이다. §68 의 deflate 와 한 절 안에서 방향이 갈린다" }, { "id": "SSOT-67-what-balloon-page-return-means", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#67-balloon-page-반환의-의미" ], "summary": "balloon driver 는 Guest page 를 확보하고 그 사실을 Host 에 알리는 것이며, Host 쪽 실제 release 동작은 QEMU/KVM 버전과 backing 종류·설정에 따라 달라질 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "단정하지 않은 자리를 그대로 옮겨야 하는 절이라 개념 본문에 둔다" }, { "id": "SSOT-68-balloon-deflate", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#68-balloon-deflate" ], "summary": "balloon target 을 줄이면 balloon page 가 반환되어 Guest usable memory 가 는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "inflate 와 짝인 한 문장이다. 따로 읽을 것이 없다" }, { "id": "SSOT-69-over-inflation-pressures-the-guest", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#69-ballooning을-과도하게-하면-guest가-압박을-받는다" ], "summary": "working set 이 큰데 과도하게 inflate 하면 Guest reclaim → page cache 회수 → Guest swap → 심하면 Guest OOM 으로 이어져, Host RAM 을 확보하려던 조치가 Guest latency 를 올릴 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "개념의 감수 비용 절이다. OQ-9 가 이 경로를 실험 대상으로 삼는다" }, { "id": "SSOT-70-ballooning-is-not-memory-hotplug", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#70-ballooning과-memory-hotplug" ], "summary": "ballooning 은 기존 capacity 안에서 usable memory 를 회수·반환하는 것이고 hotplug 는 capacity 자체를 더하는 것이라 다르다. `virtio-mem` 같은 다른 방식도 있어 동적 memory 관리를 ballooning 하나로 일반화하면 안 된다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "개념의 경계 절이다. 잘못 뭉치는 것을 막는 문장이라 본문에 있어야 한다" }, { "id": "SSOT-73-74-numa-local-and-remote", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#73-numa", "final/document.md#74-local-memory와-remote-memory", "final/document.md#75-vcpu와-numa의-연결" ], "summary": "NUMA 에서는 어느 CPU 가 어느 RAM 을 읽느냐로 비용이 갈리고, Guest vCPU 는 Host 의 QEMU vCPU thread 라 그 thread 가 도는 node 와 backing page 가 있는 node 가 어긋나면 remote access 가 된다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "OQ-11 과 OQ-12 가 이 개념 위에 선다. CPU 부의 question:host-numa-topology 가 「상세한 memory placement 와 NUMA tuning 은 메모리 가상화 CONCEPT 에서 다룬다」고 범위를 넘긴 자리가 여기다" }, { "id": "SSOT-75-vcpu-placement-decides-which-node-reads-ram", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#75-vcpu와-numa의-연결" ], "summary": "Guest 안에서는 단순한 memory load 인데 실제 하드웨어에서는 vCPU thread 가 도는 node 에 따라 interconnect 를 건널 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "개념의 핵심 연결이다. CPU 부의 vCPU thread 서술과 메모리 배치가 여기서 만난다" }, { "id": "SSOT-76-pinning-alone-does-not-finish-numa", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#76-vcpu-pinning만으로는-numa-최적화가-끝나지-않는다" ], "summary": "vCPU 를 Node 0 에 pinning 해도 backing page 가 Node 1 에 몰려 있으면 remote access 가 늘 수 있어 vCPU placement 와 memory placement 를 함께 봐야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "개념의 결론 절이다. OQ-11 이 이 어긋남을 이 Host 에서 확인한다" }, { "id": "SSOT-77-guest-numa", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#77-guest-numa" ], "summary": "큰 VM 에서는 Guest 에게 NUMA topology 자체를 노출하고 Guest node 와 Host node 가 합리적으로 대응되도록 구성할 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "개념 안의 한 절이다. 이 프로젝트의 VM 이 그런 크기인지는 SSOT 에 적혀 있지 않다" }, { "id": "SSOT-78-numa-observation-commands", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#78-numa는-실제-장비-topology부터-확인한다" ], "summary": "`lscpu` · `numactl --hardware` · `numastat -p ` · `virsh vcpupin` · `virsh vcpuinfo` — NUMA topology 와 배치를 읽는 명령", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "명령 목록만으로는 규칙이 되지 않는다. 개념 본문에서 무엇을 읽는 명령인지와 함께 놓아야 뜻이 있고, 실제 값은 OQ-11·OQ-12 가 받는다" }, { "id": "SSOT-78-measure-topology-before-optimizing", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#78-numa는-실제-장비-topology부터-확인한다" ], "summary": "Host 가 단일 NUMA node 면 cross-node 문제가 주요 이슈가 아닐 수 있으므로 topology 를 먼저 재고 NUMA 최적화 필요성을 판단한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:memory-symptom-needs-layer-separation", "reason": "「재기 전에 단정하지 않는다」는 같은 규칙의 NUMA 판이라 그 Reference 의 적용 범위 한 줄로 들어간다" }, { "id": "SSOT-79-memory-execution-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#79-전체-memory-virtualization-실행-경로" ], "summary": "TLB → Guest Page Table(#PF 가능) → GPA → VM Boundary → EPT(Violation 가능) → HPA → NUMA node 로 이어지는 실행 경로 한 장", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "개념이 그리는 경로 그대로다. 그림 한 장을 기록 하나로 만들지 않는다" }, { "id": "SSOT-80-memory-management-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#80-전체-memory-virtualization-관리-경로" ], "summary": "virsh → libvirt → QEMU(backing · balloon device · ioctl) → KVM(memory slot · EPT 매핑) → CPU 로 이어지는 관리 경로", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "실행 경로와 짝이라 같은 개념 안에서 나란히 놓아야 한다" }, { "id": "SSOT-81-memory-pressure-to-application-latency", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#81-cpu-network-storage-memory-연결" ], "summary": "memory pressure → reclaim/swap → storage I/O → contention → application latency 로 이어지는 사슬과, vCPU pinning + memory placement 가 함께 NUMA locality 를 정한다는 연결", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "압박 개념의 결론 사슬이다. §62 와 같은 것을 한 번 더 그린 자리라 그 개념 안에 함께 둔다" }, { "id": "SSOT-81-four-resource-map", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#81-cpu-network-storage-memory-연결" ], "summary": "CPU · Network · Storage · Memory 넷을 한 그림에 놓고 memory 가 그 전부를 받친다고 적은 지도", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "이 문서 네 부 전체의 지도이지 메모리만의 개념이 아니다. 제3부(네트워크)와 제4부(스토리지)가 같은 그림을 쓰므로 SSOT 에 두고 각 개념이 필요할 때 가리킨다" }, { "id": "SSOT-87-final-reference-picture", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#87-최종-기준-그림" ], "summary": "Guest Userspace → Guest Kernel(TLB · Page Table) → VM Boundary → KVM/CPU(EPT) → Host RAM(NUMA) 한 장과, 관리 경로와 자원 압박 경로를 따로 기억하라는 지시", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "§29 와 §79 가 그린 것을 최종 기준으로 다시 그린 것이다. 같은 경로를 세 번째 기록으로 만들지 않는다" }, { "id": "SSOT-82-claims-translation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-01~06 — 두 단계 변환 · Guest Page Table 의 관리 주체 · EPT 의 하드웨어 지원 · 정상 접근이 VM Exit 을 부르지 않는다는 것 · QEMU backing 과 region 등록 · configured ≠ resident", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "개념 본문이 이미 서술한 것을 한 문장씩으로 줄인 목록이다. 개념의 요약 표로 들어간다" }, { "id": "SSOT-82-claims-fault-layers", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-07~09 — TLB Miss ≠ Page Fault · Guest Page Fault 와 EPT Violation 의 발생 단계가 다르다 · Page Fault 자체는 프로그램 오류가 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:page-fault-layers-in-a-vm", "reason": "fault 계층 개념이 서술한 것의 요약이다. 그 글의 표로 들어간다" }, { "id": "SSOT-82-claims-huge-page", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-10~11 — Huge Page 가 TLB/page-table 효율을 개선할 가능성 · THP 와 HugeTLB 는 같은 방식이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:huge-pages-in-a-vm", "reason": "huge page 개념의 요약 두 줄이다" }, { "id": "SSOT-82-claims-pressure", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-12~14 와 17 — Memory Overcommit 의 성격 · Guest Swap 과 Host Swap 의 계층 · pressure 가 storage 와 latency 를 악화시킬 수 있다 · Guest OOM 과 Host OOM 의 영향 범위", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:memory-pressure-reclaim-swap-oom", "reason": "압박 개념의 요약이다. 개념 안의 표로 들어간다" }, { "id": "SSOT-82-claims-balloon", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-15~16 — virtio-balloon 은 협력용 장치이지 RAM 제공 장치가 아니다 · 과도한 inflate 는 Guest reclaim/swap/OOM 을 부를 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:virtio-balloon-memory-reclaim", "reason": "balloon 개념의 요약 두 줄이다" }, { "id": "SSOT-82-claims-numa", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#82-핵심-claim-registry" ], "summary": "CLAIM-MEM-18 — NUMA 시스템에서는 vCPU placement 와 memory placement 를 함께 봐야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:numa-locality-for-vcpu-and-memory", "reason": "NUMA 개념의 결론을 한 문장으로 줄인 것이다" }, { "id": "SSOT-83-oq-1-host-numa-topology-overlap", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-1" ], "summary": "OQ-1. Host 의 실제 NUMA topology 는 무엇인가 — node 수 · node 별 CPU · node 별 memory · node distance", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "question:host-numa-topology", "reason": "CPU 부의 question:host-numa-topology 가 같은 것을 이미 묻고 있고 그 unknown 이 「단일인지 다중인지」를 그대로 담고 있다. 같은 한 번의 측정으로 닫히는 물음을 두 편으로 만들지 않는다. 그 질문이 「SSOT 는 이 확인에 쓸 명령을 적지 않았다」고 남긴 자리에 §83 OQ-1 의 `lscpu` · `numactl --hardware` 와 node 별 memory · node distance 를 확인 항목으로 더한다" }, { "id": "SSOT-83-oq-2-vm-configured-vs-current-memory", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-2" ], "summary": "OQ-2. 각 VM 의 configured/current memory 는 얼마인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm-configured-vs-current-memory", "reason": "§42 가 세운 세 값의 차이를 이 Host 에서 재는 물음이다. 답에 따라 overcommit 상태인지가 정해지고 그 뒤 실험 설계가 갈린다" }, { "id": "SSOT-83-oq-3-qemu-resident-memory-distribution", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-3" ], "summary": "OQ-3. QEMU process 의 Host resident memory 는 어떻게 분포하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:qemu-resident-memory-distribution", "reason": "configured 와 RSS 의 차이, 그리고 backing 이 anonymous 인지 huge page 인지를 재는 물음이다. §40·§41 이 서술한 backing 구조가 이 Host 에서 어떤 값인지가 답이다" }, { "id": "SSOT-83-oq-4-host-thp-policy", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-4" ], "summary": "OQ-4. Host THP 정책은 무엇인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-thp-policy", "reason": "§53 이 정책은 kernel/distribution/Host 설정에 따라 다르니 실제 시스템에서 확인하라고 적었다. 값을 읽어야 닫힌다" }, { "id": "SSOT-83-oq-5-vm-ram-backed-by-hugetlb", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-5" ], "summary": "OQ-5. VM RAM 이 HugeTLB 로 명시적으로 backing 되어 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm-ram-backed-by-hugetlb", "reason": "§52 가 가른 세 자리 가운데 Host backing 쪽을 이 Host 에서 확정하는 물음이다" }, { "id": "SSOT-83-oq-6-swap-activity-in-guest-and-host", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-6" ], "summary": "OQ-6. Guest 와 Host 에서 현재 swap 이 발생하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:swap-activity-in-guest-and-host", "reason": "§63 이 swap-used 값이 아니라 지금 오가는지를 보라고 적었다. Guest 와 Host 를 같은 시각에 재야 §61 의 계층 구분이 값으로 갈린다" }, { "id": "SSOT-83-oq-7-host-memory-pressure-vs-guest-latency", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-7" ], "summary": "OQ-7. Host memory pressure 가 Guest latency 에 영향을 주는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-memory-pressure-vs-guest-latency", "reason": "§60·§62 가 그린 경로가 이 Host 에서 실제로 이어지는지를 baseline → 압박 유도 → 재측정으로 확인하는 물음이다" }, { "id": "SSOT-83-oq-8-virtio-balloon-configured", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-8" ], "summary": "OQ-8. virtio-balloon 이 VM 에 구성되어 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:virtio-balloon-configured", "reason": "구성 여부가 정해지지 않으면 OQ-9 의 실험 자체가 성립하지 않는다. §83 이 driver 이름과 표시 방식이 환경마다 다를 수 있다는 단서를 달았다" }, { "id": "SSOT-83-oq-9-balloon-target-vs-guest-available-memory", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-9" ], "summary": "OQ-9. Balloon target 변화가 Guest available memory 에 어떻게 반영되는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:balloon-target-vs-guest-available-memory", "reason": "§66·§68 의 방향과 §69 의 과도 inflate 위험을 이 Host 에서 값으로 확인하는 물음이다" }, { "id": "SSOT-83-oq-10-host-numa-topology-overlap", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-10" ], "summary": "OQ-10. VM vCPU 는 어느 Host CPU 에 배치되어 있는가", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "question:host-numa-topology", "reason": "§83 OQ-10 이 스스로 「CPU 가상화 SSOT 의 pinning/overcommit 관측과 연결한다」고 적었고, CPU 부의 question:host-numa-topology 가 이미 두 VM 의 vCPU 배치를 unknown 에 담고 있다. 같은 `virsh vcpuinfo`/`vcpupin` 한 번으로 닫히는 것을 따로 세우지 않는다" }, { "id": "SSOT-83-oq-11-qemu-memory-numa-placement", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-11" ], "summary": "OQ-11. QEMU memory 는 어느 NUMA node 에 배치되어 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:qemu-memory-numa-placement", "reason": "CPU 부가 넘긴 자리다. vCPU 배치는 그쪽이 재고 memory 배치와 둘의 어긋남은 여기서 잰다 — `numastat -p ` 는 CPU 부 어디에도 없다" }, { "id": "SSOT-83-oq-12-numa-remote-access-vs-workload-latency", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-12" ], "summary": "OQ-12. NUMA remote access 가 실제 workload latency 에 의미 있는 영향을 주는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:numa-remote-access-vs-workload-latency", "reason": "topology 를 아는 것과 latency 가 달라지는 것은 다른 물음이다. §83 이 단순 topology 만 보고 성능 문제라고 단정하지 말라고 적었다" }, { "id": "SSOT-83-oq-13-guest-page-fault-vs-workload", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-13" ], "summary": "OQ-13. Guest Page Fault 가 workload 변화와 함께 증가하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:guest-page-fault-vs-workload", "reason": "§46 의 다섯 원인 가운데 무엇이 늘었는지를 갈라야 답이 된다. Page Fault 증가만으로 오류라고 판단하지 말라는 것이 §83 의 단서다" }, { "id": "SSOT-83-oq-14-host-major-fault-vs-storage-latency", "kindCandidate": "QUESTION", "sourceRefs": [ "final/document.md#83-실제-환경에서-확인할-open-question-oq-14" ], "summary": "OQ-14. Host Page Fault/major fault 와 storage latency 가 상관되는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-major-fault-vs-storage-latency", "reason": "§49 의 Host 계층과 §62 의 storage 연결을 같은 시간축에서 확인하는 물음이다" }, { "id": "SSOT-84-recommended-experiment-order", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#84-권장-실험-순서" ], "summary": "Host physical memory/NUMA 확인부터 NUMA locality 실험까지 열두 단계로 적은 권장 검증 순서", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "분석 진행 계획이다. 어느 Question 을 먼저 여느냐의 순서일 뿐 독립 기록으로 읽을 사람이 없다. CPU 부의 §23 도 같은 처분이었다" }, { "id": "SSOT-85-conditions-to-record-with-every-experiment", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#85-실험-시-반드시-같이-기록할-것" ], "summary": "Host(CPU model · core/thread · RAM · NUMA topology · swap 설정 · kernel version · THP policy · physical storage) · VM(vCPU · configured/current RAM · memory backing · balloon device · guest swap · guest kernel) · Workload(application · heap 설정 · request concurrency · DB workload · 측정 시간) 세 묶음을 실험마다 함께 남긴다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:record-the-conditions-with-every-memory-experiment", "reason": "열두 Question 전부에 같이 걸리는 규칙이라 각 글에 되풀이할 것이 아니라 한 편으로 두고 가리킨다. 원 사건 이름을 지워도 규칙이 남는다 — 메모리 실험 결과를 다른 환경에 재사용하려면 어떤 조건을 같이 남겨야 하는가에 대한 답이다" }, { "id": "SSOT-86-classify-the-symptom-before-concluding", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#86-문제를-진단할-때의-분류" ], "summary": "메모리 latency 나 OOM 을 보고 한 번에 「메모리 부족」이라고 결론내지 않고 Guest Virtual Memory · Virtualization Translation · Host Memory · Dynamic Memory · NUMA 다섯 갈래로 먼저 가른다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:memory-symptom-needs-layer-separation", "reason": "다음 프로젝트에도 그대로 적용되는 판독 규칙이다. 다섯 갈래는 이 부의 여섯 개념을 가로지르는 라우팅이라 어느 개념 안에 넣어도 나머지 넷을 가리키지 못한다" }, { "id": "SSOT-88-do-not-judge-memory-from-one-guest-free", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#88-결론" ], "summary": "Guest 하나의 `free -h` 만 보고 메모리 상태를 판단하지 않고 Guest → QEMU → Host → NUMA → Storage 영향을 같은 시간축에서 관측한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:memory-symptom-needs-layer-separation", "reason": "§86 과 같은 규칙의 결론 문장이다. 그 Reference 의 적용 조건 한 줄로 들어간다" }, { "id": "SSOT-88-concept-is-fixed-oq-becomes-case", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#88-결론" ], "summary": "이 문서의 개념 부분은 SSOT 로 고정하고 실제 서버에 종속되는 설정과 동작은 OQ-1~OQ-14 를 실험해 CASE 로 전환한다는 경계 선언", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-memory-address-translation", "reason": "이 부가 무엇까지 확정하고 무엇을 확정하지 않는지를 그은 문장이라 개념의 missing-verification 이 그대로 받는다. CPU 부의 §28 도 같은 처분이었다" }, { "id": "SSOT-89-part-scope-and-experiment-goals", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#89-문서-목적" ], "summary": "제3부가 다루는 범위 — Guest 애플리케이션의 요청이 Guest Kernel · virtio-net · virtqueue · vhost-net · TAP · Bridge/Routing · Physical NIC 를 거쳐 나가고 돌아오는 구조 — 와 그 위에서 검증하려는 Keycloak 멀티 노드 · 동일 Refresh Token 동시 갱신 · 세션 상태 공유 · Host Nginx → VM → K3s → Keycloak 요청 경로 일곱 항목", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "이 부가 무엇을 다루고 무엇을 다루지 않는지의 선언이다. 따로 떼면 아무 것도 설명하지 않는 목차가 되고, 개념의 classification 과 missing-verification 이 그대로 받는다. CPU 부의 §28 과 메모리 부의 §88 도 같은 처분이었다" }, { "id": "SSOT-90-virsh-libvirt-virtio-are-different-things", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#90-virsh-libvirt-virtio-구분" ], "summary": "virsh 는 libvirt 에 관리 명령을 넣는 CLI 이고 packet datapath 에 직접 참여하지 않는다 · libvirt 는 VM lifecycle 과 NIC/network configuration 을 관리한다 · virtio 는 명령어도 단일 프로그램도 단일 커널 모듈도 아니라 Guest 와 Host/Hypervisor 사이의 표준 인터페이스다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§121 이 virsh · libvirt · virtio 셋을 CONCEPT 의 포함 범위 첫 줄에 넣었다. 셋의 구분은 경로의 어느 자리가 관리이고 어느 자리가 datapath 인지를 가르는 도입부라 개념 밖에 두면 §105 의 control/data path 절이 시작할 자리를 잃는다" }, { "id": "SSOT-91-virtio-net-is-split-across-guest-and-host", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#91-virtio-net은-정확히-어디에-있는가" ], "summary": "virtio-net 은 한 자리에 있는 하나의 프로세스가 아니다. Guest 측에 TCP/IP Stack · virtio-net Frontend Driver · virtqueue 가 있고 Host 측에 QEMU virtio-net Device Model · vhost-net · TAP · Bridge/Routing/NAT · Physical NIC Driver 가 있다. virtio 는 특정 커널 계층이 아니라 frontend 와 backend 사이의 I/O 계약이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "개념이 서 있는 문장이다. 이 한 줄을 떼면 뒤의 §103~§109 가 「누가 무엇을 처리하는가」를 물을 수 없다. 독립 기록으로 만들면 경로의 정거장 배치도만 담은 글이 하나 남는다" }, { "id": "SSOT-92-frontend-and-backend", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#92-frontend와-backend" ], "summary": "Frontend 는 Guest Kernel 의 virtio-net driver, Backend 는 Guest 가 넘긴 packet buffer 를 Host 쪽에서 처리하는 구현이고 backend 는 QEMU userspace 이거나 vhost-net kernel backend 다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§91 이 그은 분할에 이름을 붙인 절이다. 두 절을 떼어 두 기록으로 만들면 어느 쪽도 혼자 읽히지 않는다" }, { "id": "SSOT-93-guest-sees-a-nic-not-qemu", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#93-guest-os는-왜-qemu가-아니라-virtio-net을-사용하는가" ], "summary": "Guest 는 「QEMU 를 호출한다」가 아니라 「내 NIC 를 쓴다」로 동작한다. QEMU 가 Virtual PCI Bus 에 virtio NIC 를 노출하면 Guest Linux 가 virtio device 를 발견해 driver 를 bind 하고 ens3/eth0 형태의 interface 가 생긴다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "물리 서버의 경로와 VM 의 경로를 나란히 놓아 frontend 가 왜 Guest 안에 있어야 하는지를 보이는 절이다. 개념의 도입 절로 들어간다" }, { "id": "SSOT-94-121-125-packet-path-as-one-concept", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#94-전체-네트워크-계층", "final/document.md#121-이-ssot에서-파생될-concept", "final/document.md#125-최종-기준-구조" ], "summary": "virtio-net + vhost-net + TAP + Linux Bridge 를 기준으로 한 수신·송신 양방향 전체 계층과, 그 요소들이 하나의 packet 실행 경로를 설명하므로 하나의 CONCEPT 로 관리한다는 §121 의 지시, 그리고 §125 가 다시 그린 Control/Setup 경로와 vhost-net·QEMU backend 두 Data Path", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§121 이 이 요소들을 하나의 CONCEPT 로 관리하라고 적었고 §125 가 같은 경로를 최종 기준 구조로 다시 그렸다. 경로 중간을 잘라 내면 packet 이 어디서 와서 어디로 가는지 말할 수 없어 독립성 검사를 통과한다. 제3부에서 유일하게 독립 개념이 되는 후보다" }, { "id": "SSOT-94-baseline-structure-is-one-of-many", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#94-전체-네트워크-계층" ], "summary": "이 문서가 기준으로 삼은 것은 가장 기본적인 virtio-net + vhost-net + TAP + Linux Bridge 구조이고, 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "개념이 무엇을 기준으로 쓴 글인지를 밝히는 문장이라 basis-version 이 받는다. 따로 떼면 「이 문서가 안 다루는 구성 목록」만 남는다" }, { "id": "SSOT-95-physical-nic-hardware-is-not-the-interface-object", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#95-physical-nic의-역할" ], "summary": "Physical NIC 는 링크와 서버를 잇는 하드웨어이고 Host Kernel 의 NIC driver 가 그것을 제어해 Linux 가 network interface 로 노출한다. Physical NIC hardware 와 Linux interface object 는 같지 않다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로의 마지막 정거장 설명이다. 하드웨어와 interface object 의 구분 한 줄만으로는 독립 기록이 되지 않는다" }, { "id": "SSOT-96-linux-bridge-is-an-l2-software-switch", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#96-linux-bridge의-역할" ], "summary": "Linux Bridge 는 Host Kernel 안의 L2 software switch 로 Ethernet frame 의 Destination MAC 을 보고 port 를 고른다. L2 forwarding · MAC learning · 여러 virtual/physical port 연결이 역할이고 `bridge link` · `bridge fdb show` · `ip link show type bridge` 로 본다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로 위 정거장 하나의 역할이다. §97·§98 과 나란히 놓여야 「이 셋 중 어느 구조인가」라는 물음이 성립하므로 셋을 흩으면 물음이 사라진다" }, { "id": "SSOT-97-routing-is-l3-not-l2", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#97-routing의-역할" ], "summary": "Routing 은 Bridge 와 달리 L3 이고 IP 기반이며 서로 다른 IP network 를 잇는다. destination IP 를 보고 interface 나 next-hop 을 고르고 `ip route` 로 본다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§96 과 짝을 이루는 대비 절이다. 개념 본문의 표 한 행이 될 것을 기록으로 만들지 않는다" }, { "id": "SSOT-98-tell-bridge-routing-and-nat-apart", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#98-nat의-역할" ], "summary": "NAT 은 packet 의 IP/Port 를 바꾸고 VM 이 private subnet 을 쓰면 Host 가 NAT gateway 처럼 동작할 수 있다. 따라서 VM network 를 분석할 때 Bridge 기반인가 · Routing 기반인가 · NAT 기반인가를 먼저 구분해야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "구분해야 한다는 요구 자체는 개념이 안고, 이 Host 가 셋 중 어느 것인지는 §122 OQ-1 이 받아 question 글감이 되었다. 규칙과 그 규칙이 낳은 물음을 같은 자리에 두 번 적지 않는다" }, { "id": "SSOT-99-tap-is-the-host-side-attach-point", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#99-tap의-역할" ], "summary": "TAP 은 물리 장치가 아니라 Host Linux Kernel 이 제공하는 가상 Ethernet interface(tap0 · vnet0)이고 VM 의 Ethernet frame 과 Host Linux networking 을 잇는 접점이다. `ip link` · `ip tuntap show` · `bridge link` · `virsh domiflist ` 로 본다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로가 Guest 를 떠나 Host 로 넘어오는 자리의 설명이다. 이 interface 가 이 Host 에서 무엇인지는 §122 OQ-2 가 따로 묻는다" }, { "id": "SSOT-100-virtqueue-is-a-descriptor-shared-queue", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#100-virtqueue의-역할" ], "summary": "virtqueue 는 NIC 도 Linux network interface 도 아니고 Guest 와 Host backend 가 I/O buffer 를 주고받는 descriptor 기반 shared queue 다. 네트워크에서는 TX(Guest → Host)와 RX(Host → Guest)를 쓰고, packet payload 를 매번 userspace API 호출로 넘기는 대신 Guest memory buffer 와 descriptor 를 공유·참조하도록 설계되어 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로의 한 정거장이자 §110·§112 가 말하는 최적화가 걸리는 자리다. 떼어 내면 무엇과 무엇 사이의 queue 인지 말할 수 없다" }, { "id": "SSOT-101-guest-tcp-ip-stack-is-real", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#101-guest-tcp-ip-stack의-역할" ], "summary": "Guest TCP/IP Stack 은 Guest Linux Kernel 의 실제 network stack 이다. Socket · TCP · UDP · IP · Routing · Neighbor/ARP · Firewall · Network Driver 가 Guest 안에 그대로 있고 VM 이라고 stack 이 가짜인 것이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로의 Guest 쪽 절반이다. 하위 절 넷(Socket · TCP · IP · Ethernet)은 일반 Linux network stack 설명이라 이 개념 밖에서 독립 기록이 될 자리가 없다" }, { "id": "SSOT-102-keycloak-only-sees-a-socket", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#102-packet이-keycloak까지-올라오는-과정" ], "summary": "Ethernet Frame → IP Packet → TCP Segment → Socket → HTTP → Keycloak 순으로 올라오고, Keycloak 은 virtqueue · vhost-net · TAP · Bridge · Physical NIC 를 직접 알 필요 없이 Guest Linux 가 준 TCP socket 위에서 HTTP 를 처리한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로의 끝이자 §120 이 「애플리케이션 증상과 network 계층을 갈라야 한다」고 말할 때 근거로 삼는 문장이다. 개념의 마지막 절로 들어가고 Reference 쪽에서는 source 로 가리킨다" }, { "id": "SSOT-103-qemu-device-model-has-two-roles", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#103-qemu-virtio-device-model의-역할" ], "summary": "QEMU 의 virtio Device Model 은 Host Userspace 의 QEMU process 안에 있고 역할이 둘이다 — 장치 생성/설정/관리(device 노출 · feature negotiation · virtqueue 설정 · backend 연결)와 실제 packet datapath 처리. datapath 는 QEMU backend 를 직접 쓰는 경우와 vhost-net 을 쓰는 경우로 갈린다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§104·§106·§108 이 되풀이해 교정하는 오해의 근원이 이 두 역할을 하나로 본 것이다. 네 절이 같은 결론(관리 주체와 packet 처리 주체는 다르다)에 닿으므로 개념 안의 한 절이지 네 편이 아니다" }, { "id": "SSOT-104-do-not-generalize-tap-vhost-qemu-virtqueue", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#104-왜-tap-→-vhost-net-→-qemu-→-virtqueue-라고-일반화하면-안-되는가" ], "summary": "`TAP → vhost-net → QEMU → virtqueue` 를 모든 환경의 일반적인 packet 경로로 그리면 안 된다. vhost-net 의 목적 하나가 datapath 에서 QEMU userspace 를 우회하는 것이라 fast path 는 `TAP → vhost-net → virtqueue → Guest` 로 이해한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§124 의 Claim 9 와 같은 문장이고 §103 이 나눈 두 역할의 따름정리다. 개념이 그리는 그림이 어떤 그림이 아닌지를 못박는 절이라 그 그림과 같은 글에 있어야 한다" }, { "id": "SSOT-105-control-path-vs-data-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#105-control-path와-data-path" ], "summary": "Control/Setup Path 는 virsh → libvirt → QEMU → virtio-net Device Model 로 이어져 feature negotiation · virtqueue setup · vhost-net setup 을 하고, Data Path 는 packet 이 반복해 흐르는 경로다. 여기서 control 은 Kubernetes Control Plane 이 아니라 일반적인 설정/제어 경로를 뜻한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "경로를 둘로 가르는 축이다. 축을 떼면 §90 의 virsh/libvirt 와 §94 의 packet 계층이 한 그림에 놓일 이유가 없어진다" }, { "id": "SSOT-106-device-owner-is-not-the-per-packet-processor", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#106-qemu가-userspace인데-packet이-qemu를-안-거칠-수-있는-이유" ], "summary": "장치의 생성/관리 주체라는 것과 모든 packet 의 runtime datapath 를 처리한다는 것은 다르다. QEMU 가 vCPU 를 만든다고 Guest 의 ADD·MOV·SUB 를 전부 QEMU 가 실행하지 않는 것처럼, QEMU 가 virtual NIC 를 만든다고 packet 을 하나씩 처리해야 하는 것은 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "CPU 가상화와의 비유로 §103 의 두 역할을 다시 설명한 절이다. 이 비유는 cpu-virtualization 의 개념을 relations 로 가리키는 다리가 되고, 따로 떼면 비유만 남는다" }, { "id": "SSOT-107-vhost-net-moves-the-hot-path-into-the-kernel", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#107-vhost-net-최적화" ], "summary": "QEMU userspace 가 packet 마다 I/O 를 처리하면 kernel ↔ userspace 전환 비용이 쌓이고 packet rate 가 높아질수록 transition · scheduling · copy · notification 비용이 커질 수 있다. vhost-net 은 hot path 를 kernel backend 로 옮겨 그 비용을 줄인다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "개념이 설명하는 두 datapath 가운데 하나의 존재 이유다. 이 Host 에서 그 차이가 실제로 보이는지는 §122 OQ-4 가 받는다" }, { "id": "SSOT-108-vhost-net-does-not-remove-qemu", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#108-vhost-net은-qemu를-제거하지-않는다" ], "summary": "vhost-net 을 써도 QEMU 는 VM lifecycle · virtual hardware model · virtio device 생성 · feature negotiation · queue configuration · backend 연결 · device reset · control/configuration 처리를 계속 맡는다. vhost-net 은 QEMU 제거가 아니라 반복적인 virtio packet datapath 의 상당 부분을 Host Kernel 로 offload 하는 것이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§124 의 Claim 16 과 같은 문장이고 §103 의 역할 A 가 남아 있음을 확인하는 절이다. §104 와 같은 오해를 반대편에서 막는 것이라 같은 글에 있어야 짝이 맞는다" }, { "id": "SSOT-109-fast-path-and-control-slow-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#109-fast-path와-slow-control-path" ], "summary": "Fast Path 는 빈번히 반복되는 packet forwarding/data transfer 경로(TAP → vhost-net → virtqueue)이고 Control/Slow Path 는 device 초기화 · feature negotiation · queue setup · configuration change · device reset 처럼 빈도가 낮은 설정/예외 처리다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§105 의 축에 빈도라는 이름을 붙인 절이다. 두 절이 같은 결론에 닿으므로 개념 안의 한 절로 합친다" }, { "id": "SSOT-110-not-always-zero-copy", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#110-data-copy-최적화" ], "summary": "virtio/virtqueue/vhost 구조는 buffer descriptor 로 불필요한 copy 와 context switch 를 줄이도록 설계되어 있지만 항상 zero-copy 라고 일반화하면 안 된다. 실제 copy 여부는 kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO 에 따라 달라질 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§121 이 CONCEPT 포함 범위에 넣은 최적화 항목이고, 「항상 그렇다」로 굳히면 안 된다는 단서다. 단서 하나로는 독립 기록이 되지 않고 개념의 한 절로 들어간다" }, { "id": "SSOT-111-notification-batching-and-moderation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#111-interrupt-notification-최적화" ], "summary": "Guest 와 Host 는 queue 에 새 packet/buffer 가 있음을 서로 알려야 하고, packet 마다 과도한 interrupt/notification 이 나면 overhead 가 커질 수 있어 batching · interrupt moderation · queueing 이 중요하다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "virtqueue 절의 이어지는 설명이다. §122 의 어떤 OQ 도 이것만 따로 재지 않으므로 개념 안에 둔다" }, { "id": "SSOT-112-multi-queue", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#112-multi-queue-최적화" ], "summary": "queue 하나만 쓰면 특정 vCPU/처리 경로에 부하가 몰릴 수 있어 virtio-net 은 multi-queue 를 쓸 수 있다. RX Queue 를 vCPU 에 나눠 packet processing 을 병렬화하고 single queue bottleneck 을 줄이는데, 효과는 workload · CPU affinity · IRQ placement · queue configuration 에 따라 달라진다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "구조 설명은 개념이 안고, 이 Host 의 virtio-net 에 실제로 켜져 있는지는 §122 OQ-5 가 받는다" }, { "id": "SSOT-113-offload-optimizations", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#113-offload-최적화" ], "summary": "TSO · GSO · GRO · Checksum Offload 는 작은 packet 을 하나씩 처리하는 CPU overhead 와 segmentation/aggregation 비용을 줄인다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§121 이 포함 범위에 넣은 최적화 항목이라 개념 본문의 목록으로 들어간다" }, { "id": "SSOT-113-117-6-offload-distorts-packet-capture", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#113-offload-최적화", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-6" ], "summary": "offload 가 켜져 있으면 tcpdump 에서 보이는 packet size 나 checksum 이 실제 wire 에서 보이는 것과 다르게 보일 수 있다. §117.6 은 packet capture 가 예상과 다르게 보이는 원인 후보로 GSO · GRO · TSO · Checksum offload 를 든다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:bisect-the-packet-path-with-capture-points", "reason": "계층마다 capture 해서 끊긴 자리를 가르는 규칙이 스스로 안고 있어야 하는 예외다. 이 단서 없이 capture 결과를 읽으면 정상 동작을 이상으로 읽는다" }, { "id": "SSOT-114-bridge-does-not-always-traverse-host-l3", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#114-linux-bridge가-항상-host-tcp-ip-stack을-거치는-것은-아니다" ], "summary": "Bridge 가 단순 L2 forwarding 을 하는 경우 frame 이 반드시 Host 의 일반적인 L3 TCP/IP stack 을 거치는 것은 아니다(VM1 TAP → Bridge → VM2 TAP). Routing · NAT · Host-local termination · Firewall 이 걸리면 L3/Netfilter 경로가 개입하므로 `Physical NIC → Host TCP/IP Stack → Bridge` 를 고정된 packet path 로 보면 안 된다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§104 와 같은 종류의 교정이고 경로가 구성에 따라 달라진다는 개념의 결론이다. 동시에 capture 결과를 읽는 예외이기도 해서 Reference 쪽에서는 source 로 가리킨다" }, { "id": "SSOT-115-host-nic-does-not-go-through-virtio-again", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#115-host-physical-nic로-나갈-때-virtio를-다시-거치지-않는다" ], "summary": "Host Physical NIC 로 나갈 때 virtio 를 다시 거치는 것이 아니라 Physical NIC 의 실제 driver 를 쓴다. virtio 는 Guest virtual I/O device 와 Host backend 사이의 인터페이스이지 Host 쪽에도 한 벌 더 있는 계층이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§124 의 Claim 13 과 같은 문장이고 §91 의 「virtio 는 I/O 계약이다」가 경로 끝에서 다시 확인되는 자리다. 개념의 마지막 교정 절로 들어간다" }, { "id": "SSOT-116-test-environment-packet-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#116-현재-keycloak-k3s-테스트-환경과-연결" ], "summary": "이 테스트 환경의 경로를 Client → Host Physical NIC → Host Nginx → Host Network → VM1/VM2 → K3s → Keycloak 으로 놓고, VM network 까지 펼치면 Bridge/Route/NAT → TAP(vm1)/TAP(vm2) → vhost-net → virtqueue → virtio-net → Guest Network Stack → K3s networking → Keycloak 이 된다는 서술", "disposition": "NEEDS_EVIDENCE", "dispositionReview": "CONFIRMED", "target": null, "reason": "이 그림의 앞부분(Host Nginx 아래 VM 두 대에 K3s/Keycloak)은 §89 가 밝힌 실험 구성이지만, 펼친 뒷부분은 이 Host 가 Bridge 인지 NAT 인지도(OQ-1) TAP 이 무엇인지도(OQ-2) vhost-net 을 쓰는지도(OQ-3) 확인하기 전의 가정이다. 「이 환경에서 실제로 그러하다」는 주장이라 재기 전에는 Case 도 Concept 도 아니다. OQ-1·2·3·6 이 답하면 다시 판정한다. CPU 부의 SSOT-22-claims-12-13 과 같은 처분이다" }, { "id": "SSOT-117-1-3-connectivity-failures", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-1", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-2", "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-3" ], "summary": "TAP/Bridge 연결 오류(VM 외부 통신 불가 · Host ↔ VM 통신 불가 · 특정 VM 만 통신 불가) · Routing 오류(같은 subnet 은 되는데 다른 subnet 은 안 됨 · gateway 까지는 되고 외부는 실패) · NAT/Firewall 오류(VM → Internet 실패 · 외부 → VM 접근 실패 · 특정 port 만 실패)와 각각의 확인 명령", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:bisect-the-packet-path-with-capture-points", "reason": "증상 셋 모두가 「어느 hop 에서 끊겼는가」로 환원되고 §119 의 계층별 capture 가 그것을 가른다. 셋을 따로 기록으로 만들면 같은 규칙의 부분 증상이 셋이 된다" }, { "id": "SSOT-117-4-vhost-net-unused-or-inefficient-datapath", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-4" ], "summary": "높은 packet rate 에서 QEMU userspace 가 datapath 를 직접 처리하면 CPU overhead 가 커질 수 있고, 관찰 대상은 QEMU CPU usage · vhost thread · packet rate · latency · context switch 다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§107 이 말한 비용이 구조에서 어긋나는 자리로 다시 나온 것이다. 개념의 「이 구조에서 어긋날 수 있는 자리」 절로 들어가고, 이 Host 에서 실제로 그런지는 OQ-3·OQ-4·OQ-7 이 받는다. CPU 부의 §24 도 같은 처분이었다" }, { "id": "SSOT-117-5-single-queue-bottleneck", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-5" ], "summary": "queue/vCPU 하나에 packet processing 이 몰릴 수 있고 확인 대상은 virtio multi-queue · IRQ distribution · per-vCPU CPU usage · RSS/RPS/XPS 다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "§112 와 같은 결론에 닿는 절이라 개념 안에서 같은 자리에 놓인다. 이 Host 의 상태는 OQ-5 가 받는다" }, { "id": "SSOT-117-7-host-cpu-contention-looks-like-network-latency", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#117-이-구조에서-발생할-수-있는-문제-117-7" ], "summary": "vhost-net · QEMU thread · softirq 도 Host CPU 를 쓰므로 network 문제처럼 보여도 CPU scheduling 문제일 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:verify-the-network-path-before-blaming-the-application", "reason": "증상을 어느 계층에 귀속할지의 규칙이고 §120 과 방향만 반대다(하나는 애플리케이션 증상을 network 로, 하나는 network 증상을 CPU 로 되돌린다). 같은 Reference 의 적용 조건과 예외로 들어가고, 재는 것은 OQ-7 이 받는다" }, { "id": "SSOT-118-per-layer-observation-commands", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#118-실제-linux에서-확인할-명령어" ], "summary": "Physical NIC · Linux Bridge · TAP/vnet · libvirt VM NIC · libvirt network · Routing · Guest NIC · virtio 장치 · vhost 아홉 자리를 보는 명령 목록 — `ip link` · `ethtool` · `bridge link` · `bridge fdb show` · `ip tuntap show` · `virsh domiflist` · `virsh net-list --all` · `virsh net-info` · `virsh net-dumpxml` · `ip route` · `ip rule` · `ip neigh` · `lspci` · `lsmod | grep virtio` · `lsmod | grep vhost`", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:bisect-the-packet-path-with-capture-points", "reason": "명령 목록 자체는 규칙이 아니다. §119 의 규칙이 각 지점에서 무엇을 실행할지를 이 목록이 대므로 그 Reference 의 본문 표가 된다. CPU 부의 §14 는 붙일 Reference 가 없어 개념으로 갔지만 여기는 있다" }, { "id": "SSOT-119-bisect-the-path-with-tcpdump", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#119-실제-packet-path-추적" ], "summary": "Host 의 physical NIC · bridge · tap/vnet 과 Guest 의 interface 에서 각각 `tcpdump -ni` 를 걸어 어디까지 보이는지로 의심 구간을 좁힌다 — Physical NIC O · Bridge O · TAP X 이면 Host Bridge/TAP mapping 을, TAP O · Guest NIC X 이면 virtio/vhost/Guest NIC 계층을, Guest NIC O · Socket X 이면 Guest routing/firewall/listen 상태를 의심한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:bisect-the-packet-path-with-capture-points", "reason": "원 사건의 이름을 지워도 규칙이 남는다 — KVM/libvirt 환경이면 어디서든 같은 순서로 구간을 좁힌다. §117.1~.3 의 증상 셋과 §118 의 명령 목록이 이 규칙의 적용 대상과 도구이고, §113·§114 가 예외를 댄다. OQ-1 · OQ-2 · OQ-6 셋이 모두 이 규칙 위에서 돌아가므로 세 글에 되풀이하지 않고 한 편으로 두고 가리킨다. 메모리 부의 §85·§86 이 세운 기준을 따랐다" }, { "id": "SSOT-120-verify-the-network-path-separately", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#120-keycloak-refresh-token-실험과의-관계" ], "summary": "Refresh Token 경쟁 자체는 virtio-net 문제가 아니지만 Client → Nginx → VM1/VM2 → K3s → Keycloak → PostgreSQL/Redis 경로를 공유하므로 network virtualization 문제가 실험 결과에 영향을 줄 수 있다. Node1 요청만 지연 · VM2 packet loss · Host bridge misconfiguration · NAT/conntrack issue · Host CPU contention 으로 인한 vhost 처리 지연을 Refresh Token 경쟁이나 DB lock 으로 오해하지 않도록 network path 를 별도로 검증한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:verify-the-network-path-before-blaming-the-application", "reason": "이 부가 존재하는 이유(§89)와 결론(§124 Claim 17)을 잇는 규칙이고, 다음 프로젝트에도 그대로 적용된다 — 경로를 공유하는 실험에서 애플리케이션·저장소 원인으로 결론내기 전에 공유 계층을 따로 검증한다. §119 의 규칙은 network 안에서 어느 hop 인지를 가르고 이 규칙은 그것이 network 인지 아닌지를 가르므로 둘은 다른 물음에 답한다" }, { "id": "SSOT-122-oq-1-vm-network-mode-bridge-nat-or-routed", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-1" ], "summary": "OQ-1. 현재 VM network 는 Bridge · NAT · Routing 중 어떤 구조인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm-network-mode-bridge-nat-or-routed", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-2-tap-interface-to-vm-mapping", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-2" ], "summary": "OQ-2. VM1/VM2 의 TAP/vnet interface 는 무엇인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:tap-interface-to-vm-mapping", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-3-is-vhost-net-actually-in-use", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-3" ], "summary": "OQ-3. 현재 환경에서 vhost-net 이 실제 사용되는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:is-vhost-net-actually-in-use", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-4-qemu-backend-vs-vhost-net-on-this-host", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-4" ], "summary": "OQ-4. QEMU backend 와 vhost-net 의 성능 차이가 현재 Host 에서 관찰 가능한가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:qemu-backend-vs-vhost-net-on-this-host", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-5-virtio-net-multi-queue-enabled", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-5" ], "summary": "OQ-5. Multi-queue 가 현재 virtio-net 에 활성화되어 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:virtio-net-multi-queue-enabled", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-6-actual-packet-path-nginx-to-keycloak", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-6" ], "summary": "OQ-6. Host Nginx 에서 VM1/VM2 Keycloak 까지 실제 packet path 는 무엇인가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:actual-packet-path-nginx-to-keycloak", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-122-oq-7-network-virtualization-cpu-cost-under-load", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#122-open-question-oq-7" ], "summary": "OQ-7. Keycloak load test 시 network virtualization 이 latency 에 영향을 줄 정도로 Host CPU 를 사용하는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:network-virtualization-cpu-cost-under-load", "reason": "§122 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고 답에 따라 이 부의 서술이 이 Host 에 적용되는지가 갈리며 §122 가 확인 명령이나 관찰 대상을 함께 적어 다음 검증이 있다. 앞선 두 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-123-oq-to-case-flow", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#123-open-question-→-case" ], "summary": "SSOT → CONCEPT → OPEN QUESTION → 실제 packet capture/configuration 확인/load test → CASE 로 이어지는 기록 흐름과 vhost-net 예시", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "네트워크 가상화가 아니라 이 저장소가 기록을 잇는 방식을 설명한 절이다. 분석에는 남아야 하고 공개 기록으로는 읽을 사람이 없다. CPU 부의 §21 도 같은 처분이었다" }, { "id": "SSOT-124-claims-1-16", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#124-핵심-claim" ], "summary": "Claim 1~16 — virsh 는 datapath 에 참여하지 않는다 · libvirt 는 lifecycle/config 를 관리한다 · virtio 는 단일 프로세스나 모듈이 아닌 표준이다 · frontend 는 Guest Kernel 에 있다 · QEMU Device Model 은 생성/negotiation/lifecycle 을 맡는다 · virtqueue 는 descriptor 기반 shared queue 다 · vhost-net 이 없으면 QEMU userspace 가 backend 다 · vhost-net 은 datapath 상당 부분을 Host Kernel 로 옮긴다 · 그러므로 TAP → vhost-net → QEMU → virtqueue 로 일반화하면 안 된다 · TAP 은 Host-side 접점이다 · Bridge 는 L2, Routing 은 L3 다 · Physical NIC 로 나갈 때 virtio 를 다시 거치지 않는다 · Guest TCP/IP Stack 은 실제 stack 이다 · Keycloak 은 socket 만 안다 · vhost-net 의 목적은 QEMU 제거가 아니라 offload 다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-packet-path-to-physical-nic", "reason": "열여섯 전부가 메커니즘 서술이고 §90~§115 가 이미 본문으로 말한 것을 한 화면으로 접은 것이다. 「이 환경에서 실제로 그러하다」고 주장한 것이 없어 NEEDS_EVIDENCE 로 남길 것도 없다. 개념 본문의 요약 표로 들어간다" }, { "id": "SSOT-124-claim-17-network-and-token-race-look-alike", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#124-핵심-claim" ], "summary": "Claim 17 — Network virtualization 문제와 Keycloak Refresh Token 경쟁 문제는 별개지만 같은 실험 환경에서 서로 비슷한 증상으로 보일 수 있으므로 계층별 관측이 필요하다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:verify-the-network-path-before-blaming-the-application", "reason": "열일곱 중 유일하게 메커니즘이 아니라 판독 규칙이다. §120 이 본문으로 말한 것의 결론 문장이라 그 Reference 의 한 줄로 들어간다" }, { "id": "SSOT-126-next-practice-order", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#126-다음-실습-순서" ], "summary": "Physical NIC 확인부터 multi-queue/offload 확인까지 열두 단계의 실습 순서와, 검증되지 않은 항목은 OPEN QUESTION 으로 남기고 결과가 나오면 CASE 로 전환한다는 원칙, 그 다음 K3s/CNI/Service/Pod network 계층을 잇는다는 계획", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "다음에 무엇을 어떤 순서로 잴지의 진행 계획이다. 계획은 실행되면 Case 가 되고 그 전까지는 분석에 남는다. CPU 부의 §23 도 같은 처분이었다" }, { "id": "SSOT-128-139-guest-block-io-path", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#128-전체-구조", "final/document.md#129-guest-application-read-write-에서-시작", "final/document.md#134-guest-block-i-o-layer", "final/document.md#137-virtio-blk-guest의-가상-block-device-driver", "final/document.md#138-virtio-blk와-virtqueue" ], "summary": "§128 이 그린 canonical flow 의 Guest 절반 — 애플리케이션의 `write()` 가 VFS · ext4/XFS · Guest Page Cache · Guest Block Layer · `/dev/vda` · virtio-blk Frontend 를 거쳐 virtqueue 에 실린다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로 중간을 잘라 내면 인과가 끊긴다 — Page Cache 만 떼면 `write()` 성공이 왜 SSD 영속화가 아닌지 말할 수 없고, virtqueue 만 떼면 무엇과 무엇 사이의 queue 인지 말할 수 없다. 독립성 검사를 통과하고, 제4부에서 경로가 시작하는 구간이라 나머지 셋(backend 형태 · 완료의 뜻 · Host block stack)이 이 글을 딛고 갈린다" }, { "id": "SSOT-140-142-what-is-behind-dev-vda", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#140-vm-boundary를-넘으면-qemu가-등장", "final/document.md#141-qemu가-물리-ssd를-직접-제어하는-것은-아니다", "final/document.md#142-qcow2-host에서는-파일-guest에서는-디스크" ], "summary": "VM 경계를 넘으면 QEMU 의 virtio-blk Device Model 과 Block Backend 가 받고, backend 가 파일이면 QEMU 는 Host Linux 에 파일 I/O 를 요청하므로 Guest storage stack 아래에 Host storage stack 이 한 번 더 존재할 수 있다. 같은 대상이 Host 에서는 파일 하나이고 Guest 에서는 디스크다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:qemu-block-backend-forms", "reason": "이 구간에서만 경로가 셋(qcow2 · RAW · Host block device)으로 분기하고, 갈래마다 결과가 다르다 — virtual size 와 실제 할당량의 차이 · mapping/metadata 처리 · Host filesystem 이 한 겹 더 있는지. 경로를 그리는 C1 에 넣으면 세 갈래의 결과가 한 글의 각주가 된다. §128 이 핵심 문장으로 뽑은 것이 이 분기다" }, { "id": "SSOT-147-157-completion-and-cache-boundaries", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#147-vm에서는-page-cache가-두-번-나타날-수-있다", "final/document.md#148-write-완료와-영속화는-다르다", "final/document.md#149-direct-i-o", "final/document.md#150-fsync-가-필요한-이유", "final/document.md#151-flush", "final/document.md#152-가장-위험한-상황-거짓-완료" ], "summary": "Page Cache 가 Guest 와 Host 양쪽에 두 번 나타날 수 있고, `write()` 완료 ≠ writeback 완료 ≠ fsync/flush 완료 ≠ 전원 장애에도 안전한 durability 이며, Guest 에게 거짓 완료를 응답하는 것은 성능 문제가 아니라 correctness 문제다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "C1·C2·C4 가 「데이터가 어디를 지나는가」를 말한다면 이 글은 「완료라는 응답이 무엇을 보장하는가」를 말하므로 물음이 다르다. 없애고 경로 글의 한 절로 넣으면 §148 의 네 경계와 §152 의 correctness 판정이 각주가 되고, cache mode 를 고르는 사람이 다시 찾지 못한다" }, { "id": "SSOT-158-167-host-block-stack", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#158-host-block-layer", "final/document.md#159-여러-vm이-하나의-nvme를-공유하면", "final/document.md#160-blk-mq-multi-queue-block-layer", "final/document.md#161-i-o-scheduler", "final/document.md#164-nvme-driver와-physical-device", "final/document.md#167-storage-contention" ], "summary": "Host Block Layer 는 그 I/O 가 VM 에서 왔는지 Host process 에서 왔는지 본질적으로 구분해 처리하는 계층이 아니라 모두 Host block request 이고, `blk-mq` 와 I/O Scheduler 와 NVMe Driver 를 지나며, 여러 VM 이 한 device 를 쓰면 Storage Contention 이 생긴다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "backend 형태를 말하는 C2 아래에서 요청이 어떻게 줄을 서고 누구와 섞이는지는 다른 물음이다. §158 의 「모두 Host block request 다」가 §167 의 경쟁을 낳고, 그 경쟁은 이 계층을 설명하지 않으면 읽히지 않는다. OQ-5 · OQ-6 · OQ-7 셋이 이 글 위에서 돌아간다" }, { "id": "SSOT-168-cpu-is-fine-but-storage-is-slow", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#168-cpu가-정상이어도-storage-때문에-느릴-수-있다" ], "summary": "PostgreSQL 이 storage completion 을 기다리면 CPU usage 가 높지 않을 수 있어 CPU 30% 인데 request latency 2초 가 가능하므로 CPU 지표만으로 latency 원인을 판단하면 안 된다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:read-storage-before-blaming-cpu-for-latency", "reason": "원 프로젝트의 이름을 지워도 규칙이 남는다 — DB 가 낀 경로면 어디서든 같은 순서로 자원을 가른다. §167 이 CPU Contention 과 Storage Contention 을 다른 자원 경쟁으로 갈라 적용 조건을 대고 §169 와 §177 이 무엇을 함께 볼지를 댄다. 제2부의 §85·§86 이 세운 기준을 따랐다" }, { "id": "SSOT-171-durability-vs-latency-tradeoff", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#171-성능과-durability의-trade-off" ], "summary": "`fsync()` 를 없애서 빨라졌다면 그것이 최적화가 아니라 durability contract 를 제거한 것일 수 있다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:a-speedup-that-removed-durability-is-not-an-optimization", "reason": "설정 선택과 성능 개선의 평가에 걸리는 규칙이라 개념 본문의 각주로 두면 다음에 같은 판단을 하는 사람이 찾지 못한다. §152 가 왜 성능 문제가 아닌지를, §156 이 반대 방향의 오독(writeback 이라는 이름만 보고 위험하다고 단정하는 것)을 막아 적용 조건과 예외가 둘 다 SSOT 안에 있다" }, { "id": "SSOT-145-backend-cannot-be-inferred-from-the-guest", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#145-host-block-device를-직접-backend로-사용-가능" ], "summary": "「Guest 에 `/dev/vda` 가 있다」는 정보만으로 backend 구조를 알 수 없다 — 그 아래에 qcow2 file · RAW file · Host block device 셋이 올 수 있다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "reference:confirm-the-disk-backend-on-the-host", "reason": "OQ-1 · OQ-2 · OQ-3 · OQ-5 넷이 모두 이 규칙 위에서 돌아가므로 네 글에 되풀이하지 않고 한 편으로 두고 가리킨다. §146 이 확정 절차를, §143·§144 가 확정하지 않고 읽었을 때 무엇을 잘못 읽게 되는지를 댄다. 제3부의 reference:bisect-the-packet-path-with-capture-points 와 같은 위치다" }, { "id": "SSOT-175-oq-1-vm-disk-backend-mapping", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-1" ], "summary": "OQ-1. VM 의 `/dev/vda` 는 어떤 Host backend 에 연결되어 있는가", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm-disk-backend-mapping", "reason": "§175 가 아직 돌리지 않은 확인으로 적어 둔 물음이다. 답이 없고, 답에 따라 §142~§145 중 어느 갈래가 이 Host 에 적용되는지가 갈리며, `lsblk` 와 `virsh domblklist ` 라는 다음 검증이 있다. 앞선 세 부가 OPEN QUESTION 을 그대로 question 글감으로 올린 것과 같은 기준이고, 다른 부의 question 이 같은 측정으로 닫는 물음도 아니다" }, { "id": "SSOT-175-oq-2-disk-image-format", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-2" ], "summary": "OQ-2. Backend 는 qcow2 인가 RAW 인가", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "question:disk-image-format-and-actual-host-usage", "reason": "OQ-3 과 같은 한 번의 `qemu-img info` 출력으로 닫힌다 — 형식은 그 출력의 첫 줄이고 OQ-3 이 요구한 세 값 비교의 전제다. 같은 측정으로 닫히는 물음을 두 편으로 만들지 않는다. 제2부가 OQ-1 과 OQ-10 을 한 물음으로 합친 것과 같은 판단이다" }, { "id": "SSOT-175-oq-3-disk-image-format-and-actual-host-usage", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-3" ], "summary": "OQ-3. qcow2 Virtual Size 와 실제 Host 사용량은 얼마나 다른가 — `qemu-img info` · `du -h` · `ls -lh` 세 명령이 보여주는 의미가 서로 다를 수 있으므로 비교한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:disk-image-format-and-actual-host-usage", "reason": "§143 이 100 GB 대 3GB 라는 예시로만 말한 차이를 이 Host 에서 확정하는 물음이다. 답이 없고, 답에 따라 저장 공간 계획과 §144 의 성능 일반화 경계가 갈리며, 세 명령이라는 다음 검증이 있다. OQ-2 를 흡수해 한 편으로 둔다" }, { "id": "SSOT-175-oq-4-qemu-disk-cache-mode", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-4" ], "summary": "OQ-4. QEMU disk cache mode 는 무엇인가 — `virsh dumpxml ` 의 disk driver 설정에서 cache 관련 값을 확인한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:qemu-disk-cache-mode", "reason": "§153~§156 이 두 설정의 뜻을 갈라 놓았지만 이 Host 가 무엇을 쓰는지는 적혀 있지 않다. 답에 따라 §147 의 이중 caching 이 이 환경에 있는지가 갈리고 확인 명령이 있다. 값을 어떻게 둘 것인지는 별도로 NEEDS_DECISION 에 남겼다" }, { "id": "SSOT-175-oq-5-host-block-device-under-the-disk-image", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-5" ], "summary": "OQ-5. qcow2 가 최종적으로 어느 Host block device 위에 있는가 — `lsblk` 와 `findmnt` 로 확인한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-block-device-under-the-disk-image", "reason": "OQ-1 이 image 경로까지 확정한다면 이 물음은 그 경로가 놓인 물리 장치까지 내려간다. 닫는 명령도 결과가 여는 물음도 다르다 — 여기서 나온 device 이름이 OQ-6 의 `` 자리를 채우고 OQ-7 의 전제(두 VM 이 같은 장치를 쓰는가)를 정한다" }, { "id": "SSOT-175-oq-6-host-io-scheduler", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-6" ], "summary": "OQ-6. Host I/O Scheduler 는 무엇인가 — `cat /sys/block//queue/scheduler`", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:host-io-scheduler", "reason": "§161·§162 가 정책의 존재와 `none` 의 뜻을 설명했지만 이 Host 의 값은 없다. 답에 따라 OQ-7 의 해석 조건이 달라지고 §163 이 확인 명령과 읽는 법(대괄호 안이 현재 선택된 것)을 함께 적어 다음 검증이 있다" }, { "id": "SSOT-175-oq-7-vm1-storage-load-vs-vm2-latency", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-7" ], "summary": "OQ-7. VM1 Storage load 가 VM2 latency 에 영향을 주는가 — VM1 에서 별도의 테스트 파일/디스크로 controlled I/O load 를 발생시키고 VM2 의 application latency 와 Host storage 지표를 동시에 본다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:vm1-storage-load-vs-vm2-latency", "reason": "§167 이 구조적 가능성으로만 적은 것을 이 Host 에서 재는 물음이다. 답에 따라 장치 분리나 I/O 제한이 필요한지가 갈리고 실험 설계가 §175 에 적혀 있다. 제1부의 question:vcpu-contention-under-two-vm-load 와 부하 형태가 같지만 재는 자원이 CPU 가 아니라 storage 라 같은 측정으로 닫히지 않는다 — relations 로만 이었다" }, { "id": "SSOT-175-oq-8-guest-fsync-latency-vs-host-storage-latency", "kindCandidate": "OPEN_QUESTION", "sourceRefs": [ "final/document.md#175-실제-테스트-서버에서-확인할-open-questions-oq-8" ], "summary": "OQ-8. Guest `fsync()` latency 와 Host storage latency 가 같이 증가하는가 — Guest application/DB latency 와 Host `iostat` 를 시간축으로 함께 관찰한다", "disposition": "PROMOTE", "dispositionReview": "CONFIRMED", "target": "question:guest-fsync-latency-vs-host-storage-latency", "reason": "§150 이 말한 전달 경로가 이 환경에서 이어지는지를 재는 물음이다. 제2부의 question:host-major-fault-vs-storage-latency 와 가장 가깝지만 그쪽은 Host memory pressure 로 유도한 major fault 가 storage 를 미는지를 보고 이쪽은 애플리케이션의 `fsync()` 가 Host storage 까지 전달되는지를 본다 — 유도 방법도 계열도 달라 같은 실행으로 닫히지 않는다. relations 로만 이었다" }, { "id": "SSOT-127-part-scope-and-deferred-internals", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#127-문서-목적" ], "summary": "제4부가 다루는 범위 — Guest 의 `write()`/`fsync()` 가 Host 물리 SSD/NVMe 까지 내려가는 하나의 일관된 경로, 그리고 VFS 부터 Storage contention 까지 열넷 — 과, qcow2 내부 L1/L2 table · blk-mq tag allocator · NVMe submission/completion queue 를 별도 문서로 미룬다는 선언", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "이 부가 무엇을 다루고 무엇을 다루지 않는지의 선언이다. 따로 떼면 아무 것도 설명하지 않는 목차가 되고, 네 개념의 basis-version 과 missing-verification 이 그대로 받는다. 제3부의 §89 와 제2부의 §88 도 같은 처분이었다" }, { "id": "SSOT-129-application-does-not-touch-the-device", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#129-guest-application-read-write-에서-시작" ], "summary": "VM 안의 PostgreSQL 이나 Keycloak 은 SSD 나 virtio-blk 를 직접 다루지 않고 `write(fd, buffer, size);` 로 Guest Linux Kernel 에 파일 연산을 요청하며, 이 시점에는 아직 QEMU · qcow2 · Host NVMe 가 등장하지 않는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로의 첫 칸이다. 한 문장으로 개념 안에 설명되므로 독립 기록이 되지 않는다" }, { "id": "SSOT-130-vfs-routes-to-the-filesystem", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#130-vfs-공통-파일-인터페이스-계층" ], "summary": "VFS 는 여러 filesystem 을 동일한 API 로 쓰게 하는 공통 계층이고, 이 fd 가 어떤 파일인가 → 어떤 filesystem 에 속하는가 → 해당 구현으로 연산 전달 순으로 동작한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로의 두 번째 칸이고 ext4 든 XFS 든 같은 자리를 지난다는 것을 말한다. 개념 본문의 한 절이다" }, { "id": "SSOT-131-132-filesystem-and-inode-map-files-onto-blocks", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#131-filesystem-ext4-xfs-파일-세계를-block-공간에-배치", "final/document.md#132-inode" ], "summary": "ext4/XFS 가 파일·디렉터리라는 논리 구조를 block 공간에 배치하고, inode 가 파일 metadata 와 저장 위치를 관리하며 파일 이름 자체와 inode 는 같은 것이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "§132 스스로 「inode 내부 구현까지 파고들 필요는 없지만 filesystem 이 파일과 block 을 연결한다는 점은 알아야 한다」고 범위를 그었다. 그 한 문단이 개념 안에 들어간다" }, { "id": "SSOT-133-write-lands-in-page-cache-first", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#133-page-cache-write-가-바로-ssd-write는-아니다" ], "summary": "buffered I/O 에서 `write()` 는 Page Cache 에 먼저 닿아 dirty page 가 되고 나중에 writeback 되므로 `write()` 성공은 Physical SSD 영속화 완료가 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로 위의 한 칸이라 C1 에 들어간다. 이 절이 던진 「완료가 무슨 뜻인가」는 §148 이 받아 concept:write-completion-is-not-durability 로 이어지므로 그 글도 이 절을 source 로 가리킨다" }, { "id": "SSOT-134-block-layer-turns-file-offsets-into-device-requests", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#134-guest-block-i-o-layer" ], "summary": "Block I/O Layer 가 filesystem 세계의 「offset 8192 에 4KB write」를 block device 세계의 READ/WRITE/FLUSH/DISCARD 요청으로 바꾸고, 내부에는 `bio` · request · queue · `blk-mq` 가 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "두 세계를 잇는 칸이다. 내부 자료구조는 §127 이 범위 밖으로 두었으므로 개념 본문에서도 이름까지만 적는다" }, { "id": "SSOT-135-dev-vda-is-not-the-host-ssd", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#135-dev-vda-guest가-보는-가상-block-device" ], "summary": "virtio-blk 를 쓰는 VM 에서는 `/dev/vda` · `/dev/vdb` 처럼 보이고 Guest Linux 는 그것을 하나의 block device 로 인식하지만 그것이 Host 의 실제 SSD 라는 뜻은 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로의 칸이면서 reference:confirm-the-disk-backend-on-the-host 가 세우는 규칙의 근거다. 개념에 흡수하고 그 Reference 가 source 로 가리킨다" }, { "id": "SSOT-136-block-device-view-and-filesystem-view", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#136-dev-vda-와-filesystem-관계" ], "summary": "`/dev/vda` → partition → filesystem → mount point 로 이어지는 관계이고, `cd /var/lib/postgresql` 은 filesystem 세계를 보는 것이며 `lsblk` 에서 `vda` 를 보는 것은 block device 세계를 보는 것이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "두 관점의 구분이라 개념 안의 그림 한 장으로 들어간다. 독립 기록으로 두면 문단 둘인 글이 된다" }, { "id": "SSOT-137-driver-and-device-node-are-different-things", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#137-virtio-blk-guest의-가상-block-device-driver" ], "summary": "`/dev/vda` 는 Guest Linux 에 보이는 block device 이고 virtio-blk 는 그 virtual block device 를 제어하는 Guest Kernel driver 다 — Network 의 `ens3` 와 virtio-net 이 같은 관계다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "이름 둘을 가르는 절이다. 개념 본문의 한 절이고, Network 대응은 §173 의 표가 받는다" }, { "id": "SSOT-138-139-virtqueue-is-descriptors-over-guest-ram", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#138-virtio-blk와-virtqueue", "final/document.md#139-virtqueue의-실제-의미" ], "summary": "virtio-blk driver 가 Guest Block Layer 의 요청을 Virtio block request 로 구성해 virtqueue 에 게시하고, virtqueue 는 단순한 데이터 파이프가 아니라 Guest RAM 의 I/O buffer 를 descriptor 가 가리키는 구조이며 처리가 끝나면 backend 가 completion 을 돌려준다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "경로의 마지막 칸이다. 제3부의 concept:guest-packet-path-to-physical-nic 이 같은 구조를 packet 쪽에서 설명하므로 여기서는 storage 요청의 모양만 적고 그 글을 relations 로 가리킨다" }, { "id": "SSOT-166-completion-travels-back-through-virtqueue", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#166-storage-i-o-completion" ], "summary": "WRITE 요청은 아래로 내려가고 완료는 NVMe → NVMe Driver → Host Block Layer → QEMU/backend → virtqueue completion → virtio-blk → Guest Block Layer 로 올라오므로 virtqueue 는 request 뿐 아니라 completion 전달 구조까지 포함해 이해해야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "이 절의 결론 문장이 virtqueue 를 가리키므로 C1 의 마지막 절로 들어간다. 왕복 경로 한 장을 기록 하나로 만들지 않는다" }, { "id": "SSOT-172-177-canonical-flow-and-summary", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#172-storage-virtualization-canonical-flow", "final/document.md#177-최종-요약" ], "summary": "Guest Userspace 부터 Non-volatile Media 까지의 canonical flow 와 그 역방향 completion, 그리고 write 완료 ≠ writeback 완료 ≠ flush 완료 ≠ 전원 장애에도 살아남는 durability 라는 요약과 CPU usage 만 보지 말고 함께 볼 여덟 가지", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "네 개념이 나눠 설명하는 경로를 한 장으로 그린 지도다. 경로가 시작하는 C1 이 그 그림을 열면서 싣고 나머지 셋은 자기가 그림의 어느 구간인지를 가리킨다. 제2부가 §79 와 §87 을 같은 이유로 첫 개념에 흡수했다" }, { "id": "SSOT-173-network-storage-correspondence", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#173-network-virtualization과-비교" ], "summary": "virtio-net ↔ virtio-blk · packet ↔ block I/O request · TX/RX virtqueue ↔ I/O virtqueue · TAP/network backend ↔ QEMU block backend · Linux Bridge/Route ↔ Host filesystem/block stack · Physical NIC ↔ Physical SSD/NVMe · Guest TCP/IP Stack ↔ Guest VFS/Filesystem/Block Layer · send/recv ↔ read/write/fsync 대응표", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:guest-block-io-path-to-virtqueue", "reason": "제3부를 읽은 독자를 이 부로 잇는 다리다. SSOT 가 스스로 붙인 단서(학습용 대응 관계이며 각 요소가 1:1 로 같은 종류라는 뜻은 아니다)까지 표와 함께 옮긴다. 표 하나를 독립 기록으로 두면 문단 셋인 글이 된다" }, { "id": "SSOT-143-virtual-size-is-not-host-allocation", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#143-qcow2-virtual-size와-실제-host-사용량" ], "summary": "qcow2 는 가상 disk size 와 실제 Host 할당량이 다를 수 있고(Guest 가 보는 100 GB 에 Host 실제 3GB), Guest 가 기록하면서 Actual 이 1GB → 10GB → 40GB 로 늘 수 있으므로 `qemu-img info vm1.qcow2` 의 `virtual size` 와 실제 allocation 을 구분해서 봐야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:qemu-block-backend-forms", "reason": "backend 가 qcow2 일 때만 생기는 성질이라 그 갈래를 설명하는 개념 안에 들어간다. 이 Host 의 값을 재는 것은 question:disk-image-format-and-actual-host-usage 가 따로 받는다" }, { "id": "SSOT-144-raw-is-not-automatically-faster", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#144-raw-image" ], "summary": "RAW 는 qcow2 보다 구조가 단순하고 qcow2 는 Copy-on-Write · sparse allocation · snapshot 에 유리하지만 metadata/mapping 처리가 있으며, 「RAW = 무조건 빠름 / qcow2 = 무조건 느림」으로 일반화하면 안 된다 — 실제 성능은 cache mode · storage backend · workload pattern · queue depth · snapshot chain · underlying filesystem · physical device 에 영향을 받는다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:qemu-block-backend-forms", "reason": "형식 둘을 가르면서 그 구분만으로 성능을 말하지 말라고 닫는 절이다. 개념이 분기를 설명하고 끝나는 자리가 여기라 개념 본문의 마지막 절이 된다" }, { "id": "SSOT-174-claims-1-3-virtual-disk-and-nested-stacks", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#174-핵심-claim" ], "summary": "Claim 1~3 — Guest 의 `/dev/vda` 는 virtual block device 이고 실제 Host backend 는 qcow2 · RAW · Host block device 등이 될 수 있다 · `virtio-blk + virtqueue` 가 Guest block I/O 를 Host backend 와 연결한다 · qcow2 가 Host filesystem 위의 파일이면 Guest filesystem 아래에 Host filesystem/storage stack 이 한 번 더 존재한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:qemu-block-backend-forms", "reason": "셋 다 메커니즘 서술이고 §135·§138·§141·§142·§145 가 이미 본문으로 말한 것을 한 화면으로 접은 것이다. 「이 환경에서 실제로 그러하다」고 주장한 것이 없어 NEEDS_EVIDENCE 로 남길 것도 없다. 개념 본문의 요약 표로 들어간다" }, { "id": "SSOT-153-155-qemu-cache-mode", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#153-qemu-cache-mode", "final/document.md#154-cache=none", "final/document.md#155-cache=writeback" ], "summary": "`cache=none` 과 `cache=writeback` 은 이름 그대로 읽으면 부정확하고 핵심은 QEMU 가 Host Page Cache 와 write completion/flush semantics 를 어떻게 쓰는가다 — `cache=none` 은 우회 방향이라 이중 caching 을 줄이지만 즉시 durable media 반영이 아니고, `cache=writeback` 은 Host Page Cache 를 쓰지만 Guest 의 `fsync()`/FLUSH 를 무시한다는 뜻이 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "완료의 뜻을 설명하는 개념 안에서 설정 둘이 그 뜻을 어떻게 바꾸는지의 절이 된다. 설정 이름 셋을 각각 기록으로 만들면 같은 물음에 답하는 글이 셋이 된다" }, { "id": "SSOT-156-writeback-is-not-automatically-unsafe", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#156-writeback-=-위험-이라고-단정하면-안-되는-이유" ], "summary": "정확한 표현은 「writeback caching 에서는 volatile cache 가 존재할 수 있으므로 Guest 의 flush/fsync semantics 가 전체 backend/storage stack 에서 올바르게 보존되는지가 중요하다」이며, Guest 가 요구한 durability 가 Guest Filesystem → Guest Block Layer → virtio → QEMU/backend → Host Storage → Device chain 에서 깨지지 않아야 한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "개념이 그리는 chain 그대로다. 이 절이 세운 판독 규칙은 reference:a-speedup-that-removed-durability-is-not-an-optimization 이 예외 항목으로 받아 두 곳에 같은 문장을 두지 않는다" }, { "id": "SSOT-157-device-side-cache", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#157-device-side-cache" ], "summary": "Host Page Cache 를 우회해도 Storage controller/device 가 volatile write cache 를 가질 수 있어 RAM 에서 나갔다 ≠ Device 에 command 가 전달됐다 ≠ 전원이 끊겨도 살아남는 상태가 됐다 이고, device flush/FUA semantics 와 power-loss protection 여부도 중요할 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "§148 의 네 경계 뒤에 하나가 더 있다는 절이라 같은 개념의 마지막 칸이다. 따로 떼면 앞의 세 경계를 다시 설명해야 읽힌다" }, { "id": "SSOT-170-postgresql-wal-durability", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#170-postgresql-예시-wal과-durability" ], "summary": "PostgreSQL 은 WAL 등의 durability protocol 을 쓰며 필요한 시점에 storage synchronization 을 수행하고, VM storage layer 가 flush/fsync semantics 를 제대로 보존하지 않으면 PostgreSQL 의 durability assumption 과 실제 storage behavior 가 어긋날 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "개념이 말한 보장이 깨질 때 애플리케이션에서 무엇이 어긋나는지를 보이는 예시다. 예시 하나를 독립 기록으로 만들지 않고 개념 본문의 적용 절로 넣는다" }, { "id": "SSOT-174-claims-4-5-cache-and-durability", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#174-핵심-claim" ], "summary": "Claim 4~5 — Guest 와 Host 양쪽에 Page Cache 가 존재할 수 있고 Direct I/O 와 QEMU cache mode 는 Host Page Cache 사용 방식과 연결된다 · `write()` 완료와 durability 는 같은 의미가 아니다(write ≠ writeback ≠ fsync/flush 완료 ≠ 전원 장애에도 안전한 상태)", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:write-completion-is-not-durability", "reason": "둘 다 메커니즘 서술이고 §147~§157 이 본문으로 말한 것을 접은 것이다. 개념 본문의 요약 표로 들어간다" }, { "id": "SSOT-159-one-nvme-serves-many-sources", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#159-여러-vm이-하나의-nvme를-공유하면" ], "summary": "VM1 QEMU · VM2 QEMU · Nginx · Host 기타 프로세스의 요청이 같은 Host Block Layer queue 에서 관리되어 NVMe 로 dispatch 된다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "§158 의 「모두 Host block request 다」가 그림으로 이어진 것이다. 개념 본문의 한 절이고, 이 Host 에서 실제로 겹치는지는 question:vm1-storage-load-vs-vm2-latency 가 받는다" }, { "id": "SSOT-160-blk-mq-parallel-queues", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#160-blk-mq-multi-queue-block-layer" ], "summary": "`blk-mq` 는 CPU 마다 queue 를 두어 여러 CPU 가 병렬로 block I/O 를 처리하게 하며 NVMe 가 높은 병렬성과 queue depth 를 지원하기 때문에 중요하고, Storage 처리 역시 CPU scheduling 과 완전히 독립된 세계는 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "Host block stack 의 한 칸이다. 마지막 문장이 제1부의 CPU 개념과 이어지는 자리라 개념의 relations 로 잇고 본문은 여기 한 절로 둔다" }, { "id": "SSOT-161-io-scheduler-reorders-requests", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#161-i-o-scheduler" ], "summary": "여러 I/O request 가 있다고 해서 항상 들어온 순서 그대로 device 에 전달되는 것은 아니고 I/O Scheduler 가 dispatch 정책을 가지며 대표적으로 `none` · `mq-deadline` · `bfq` 를 볼 수 있다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "Host block stack 의 한 칸이다. 이 Host 의 값은 question:host-io-scheduler 가 받는다" }, { "id": "SSOT-162-none-scheduler", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#162-none" ], "summary": "`none` 은 복잡한 scheduling 정책을 최소화해 비교적 직접 device 쪽으로 dispatch 하는 방향이고 NVMe 처럼 device 자체가 강한 병렬성과 queueing 을 가지면 적합할 수 있지만, block layer 가 아무 일도 하지 않는다는 뜻은 아니다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "scheduler 값 하나의 뜻이다. 개념 본문에서 §161 의 목록에 붙는 한 문단이고 독립 기록이 될 분량도 물음도 아니다" }, { "id": "SSOT-163-read-the-active-io-scheduler", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#163-실제-i-o-scheduler-확인" ], "summary": "`cat /sys/block/nvme0n1/queue/scheduler` 의 출력 `[none] mq-deadline` 에서 대괄호 안이 현재 선택된 scheduler 이고, SATA/SCSI device 라면 `cat /sys/block/sda/queue/scheduler` 처럼 확인한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "명령 하나와 출력 읽는 법이다. 개념 본문에 두고, 이 Host 에서 실제로 돌리는 것은 question:host-io-scheduler 가 next-verification 으로 받는다" }, { "id": "SSOT-164-nvme-driver-is-a-host-kernel-driver", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#164-nvme-driver와-physical-device" ], "summary": "NVMe Driver 는 Host Linux Kernel 의 device driver 이고 Network 에서 physical NIC driver 가 하드웨어를 제어하는 것과 동일한 계층적 위치다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "Host block stack 의 마지막 칸이다. 한 문단으로 개념 안에 들어간다" }, { "id": "SSOT-165-nvme-is-a-protocol-ssd-is-a-device-class", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#165-nvme와-ssd-구분" ], "summary": "SSD 는 저장장치의 넓은 종류이고 NVMe 는 PCIe 기반 non-volatile storage 를 위한 protocol/interface 이며, SSD 아래에 SATA SSD(SATA/AHCI)와 NVMe SSD(PCIe + NVMe)가 갈린다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "이 계층의 이름을 정리하는 절이다. 용어 구분 하나를 독립 기록으로 만들지 않는다" }, { "id": "SSOT-167-storage-contention-is-not-cpu-contention", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#167-storage-contention" ], "summary": "여러 VM 이 동일한 Physical NVMe 를 쓰면 storage resource 경쟁이 생겨 VM1 의 대량 I/O 가 VM2 의 storage latency 를 올릴 수 있고, CPU Contention(Host logical CPU 실행 시간 경쟁)과 Storage Contention(IOPS/bandwidth/queue/device 처리시간 경쟁)은 다른 자원 경쟁이다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "concept:host-block-stack-under-the-vm", "reason": "§158·§159 가 세운 구조의 결과라 같은 개념 안에서 닫힌다. 여기서 나온 판독 규칙은 reference:read-storage-before-blaming-cpu-for-latency 가 받고, 이 Host 에서 재는 것은 question:vm1-storage-load-vs-vm2-latency 가 받는다" }, { "id": "SSOT-146-verify-the-guest-to-host-disk-link", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#146-실제-연결-확인" ], "summary": "Guest 의 `lsblk` 와 Host 의 `virsh domblklist ` 로 Target 과 Source 를 이어 `/dev/vda` → virtio-blk → QEMU → `/var/lib/libvirt/images/vm1.qcow2` 관계를 확인한다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:confirm-the-disk-backend-on-the-host", "reason": "명령 둘과 판독 절차 자체가 §145 규칙의 실행 방법이다. 그 Reference 의 scope 가 요구하는 첫 확인이라 본문 절로 들어간다. 제3부에서 §118 의 명령 목록을 §119 의 Reference 로 넣은 것과 같다" }, { "id": "SSOT-169-storage-observation-commands", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#169-storage-관측-명령어" ], "summary": "device I/O 관측은 `iostat -xz 1` 로 read/write throughput · IOPS · request latency · queue 상태 · device utilization 성격의 지표를 보고, 어떤 process 가 I/O 를 내는지는 `iotop` 으로 본다. Guest 는 `lsblk` · `mount` · `df -h` · `cat /proc/mounts` · `iostat -xz 1`, Host 는 `virsh domblklist ` · `qemu-img info ` · `lsblk` · `cat /sys/block//queue/scheduler` · `iostat -xz 1` · `iotop`", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:read-storage-before-blaming-cpu-for-latency", "reason": "명령 목록 자체는 규칙이 아니다. §168 의 규칙이 무엇을 함께 보라고 요구하고 이 목록이 그 도구를 대므로 그 Reference 의 본문 표가 된다. 제3부의 §118 도 같은 처분이었다" }, { "id": "SSOT-174-claim-6-storage-perf-is-not-guest-only", "kindCandidate": "REFERENCE", "sourceRefs": [ "final/document.md#174-핵심-claim" ], "summary": "Claim 6 — Storage 성능은 Guest 내부만으로 결정되지 않고 QEMU/backend · Host block queue · I/O scheduler · NVMe · cache · 다른 VM 의 storage load 가 함께 영향을 준다", "disposition": "MERGE_INTO", "dispositionReview": "CONFIRMED", "target": "reference:read-storage-before-blaming-cpu-for-latency", "reason": "여섯 Claim 중 유일하게 메커니즘이 아니라 판독 규칙이다. §168 이 본문으로 말한 것의 결론 문장이라 그 Reference 의 한 줄로 들어간다. 제3부의 Claim 17 과 같은 처분이다" }, { "id": "SSOT-176-recommended-practice-order", "kindCandidate": "CONCEPT", "sourceRefs": [ "final/document.md#176-권장-실습-흐름" ], "summary": "Guest 에서 `/dev/vda` 확인부터 DB fsync latency 와 Host storage latency 상관관계 확인까지 여덟 단계의 권장 실습 흐름", "disposition": "KEEP_IN_SSOT", "dispositionReview": "CONFIRMED", "target": null, "reason": "다음에 무엇을 어떤 순서로 잴지의 진행 계획이다. 계획은 실행되면 Case 가 되고 그 전까지는 분석에 남는다. 제1부의 §23 · 제2부의 §84 · 제3부의 §126 도 같은 처분이었다" }, { "id": "SSOT-153-157-cache-mode-choice-not-made", "kindCandidate": "DECISION", "sourceRefs": [ "final/document.md#153-qemu-cache-mode", "final/document.md#156-writeback-=-위험-이라고-단정하면-안-되는-이유" ], "summary": "이 환경의 VM disk cache mode 를 `cache=none` 으로 둘 것인가 `cache=writeback` 으로 둘 것인가", "disposition": "NEEDS_DECISION", "dispositionReview": "CONFIRMED", "target": null, "reason": "SSOT 는 두 설정의 뜻과 각각의 오해를 갈라 놓기만 했고 어느 쪽을 쓰기로 정했다고 적지 않았다. §156 은 오히려 이름만 보고 단정하지 말라고 못박아 방향을 제시하지 않는다. 감수한 비용도 적혀 있지 않다. 게다가 현재 값이 무엇인지조차 확인되지 않았다 — question:qemu-disk-cache-mode 가 그것을 먼저 답해야 한다. 권고 없는 서술을 Decision 으로 올리면 「기술이 존재한다」를 근거로 바꾸는 실수가 된다" } ], "counts": { "topics": 4, "nodes": 57, "written": 57, "unwritten": 0, "unlisted": 0, "candidates": 213 }, "unlisted": [], "history": { "2026-09-08": "S2 — SSOT(절 28개)에서 후보 39건을 뽑아 처분을 적고 PROMOTE 하나만 글감으로 올렸다. 앵커 형식을 h2 절 제목 슬러그로 정하면서 final/document.md 의 frontmatter 를 떼고 heading 단계를 맞췄다(본문 문장은 그대로).", "2026-09-08 · S2 재판정": "§20 의 OQ-1~6 과 §27 의 OQ-7~12 열둘을 NEEDS_EVIDENCE 에서 PROMOTE 로 다시 판정하고 cpu-virtualization 주제에 question 글감 열둘로 올렸다. readiness 는 전부 OPEN 이고 known 에는 SSOT 가 서술한 것만, unknown 에는 이 Host 에서 재야 아는 것만 적었다. 앵커는 h2 절 제목 슬러그에 OQ 번호를 구분자로 붙인 형식이다. 후보 27건과 concept 글감은 그대로 두었다.", "2026-09-09 · S2-B 제3부": "SSOT 제3부(네트워크 가상화 §89~§126, 절 38개)에서 후보 48건을 뽑아 처분을 적고 PROMOTE 10건을 network-virtualization 주제의 글감으로 올렸다 — concept 하나 · reference 둘 · question 일곱. candidateScope.sections 에 제3부 절 제목 38개를 덧붙였다. 제1부·제2부의 주제 둘과 후보 116건은 그대로 두었다.", "2026-09-09 · S2-C 제4부": "SSOT 제4부(스토리지 가상화 §127~§177, 절 51개)에서 후보 56건을 뽑아 처분을 적고 PROMOTE 14건을 storage-virtualization 주제의 글감으로 올렸다 — concept 넷 · reference 셋 · question 일곱. candidateScope.sections 에 제4부 절 제목 51개를 덧붙이고 최상단 note 의 「주제도 하나이고 글감도 concept 하나」를 지금 상태(주제 넷 · 글감 57)로 고쳤다. 제1~3부의 주제 셋과 후보 164건은 그대로 두었다." } }