Files
document-haness/docs/virtualization/tech-log-studio/memory-virtualization/concept/concept-virtio-balloon-memory-reclaim.md
T
DongHyeonkaandClaude Opus 5 2109f726fe feat(pipeline): keycloak-session-store 25편·virtualization 59편을 S3→S5→S6 으로 돌린다
기록 84편을 계약 에이전트로 다시 썼다. 기존 71편(kss 25 · virt 46)과, 계약에만
있고 안 쓰여 있던 새 글감 13편이다. 원장 84개를 열어 단계마다 스킬 영수증과 관문
종료 코드를 적었고 verify-pipeline-run.py 가 error 0 으로 닫는다.

SSOT 결함 둘을 고쳤다.

- kss 의 `약 58일` 이 반입 중 `약 59일` 로 바뀌어 있었다. 원 증거 파일이
  「남은 일수: 88일 … 실제 갱신까지 약 58일」로 산수를 직접 적는다. D-4a 쪽
  `약 59일` 은 강제 갱신 뒤(`VALID: 89 days`)라 맞는 값이라 그대로 뒀다.
- virt §198 의 `11.6GB` 는 §178 의 원 측정 `Mem: 11648`(MiB)과 어긋나는데
  원 가이드의 표기 그대로라 고치지 않고 쓰이는 자리에 대조를 적었다.

기록의 수치 오류 셋을 고쳤다 — CASE 요약의 「게스트 셋에 8240MB」(5120+3120 은
둘이다), k3s 편이 같은 것을 여섯·일곱·여덟로 세던 것, no-docker 편의 「셋을 더
든다」(§281 의 표는 네 행이고 디스크 행이 빠져 있었다).

계약을 셋 고쳤다.

- kss 의 sourceRepository 리비전이 cdac9b8 이었는데 그 커밋에는 docs/guides/**
  28개가 아예 없다. 9465582b 로 바꾸고, 반입한 바이트가 어느 커밋과도 같지 않다는
  것을 측정값과 함께 적었다 — 반입은 커밋이 아니라 그 시점의 작업 트리에서 떠 온
  것이다(kss 297/306 · virt 12/14 가 작업 트리와 같고, 200 커밋을 거슬러 전수
  대조했을 때 가장 가까운 커밋도 28개가 어긋났다).
- virt 계약이 「2026-09-11 재배분」이라고 적는데 SSOT 는 재배분 날짜를 적지 않고
  재배분 뒤 값은 이미 2026-09-10 측정에 찍혀 있다.
- kss 후보 대장이 지나친 절 아홉에 처분을 적었다(warn 9 → 0). 새 글감은 0건이고
  넷은 앵커가 h3 슬러그의 접두가 아니라 중간 토막이라 검사기가 못 본 것이었다.

style_profile.mjs 의 결함 둘을 고쳤다 — frontmatter 가 문장으로 세어져
(실측 398자짜리 「문장」 하나) 평균 길이를 기준 안으로 밀어 올리고 있었고,
engPerSent 의 분자는 목록을 포함한 글에서, 분모는 목록을 걷어낸 글에서 세고
있었다(Question 기록에서 11.94 → 3.86).

verify-pipeline.py 전 항목 PASS · error 0 · unittest 334건 OK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:01:55 +09:00

12 KiB

id, kind, slug, title, topic, topicName, project, status, basisVersion, studio, sourceRevision, assets, source
id kind slug title topic topicName project status basisVersion studio sourceRevision assets source
ebdf93d7-2dcb-4fc8-91b9-2364ac8196e6 CONCEPT virtio-balloon-memory-reclaim virtio-balloon 이 Guest 메모리를 회수하고 돌려주는 방식 memory-virtualization 메모리 가상화 virtualization 초안 virtio-balloon — Guest kernel 쪽 driver 와 QEMU 쪽 device 가 virtqueue 로 맞물린 구성 · libvirt 의 balloon target https://hyeonworks.com/studio/documents/ebdf93d7-2dcb-4fc8-91b9-2364ac8196e6/edit no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
key file
virtio-balloon-inflate-deflate ../../../final/assets/diagrams/virtio-balloon-inflate-deflate/virtio-balloon-inflate-deflate.svg
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

virtio-balloon 이 Guest 메모리를 회수하고 돌려주는 방식

호스트는 QEMU 가 마련한 게스트 RAM 을 볼 수 있지만 그 안에서 어떤 메모리가 중요한지는 알지 못한다. 그 구분을 아는 쪽은 게스트 커널이라, 호스트가 그 메모리를 그냥 스왑으로 밀어내는 대신 게스트와 협력해 필요 없는 몫을 돌려받는 방법이 따로 있다. virtio-balloon 이 그 협력에 쓰는 가상 장치다. 게스트 안의 드라이버와 QEMU 쪽 장치가 virtqueue 로 맞물려 있어서, 호스트가 balloon target 을 올리면 게스트 안의 balloon 이 커지고 게스트가 쓸 수 있는 메모리가 줄며 호스트가 회수할 수 있는 몫이 는다. 값을 낮추면 반대 방향으로 움직인다. 이 장치는 게스트에 RAM 을 더 주는 장치가 아니라 이미 준 용량 안에서 쓸 수 있는 양을 옮기는 장치이고, 과도하게 회수하면 호스트 RAM 을 확보하려던 조치가 게스트를 압박한다.

관계

  • Host 메모리 압박이 Guest 와 스토리지까지 내려가는 경로 ballooning 은 그 압박에 대응하는 수단 가운데 하나다. 호스트가 무작정 스왑으로 밀어낼 때 무엇이 일어나는지는 그쪽에 적혀 있다.
  • 이 가상 머신들에 virtio-balloon 이 붙어 있는가 이 프로젝트의 가상 머신에 이 장치가 구성돼 있는지는 근거 문서에 없다. 그것을 확인하는 질문이다.
  • balloon target 을 바꾸면 게스트가 쓸 수 있는 메모리는 어떻게 따라 움직이는가 부풀리고 줄이는 방향은 이 글이 적었고, 이 환경에서 얼마나 어떤 속도로 반영되는지는 그 질문이 잰다.
  • 메모리 증상 하나로 계층을 단정하지 않는다 balloon target 은 그 기준이 가르는 다섯 갈래 중 Dynamic Memory 갈래다. 게스트 안의 압박을 보고 호스트 RAM 부족으로 넘기기 전에 이 값을 본다.

본문

호스트는 게스트 안에서 무엇이 중요한지 알지 못한다

호스트는 QEMU 가 마련한 게스트 RAM 을 볼 수 있다. 그러나 그 안에서 어떤 메모리가 중요한지는 게스트 밖에서 완전히 알 수 없다. 게스트는 자기 메모리를 애플리케이션이 실제로 쓰는 몫(working set)과 JVM heap, 페이지 캐시, 비어 있는 몫처럼 의미가 다른 묶음으로 구분해 알고 있다. 호스트가 보는 것은 같은 크기의 익명 메모리라서 그 안에서 페이지 캐시를 눌렀는지 실제로 쓰는 몫을 눌렀는지 가려낼 수 없다.

그래서 호스트가 그 메모리를 무작정 스왑으로 밀어내기보다 게스트 커널과 협력해 필요 없는 몫을 돌려받는 편이 유리할 수 있다. 그 협력에 쓰는 대표적인 메커니즘이 virtio-balloon 이다.

게스트 드라이버와 QEMU 장치가 virtqueue 로 맞물린다

virtio-balloon 은 게스트 커널 쪽의 balloon 드라이버와 QEMU 쪽의 balloon 장치가 virtqueue 로 이어진 구성이다. virtqueue 는 게스트와 QEMU 가 요청과 응답을 주고받는 공유 큐이고, balloon 관련 요청도 이 큐를 지나 VM 경계를 넘는다. QEMU 쪽 장치는 받은 내용을 호스트의 메모리 관리로 넘긴다.

이 장치는 게스트 RAM 자체를 제공하지 않는다. 이미 존재하는 게스트 RAM 을 호스트와 게스트가 협력해 회수하고 반환하는 데 쓰는 가상 장치다.

이 프로젝트의 가상 머신에 이 장치가 붙어 있는지는 libvirt 설정을 읽어야 정해지고 그 기록이 아직 없다. 아래 두 절이 적는 것은 장치가 있을 때 어느 방향으로 움직이는가다.

Inflate — 게스트 안의 balloon 이 커진다

호스트가 게스트 메모리를 회수하려고 하면 balloon target 을 조정해 balloon 을 부풀린다. 이 동작을 inflate 라고 한다. 그 요청이 virtio-balloon 을 지나 게스트 안의 balloon 드라이버에 닿으면 드라이버가 게스트 페이지를 확보한다. 게스트 안의 balloon 이 커지기 때문에 게스트가 쓸 수 있는 RAM 이 그만큼 줄고, 호스트 쪽에서는 회수할 수 있는 메모리가 는다.

드라이버가 하는 일은 확보한 페이지를 일반적인 게스트 작업이 쓰지 못하도록 붙잡아 두고 그 사실을 호스트 쪽에 알리는 것까지다. 그 뒤 호스트가 그 메모리를 실제로 언제 어떻게 놓아주는지는 QEMU/KVM 버전과 backing 종류 및 설정에 따라 달라질 수 있다. 근거 문서는 그 동작을 하나로 단정하지 않았고 이 환경에서도 확인하지 않았다. 이 실험대의 버전은 §197 이 적어 두었다 — QEMU 11.1.1 과 libvirt 12.7.0, 커널 7.2.2-arch1-1 이다. 버전은 정해졌지만 그 위에서 호스트가 언제 놓아주는지를 잰 기록도, backing 설정을 읽은 기록도 없다.

virtio-balloon Driver 와 virtqueue, QEMU virtio-balloon Device, Host Memory Management 네 참여자 사이를 여섯 개의 메시지가 오가는 순서도. 1번부터 3번까지는 Host 쪽에서 정한 balloon target 조정이 QEMU device 와 virtqueue 를 지나 VM Boundary 를 넘어 Guest kernel 의 driver 에 닿는 방향이고, 4번부터 6번까지는 driver 가 확보한 Guest page 가 같은 경계를 반대로 건너 Host 의 회수 가능 backing 이 되는 방향이다.

Deflate — target 을 줄이면 되돌아온다

호스트가 게스트에게 메모리를 다시 내줄 수 있으면 balloon target 을 줄인다. 그러면 게스트 balloon 드라이버가 붙잡고 있던 페이지를 반환하고 게스트가 쓸 수 있는 메모리가 늘어난다.

호스트가 balloon target 을 게스트가 쓸 수 있는 메모리는
올린다 (Inflate) 감소
내린다 (Deflate) 증가

과도한 inflate 가 게스트를 압박한다

게스트 애플리케이션이 실제로 쓰는 메모리가 큰데 balloon 을 과도하게 부풀리면, 게스트가 쓸 수 있는 메모리가 줄면서 게스트 안에 메모리 압박이 생긴다. 그러면 게스트 안에서 회수가 돌고 페이지 캐시가 회수되고 게스트 스왑이 시작되며, 심하면 게스트 OOM(Out Of Memory)까지 간다.

호스트 RAM 을 확보하려는 조치가 게스트의 스토리지 I/O 와 애플리케이션 지연을 늘릴 수 있다는 뜻이다. 회수한 만큼 호스트가 편해지는 대신 게스트가 그 압박을 받으므로, balloon target 을 어디까지 올릴지는 게스트가 실제로 쓰는 메모리를 보고 정한다.

ballooning 과 memory hotplug 는 같은 것이 아니다

ballooning 은 게스트에 이미 설정된 메모리 용량 안에서 호스트와 게스트 사이의 쓸 수 있는 양을 회수하고 반환한다. 용량 자체는 그대로다. memory hotplug 는 기존 게스트 RAM 에 메모리 장치나 영역을 더해 게스트가 늘어난 용량을 인식하게 한다. 하나는 이미 준 용량 안에서 쓸 수 있는 양을 옮기고 다른 하나는 용량을 더한다.

현대 가상화에는 virtio-mem 같은 다른 동적 메모리 관리 방식도 있어서, 가상 머신의 동적 메모리 관리를 ballooning 하나로 일반화하지 않는다. 근거 문서에 있는 것은 그런 방식이 존재한다는 사실까지다.

이 실험대에서 할당이 줄어 있던 값 하나

앞에서 적었듯 balloon 장치가 붙어 있는지를 설정으로 확인한 기록은 아직 없다. 대신 값이 하나 나와 있다 — §198 이 k3s 게스트 두 대에 virsh dommemstat 을 돌려 받은 출력이다.

kc-lab-1   할당 5120MB  실사용 353MB
kc-lab-2   할당 3120MB  실사용 301MB

kc-lab-2virt-install --memory 4096 으로 만들었는데 현재 할당이 3120MB 로 나왔다. §198 은 이것을 virtio-balloon 이 회수해 간 것으로 보인다고 적고 거기서 멈췄다. 같은 절은 dommemstatactual 이 현재 할당이지 선언한 상한이 아니라고 덧붙였다. 상한은 virsh dominfoMax memory 에 있는데, 이 실험대는 그 두 값을 나란히 찍어 보지 않았다.

§198 은 이 값이 언제의 값인지도 함께 적었다 — 「다만 이것은 지금 k3s 만 떠 있어서다」이고, Keycloak 2 파드와 PostgreSQL, Redis, Prometheus 가 올라간 뒤의 값은 미측정이다. 게스트 세 대 가운데 kc-lab-edge 는 이 측정에 들어 있지 않다.

이 숫자로 알 수 있는 것은 kc-lab-2 의 현재 할당이 선언값보다 작다는 것까지다. 그 차이가 balloon 회수 때문인지와 이 가상 머신들에 장치가 실제로 붙어 있는지는 설정과 게스트 쪽 드라이버 상태를 읽어야 갈린다.

근거 문서가 번호를 붙여 둔 문장

근거 문서는 이 장치에서 고정한 문장에 번호를 붙여 두었다. 실험 기록에서 어느 문장을 확인했는지 가리킬 때 이 번호를 쓴다.

번호 근거 문서가 고정한 문장
CLAIM-MEM-15 virtio-balloon은 Guest와 Host가 memory 회수/반환에 협력하기 위한 가상 장치이며 RAM 자체를 제공하는 장치는 아니다.
CLAIM-MEM-16 Balloon inflate가 과도하면 Guest reclaim/swap/OOM을 유발할 수 있다.

이 문서가 확정하지 않는 것

이 글이 확정하는 것은 balloon 이 어떤 구조로 어느 방향으로 동작하는가까지다. 이 테스트 서버에서 잰 값 가운데 여기 쓴 것은 §198 의 할당과 실사용뿐이고, balloon 을 움직여 본 적은 없다.

이 프로젝트의 가상 머신에 virtio-balloon 이 붙어 있는지를 설정으로 확인한 기록이 없다. 앞 절의 §198 실측은 inflate 방향과 들어맞지만 근거 문서도 그것을 단정하지 않았다. libvirt 설정에 balloon 관련 요소가 있는지, 있다면 게스트 안에서 그 드라이버가 어떤 이름으로 올라와 있는지를 먼저 확인해야 한다. 장치가 없으면 balloon target 실험은 성립하지 않는다.

값을 한 단계 바꿨을 때 게스트가 쓸 수 있는 메모리가 얼마나 움직이는지, 그 반영이 즉시인지 늦는지, 어느 값부터 게스트 안에서 회수와 스왑이 시작되는지도 재지 않았다. 호스트가 그 메모리를 언제 놓아주는지가 QEMU 11.1.1 과 이 backing 설정에서 어떻게 되는지도 마찬가지다. 두 확인은 각각 열린 질문으로 두었고 관계에 걸어 두었다.