Files
document-haness/docs/virtualization/tech-log-studio/cpu-virtualization/question/question-virtualization-layer-saturation-during-refresh.md
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

145 lines
9.2 KiB
Markdown

---
id: da3a7b56-5691-4a9f-90c5-3a1a5d0f0013
kind: QUESTION
slug: virtualization-layer-saturation-during-refresh
title: Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가
topic: cpu-virtualization
topicName: CPU 가상화
project: virtualization
status: 초안
questionStatus: OPEN
studio: "https://hyeonworks.com/studio/documents/da3a7b56-5691-4a9f-90c5-3a1a5d0f0013/edit"
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
source:
- final/document.md#20-이-concept에서-파생되는-open-question-oq-2
- final/document.md#16-현재-keycloak-k3s-실험과의-관계
- final/document.md#26-현재-keycloak-실험에서-cpu-문제를-오판하지-않기-위한-기준
---
# Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가
§20 이 함께 관찰하라고 든 다섯 지표를 아직 한 번도 같이 찍지 않았다. Keycloak refresh 경쟁 실험은 가상 머신 두 대 위에서 돌기 때문에, 원래 검증하려던 구조 아래에 KVM 계층이 하나 더 붙는다. 실험 구간의 지연을 refresh 경쟁으로 읽어도 되는지는 같은 구간의 호스트 CPU 와 steal time 이 갈라 준다.
## 관계
- **KVM 에서 vCPU 가 물리 CPU 에서 실행되기까지**
게스트 안의 지연이 가상화 계층까지 내려가는 경로를 이 개념이 설명한다.
- **가상 머신 두 대에 동시에 부하를 주면 이 호스트에서 vCPU 경쟁이 실제로 생기는가**
경쟁이 생길 수 있는 구성인지를 먼저 묻는다. 그쪽이 닫히면 여기서 기준값을 다시 만들지 않아도 된다.
- **cgroup CPU 제한과 호스트 vCPU 경쟁을 지표로 가를 수 있는가**
§26 이 나눈 여섯 경계 가운데 K3s 와 Virtualization 을 어떻게 가르는지를 따로 묻는다.
## 사실
§16 이 그린 원래 검증 대상 구조
Client
Nginx / Load Balancer
K3s
Keycloak Node 1 · Keycloak Node 2
Session / Token State
PostgreSQL · Redis
테스트 환경에서는 이 구조 아래에 KVM 계층이 추가된다 : §16
Physical Host 아래에 Host Nginx 와 가상 머신 두 대가 있고 가상 머신마다 K3s 노드와 Keycloak 이 돈다 : §16
§16 이 테스트 결과를 해석할 때 분리하라고 든 원인 일곱
Keycloak refresh/session 동시성
PostgreSQL contention/locking
Redis 상태 관리
K3s resource scheduling
VM vCPU scheduling
Host CPU saturation
Nginx/LB
§16 은 KVM CPU 가상화를 이해하는 목적을 이렇게 적었다.
Keycloak 멀티 노드 실험에서 발생한 지연이나 실패가 application/storage 문제인지, VM/Host 자원 문제인지 구분할 수 있도록 실험 기반을 이해하기 위해서다.
§26 은 같은 원인들을 여섯 경계로 다시 나눈다.
Application / Auth : Refresh Token 경쟁 · Session 상태 경쟁 · Keycloak 내부 처리
Storage : PostgreSQL lock / latency · Redis latency / consistency
K3s : Pod CPU throttling · Pod scheduling/resource limit
Guest : Guest CPU saturation
Virtualization : vCPU scheduling · Steal time · VM Exit overhead
Host : CPU contention · CPU overcommit · Host saturation
§26 은 refresh 경쟁을 검증하는 첫 실험에서 가능하면 CPU 자원을 여유 있게 유지하고, 그 상태에서 같은 세션과 같은 refresh token 에 대한 동시 요청을 만들어 동시성 문제를 먼저 확인하라고 적는다. 트래픽을 늘려 CPU/DB/Redis/K3s 자원 포화를 관찰하는 것은 별도의 부하·스트레스 Case 로 나눈다.
§13 은 steal time 을 게스트 vCPU 에 실행할 작업이 있는데 다른 작업 때문에 즉시 실행되지 못하는 상황을 가리키는 단서로 적었다.
§20 이 refresh 경쟁 실험 중 동시에 관찰하라고 든 다섯
Host CPU
Guest CPU
steal time
Keycloak latency
DB/Redis latency
§20 은 그 목적이 refresh 경쟁과 호스트 자원 경쟁을 분리하는 것이라고 밝힌다.
§197 은 2026-09-10 에 이 호스트에서 논리 코어 8 과 Mem: 11648 을 받아 적었고, 실험대가 잡은 vCPU 를 2 + 2 + 1 = 5 로 적었다. 실험 구간의 값은 아직 없다.
## 가정
refresh 경쟁 실험이 Keycloak latency 와 DB/Redis latency 를 이미 재고 있다고 전제한다. 그 실험이 어떤 값을 어떤 주기로 내는지는 이 근거 문서에 적혀 있지 않다.
기준값을 찍는 구간과 실험 구간 사이에 호스트의 다른 작업이 달라지지 않는다.
§211 은 2026-09-03 과 2026-09-10 사이에 호스트 RAM 이 물리 증설되고 게스트가 두 대에서 세 대로 늘었다고 적으면서, 두 값이 어긋나 보이면 「틀린 것이 아니라 다른 날이다」라고 못 박았다. 기준값과 실험 구간은 같은 날 같은 구성에서 받아야 이 전제가 선다.
다섯 지표의 시각을 맞춰 읽을 수 있다고 전제한다. 호스트 쪽과 게스트 쪽 시계가 어긋나면 부하 구간을 겹쳐 놓을 수 없기 때문이다.
§26 이 말한 「CPU 자원을 여유 있게 유지한」 상태를 이 호스트에서 만들 수 있다.
## 미지수
실험을 걸기 전 다섯 지표의 기준값.
실험 구간의 호스트 CPU 와 게스트 CPU, 그리고 각 게스트의 steal time.
같은 구간의 Keycloak latency 와 DB/Redis latency.
가상화 쪽 지표가 얼마나 움직여야 실험 결과를 다르게 읽어야 하는지. 그 문턱을 아직 정하지 않았다.
두 가상 머신이 같은 호스트에 있으므로 한쪽 Keycloak 노드에 몰린 요청이 다른 쪽 게스트의 steal time 을 올리는지.
## 제약
§26 이 첫 실험을 CPU 여유 상태로 못박기 때문에, 이 질문은 실험 조건을 바꾸지 않고 관찰 지표만 덧붙여 답해야 한다. §17.1 이 refresh token 경쟁을 확인하는 데 반드시 호스트 CPU 를 100% 까지 밀 필요는 없다고 적었으므로, 실험을 그대로 두고 관찰만 덧붙이는 것이 §26 의 조건과도 어긋나지 않는다.
이 호스트에서 그 다섯 지표를 잰 값이 없어 기준값부터 만들어야 한다. 실험 구간의 값만 있으면 그 값이 평소 값인지 실험 때문에 오른 값인지 갈리지 않는다.
§22 의 Claim 12·13 은 이 환경에서 실제로 그러한지를 주장하는 것이라, 재기 전에는 Case 도 Question 도 되지 않는다고 보고 그대로 두었다. 이 물음을 그와 갈라 먼저 올린 것은 아는 것과 모르는 것이 실험 전에도 갈리기 때문이다.
§16 은 CPU 가상화가 refresh token 경쟁의 원인은 아니라고 적는다. 여기서 「포화되지 않았다」가 나와도 refresh 경쟁 실험의 결론이 바뀌지는 않고, 그 결론을 애플리케이션·저장소 쪽으로 읽어도 되는지만 갈린다.
§20 이 든 다섯 가운데 Keycloak latency 와 DB/Redis latency 는 실험 쪽 도구가 낸다. 가상화 쪽에서 새로 만들 값은 Host CPU · Guest CPU · steal time 셋이다.
## 선택지
### 1. 실험을 그대로 두고 관찰만 덧붙인다
§26 이 첫 실험의 CPU 조건을 정해 두었으므로 실험 자체는 건드리지 않는다. 같은 실험을 돌리면서 호스트 쪽 QEMU vCPU 스레드 사용량과 게스트 쪽 %st 만 함께 기록한다. 이 방법으로는 이번 실험 구간에서 가상화 계층이 움직였는지 하나만 알 수 있다.
### 2. 실험 직전 구간을 기준값으로 따로 찍는다
부하를 걸기 전 같은 다섯 지표를 한 번 찍어 두면 실험 구간의 값을 견줄 대상이 생긴다. 기준값 없이 실험 구간만 찍으면 steal time 이 어떤 값으로 나오든 그것이 평소 값인지 실험 때문에 오른 값인지 판정할 수 없다.
### 3. 여섯 경계 가운데 가상화 쪽 둘만 먼저 잰다
§26 은 Application / Auth 부터 Host 까지 여섯 경계를 든다. 여섯을 한 번에 분리하려면 경계마다 지표를 붙여야 하는데, 이 질문은 Virtualization 과 Host 두 경계가 실험 결과를 흔들었는지만 묻는다. 나머지 넷은 실험 쪽 기록을 그대로 쓰고 이 둘만 새로 잰다.
### 4. 제외 — CPU 를 일부러 포화시켜 견준다
포화 구간과 여유 구간을 나란히 놓으면 가상화 계층이 결과를 얼마나 흔드는지 바로 보인다. 그러나 §26 이 첫 refresh 실험을 CPU 여유 상태로 정해 두어서 같은 실험 안에서는 할 수 없다. 별도의 부하·스트레스 Case 로 뺀다.
## 다음 검증
1. 실험을 걸기 전 §20 이 든 다섯 지표를 한 번 찍어 기준값으로 둔다.
2. refresh 경쟁 실험을 돌리면서 같은 다섯을 같은 시각에 기록한다. 게스트의 steal time 은 top (§14.8), 호스트 쪽 QEMU vCPU 스레드는 ps -eLo pid,tid,psr,pcpu,comm | grep qemu (§14.7) 로 본다.
3. Keycloak 과 DB/Redis latency 는 실험이 이미 재는 값을 그대로 쓴다.
닫는 조건 : 실험 구간의 호스트 CPU 와 steal time 이 기준값과 다르지 않으면, 그 실험 결과를 애플리케이션·저장소 문제로 읽어도 된다고 적고 닫는다. 둘 중 하나라도 움직이면 §26 의 여섯 경계를 분리해 다시 재고, refresh 경쟁 실험을 CPU 여유 상태에서 따로 돌릴지는 Decision 으로 넘긴다.