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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d473609e0a
commit
2109f726fe
+6
-6
@@ -50,7 +50,7 @@ source:
|
||||
|
||||
# Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge
|
||||
|
||||
가상 머신 안의 Keycloak 이 HTTP 요청 하나를 받으려면 그 패킷이 먼저 호스트의 물리 NIC 에 닿아야 한다. 거기서 Linux Bridge 와 TAP, vhost-net, virtqueue 를 지나 게스트 커널의 TCP/IP 스택까지 올라온다. virtio-net 은 그 경로 어딘가에 놓인 프로그램 하나가 아니다. 게스트 쪽 프런트엔드 드라이버와 호스트 쪽 백엔드를 잇는 I/O 계약이고, 그 백엔드 자리는 QEMU 사용자 공간이 맡을 수도 호스트 커널의 vhost-net 이 맡을 수도 있다. 가상 머신 두 대에서 Keycloak 멀티 노드 실험을 돌리면 요청이 느려지거나 아예 닿지 않는 일이 생긴다. 이 경로를 알아 두면 그 증상을 애플리케이션·저장소 쪽 문제와 네트워크 가상화 계층 문제로 갈라 볼 수 있다.
|
||||
가상 머신 안의 Keycloak 이 HTTP 요청 하나를 받으려면 그 패킷이 호스트의 물리 NIC 에서 Linux Bridge 와 TAP, vhost-net, virtqueue 를 지나 게스트 커널의 TCP/IP 스택까지 올라와야 한다. virtio-net 은 그 경로에 놓인 프로그램 하나가 아니라 게스트 쪽 프런트엔드 드라이버와 호스트 쪽 백엔드를 잇는 I/O 계약이고, 그 백엔드 자리는 QEMU 사용자 공간이 맡을 수도 호스트 커널의 vhost-net 이 맡을 수도 있다. 가상 머신 두 대로 Keycloak 멀티 노드 실험을 돌리다 요청이 느려지거나 아예 닿지 않으면, 이 경로를 알아야 그 증상을 애플리케이션·저장소 쪽 문제와 네트워크 가상화 계층 문제로 갈라 볼 수 있다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -59,7 +59,7 @@ source:
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
이 경로가 실험의 여러 노드에 공유되기 때문에 생기는 오귀속을 막는 기준이다.
|
||||
- **이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가**
|
||||
이 글은 Bridge 와 라우팅, NAT 가 각각 무엇을 하는지까지만 적었다. 이 호스트가 그중 무엇으로 구성돼 있는지는 확인하지 않았다.
|
||||
이 글은 Bridge 와 라우팅, NAT 가 각각 무엇을 하는지까지만 적었다. 이 호스트가 NAT 로 돈다는 것은 실험대를 세운 기록이 나중에 적었고, 그 구성에서 프레임이 어느 계층을 지나는지는 그 물음이 받는다.
|
||||
- **VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가**
|
||||
TAP 이 게스트의 이더넷 프레임과 호스트 네트워크를 잇는 접점이라는 설명이 이 물음의 전제다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
@@ -254,7 +254,7 @@ Intel Physical NIC
|
||||
|
||||
네트워크 성능에서 큰 비용 하나가 패킷 데이터를 복사하는 일이다. virtio 와 virtqueue, vhost 구조는 버퍼 디스크립터를 써서 불필요한 복사와 컨텍스트 스위치를 줄이는 방향으로 설계돼 있다. 다만 이것을 항상 zero-copy 라고 일반화하지 않는다. 실제로 복사가 일어나는지는 커널 버전과 QEMU 버전, vhost 설정, 오프로드, NIC 의 기능, 패킷이 지나는 경로, GSO/GRO/TSO 에 따라 달라질 수 있다.
|
||||
|
||||
게스트와 호스트는 큐에 새 패킷이나 버퍼가 들어왔다는 것을 서로 알려야 한다. 게스트가 보낼 때는 virtqueue 에 디스크립터를 등록하고 호스트 백엔드에 알리면 백엔드가 처리하고, 받을 때는 호스트가 virtqueue 에 버퍼를 반영하고 게스트에 알리면 게스트 드라이버가 처리한다. 패킷마다 인터럽트와 알림이 지나치게 많이 발생하면 오버헤드가 커지기 때문에 batching 과 interrupt moderation, queueing 을 쓴다.
|
||||
게스트와 호스트는 큐에 새 패킷이나 버퍼가 들어왔다는 것을 서로 알려야 한다. 게스트가 보낼 때는 virtqueue 에 디스크립터를 등록하고 호스트 백엔드에 알리면 백엔드가 처리한다. 받을 때는 호스트가 virtqueue 에 버퍼를 반영하고 게스트에 알리면 게스트 드라이버가 처리한다. 패킷마다 인터럽트와 알림이 지나치게 많이 발생하면 오버헤드가 커지기 때문에 batching 과 interrupt moderation, queueing 을 쓴다.
|
||||
|
||||
큐를 하나만 쓰면 특정 vCPU 나 처리 경로에 부하가 몰릴 수 있다. virtio-net 은 multi-queue 를 쓸 수 있고, RX 큐를 vCPU 마다 하나씩 붙여 패킷 처리를 병렬로 돌리고 큐 하나에 몰리는 병목을 완화한다. 효과는 부하의 성격과 CPU affinity, IRQ(Interrupt Request) 배치, 큐 설정에 따라 달라진다.
|
||||
|
||||
@@ -328,11 +328,11 @@ sudo tcpdump -ni <guest-interface>
|
||||
|
||||
## 이 문서가 확인하지 않은 것
|
||||
|
||||
이 호스트에서 잰 값은 하나도 없다. 위의 명령들은 무엇을 볼 수 있는지 적어 둔 목록이고 아직 실행하지 않았다. 이 가상 머신들의 네트워크가 Bridge 인지 NAT 인지 라우팅인지, VM1 과 VM2 의 TAP 또는 vnet 인터페이스가 무엇인지를 아직 확인하지 않았다. vhost-net 이 실제로 데이터 경로를 맡고 있는지, multi-queue 가 켜져 있는지도 마찬가지다. 그래서 이 글은 「이 구조에서는 이렇게 동작한다」까지만 말하고 「이 서버가 그 구조다」라고는 말하지 않는다. QEMU 백엔드와 vhost-net 의 성능 차이가 이 호스트에서 관찰되는지, Keycloak 부하 시험에서 네트워크 가상화가 지연에 영향을 줄 만큼 호스트 CPU 를 쓰는지도 같은 상태다.
|
||||
위의 명령을 이 호스트에서 돌린 출력은 대부분 없다. 네트워크 구성만은 나중에 갈렸다. 실험대를 세운 기록이 이 호스트에 이더넷 없이 WiFi 만 있어 브리지를 못 쓰고 libvirt NAT 를 골랐다고 적었고, 게스트는 그 NAT 가 만드는 브리지에 붙는다. 브리지를 막은 것은 무선 링크다. 802.11 데이터 프레임은 기본적으로 주소 필드가 3개라, AP(Access Point, 무선 접속 장치) 는 연결된 단말의 MAC 만 알고 있고 그 단말이 자기 것이 아닌 출발지 MAC 을 단 프레임을 보내면 버린다. 브리지된 가상 머신이 보내는 것이 정확히 그런 프레임이다. 우회로 4-address 모드(WDS) 가 있지만 AP 와 클라이언트 드라이버가 모두 지원해야 하고 실제로는 거의 지원되지 않아, 그 기록은 현실적인 우회로 USB 이더넷 어댑터를 들었다. 같은 기록이 NAT 와 브리지와 macvtap 을 견준 표에서 뒤의 둘은 나란히 WiFi 라 불가다. TAP 또는 vnet 인터페이스의 이름과 vhost-net 이 실제로 데이터 경로를 맡는지, multi-queue 가 켜져 있는지는 아직 읽지 않았다. 그래서 이 글은 「이 구조에서는 이렇게 동작한다」까지만 말하고 「이 서버가 그 구조다」라고는 말하지 않는다. QEMU 백엔드와 vhost-net 의 성능 차이가 이 호스트에서 관찰되는지, Keycloak 부하 시험에서 네트워크 가상화가 지연에 영향을 줄 만큼 호스트 CPU 를 쓰는지도 재지 않았다.
|
||||
|
||||
이 문서가 Keycloak 테스트 환경에 얹어 그린 경로도 마찬가지다. 호스트 Nginx 아래에 가상 머신 두 대가 있고 그 안에서 K3s 와 Keycloak 노드가 돈다는 앞부분은 실험 구성으로 밝혀 두었다. 그 아래를 브리지와 라우팅·NAT, TAP, vhost-net, virtqueue 로 펼친 뒷부분은 네트워크 구성과 TAP 이름, vhost-net 사용 여부를 확인하기 전의 가정이다. 이 환경이 실제로 그렇다는 주장이어서, 재기 전에는 이 글의 그림으로 올리지 않고 근거가 모자란 후보로 남겼다.
|
||||
이 문서가 Keycloak 테스트 환경에 얹어 그린 경로는 그대로 쓰지 못한다. 그 그림은 호스트의 nginx 가 가상 머신 두 대로 프록시하는 모양인데, 실험대는 그 뒤에 nginx 를 게스트 한 대로 옮기고 호스트에는 커널 DNAT(Destination NAT, 목적지 주소 변환) 만 두었다. 게스트도 둘이 아니라 셋이고, 엣지 한 대와 K3s 노드 두 대다. 브리지와 라우팅·NAT, TAP, vhost-net, virtqueue 로 펼친 뒷부분은 TAP 이름과 vhost-net 사용 여부를 확인하기 전의 가정이어서, 재기 전에는 이 글의 그림으로 올리지 않는다.
|
||||
|
||||
여기 적은 것은 가장 기본적인 조합 안에서만 성립한다. 실제 환경은 Bridge 와 NAT, routed network, macvtap, SR-IOV, VFIO(Virtual Function I/O) passthrough, Open vSwitch, Kubernetes CNI(Container Network Interface) 에 따라 달라질 수 있다. 이 문서에 커널과 QEMU, libvirt 버전이 한 번도 적혀 있지 않아서 특정 버전에 고정하지도 못한다. 복사 동작 하나만 봐도 커널 버전과 QEMU 버전, vhost 설정, 오프로드, NIC 의 기능에 따라 달라지므로, 버전이 바뀌어 이 서술이 낡았는지는 위 확인 명령을 실제 호스트에서 돌릴 때 드러난다.
|
||||
여기 적은 것은 가장 기본적인 조합 안에서만 성립한다. 실제 환경은 Bridge 와 NAT, routed network, macvtap, SR-IOV, VFIO(Virtual Function I/O) passthrough, Open vSwitch, Kubernetes CNI(Container Network Interface) 에 따라 달라질 수 있다. 이 서술 자체는 판 번호를 달고 있지 않다. 실험대를 잰 기록이 그 호스트의 libvirt 12.7.0 과 QEMU 11.1.1, 커널 7.2.2-arch1-1 을 적었다. 여기 적은 동작은 그 판에서 읽은 것이 아니라 구조를 서술한 것이라, 세 값은 확인할 때의 조건으로 쓴다. 복사 동작 하나만 봐도 커널 버전과 QEMU 버전, vhost 설정, 오프로드, NIC 의 기능에 따라 달라지므로, 버전이 바뀌어 이 서술이 낡았는지는 위 확인 명령을 실제 호스트에서 돌릴 때 드러난다.
|
||||
|
||||
가상 머신 위에 올린 K3s 안쪽도 이 문서 밖이다. K3s 의 CNI 와 Service, Pod 네트워크는 이 네트워크 가상화 위에 더해지는 계층이라 따로 분석한다.
|
||||
|
||||
|
||||
+27
-12
@@ -20,7 +20,7 @@ source:
|
||||
|
||||
# Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가
|
||||
|
||||
§116 은 이 테스트 환경의 요청 경로를 클라이언트에서 Keycloak 까지 한 줄로 그렸다. 가상 머신 네트워크까지 펼치면 물리 NIC 에서 브리지와 TAP 을 지나 vhost-net 과 virtqueue 를 거쳐 게스트 안으로 들어간다고 적었다. 그 펼친 그림은 §94 가 기준으로 삼은 구조를 이 환경에 얹은 것이고, 이 호스트에서 패킷을 잡아 본 결과가 아니다. 여기서 묻는 것은 호스트 Nginx 를 지난 요청이 실제로 어느 브리지와 어느 TAP 을 거쳐 어느 가상 머신으로 들어가는가 하나다.
|
||||
경로가 한 번 바뀌었다. §179 는 nginx 를 물리 호스트에서 엣지 게스트로 옮기고 호스트에는 커널 DNAT(Destination NAT, 목적지 주소 변환) 만 두었다고 적었다. §116 이 그린 그림은 옮기기 전 모양이고, 네 지점에 tcpdump 를 걸어 본 기록은 아직 없다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -42,7 +42,7 @@ source:
|
||||
- §116 이 가상 머신 네트워크까지 펼친 경로
|
||||
Client → Physical NIC → Host Network Stack / Bridge / Route / NAT → TAP(vm1) / TAP(vm2) → vhost-net → virtqueue → virtio-net → Guest Network Stack → K3s networking → Keycloak
|
||||
- §116 은 그 뒤에 K3s 내부의 CNI · Service · Pod network 가 추가되므로 별도 계층으로 분석한다고 적었다.
|
||||
- §94 는 이 문서가 기준으로 삼은 구조를 virtio-net + vhost-net + TAP + Linux Bridge 로 놓고 수신 방향과 송신 방향을 각각 그렸으며, 실제 환경이 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 밝혔다.
|
||||
- §94 는 이 문서가 기준으로 삼은 구조를 virtio-net + vhost-net + TAP + Linux Bridge 로 놓고 수신 방향과 송신 방향을 각각 그렸다. 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 밝혔다.
|
||||
- §125 는 같은 경로를 vhost-net 을 쓸 때와 QEMU backend 를 쓸 때로 나눠 다시 그렸다. 두 그림은 TAP 다음이 vhost-net 인지 QEMU virtio backend 인지에서 갈리고 나머지 구간은 같다.
|
||||
- §119 는 경로를 확인하는 방법으로 호스트의 physical NIC · bridge · tap 또는 vnet 세 곳과 게스트의 guest interface 한 곳에 sudo tcpdump -ni 를 걸고, 어디까지 보이는지로 의심 구간을 좁히라고 적었다.
|
||||
- §119 가 든 판정 예 셋
|
||||
@@ -50,20 +50,34 @@ source:
|
||||
TAP O · Guest NIC X : virtio/vhost/Guest NIC 계층을 의심한다
|
||||
Guest NIC O · Socket X : Guest routing/firewall/listen 상태를 의심한다
|
||||
- §122 OQ-6 은 Host NIC · Bridge · TAP · Guest NIC 에서 tcpdump 로 추적한다고만 적었다. 어느 이름의 인터페이스인지는 적혀 있지 않다.
|
||||
- §116 의 그림은 앞부분과 뒷부분의 근거가 다르다. 호스트 Nginx 아래에 가상 머신 두 대가 있고 그 안에서 K3s 와 Keycloak 노드가 돈다는 앞부분은 §89 가 밝힌 실험 구성이고, 브리지와 라우팅·NAT, TAP, vhost-net 으로 펼친 뒷부분은 OQ-1 과 OQ-2, OQ-3 를 확인하기 전의 가정이다.
|
||||
- 이 호스트에서 패킷을 잡아 본 기록이 없다. §116 이 펼친 경로는 확인한 결과가 아니라 §94 의 기준 구조를 이 환경에 얹은 그림이다.
|
||||
- §116 의 그림은 앞부분과 뒷부분의 근거가 다르다. 호스트 Nginx 아래에 가상 머신 두 대가 있고 그 안에서 K3s 와 Keycloak 노드가 돈다는 앞부분은 §89 가 밝힌 실험 구성이다. 브리지와 라우팅·NAT, TAP, vhost-net 으로 펼친 뒷부분은 OQ-1 과 OQ-2, OQ-3 를 확인하기 전의 가정이다.
|
||||
- §179 와 §254 는 같은 nginx 를 물리 호스트에서 엣지 게스트로 옮겼다고 적고 전후를 나란히 그렸다.
|
||||
전 : `tailnet:443` → 호스트 nginx → Traefik(게스트 .11/.12)
|
||||
후 : `tailnet:443` → 호스트 커널 DNAT → 엣지 nginx(.10) → Traefik(.11/.12)
|
||||
- §179 는 그렇게 옮겨도 L7 홉 수는 2홉 그대로라고 관측으로 적었다. 늘어난 것은 커널이 하는 L4 전달 한 번이다. 지금 호스트에는 `:443` 을 듣는 리스너가 없다.
|
||||
- §179 는 옮긴 이유를 성능이 아니라 더러워지는 층의 격리로 적었다. nginx 설정과 인증서, certbot, deploy 훅은 자주 갈아엎는 것들인데 호스트에 있으면 초기화가 불가능하고, 엣지 장애 실험이 SSH 까지 위험하게 만든다. 그 대가로 일곱 가지가 새로 필요해졌고 §179 는 그중 DNAT 와 libvirt 방화벽 구멍 둘을 이 이동의 본질로 꼽았다. 그 둘을 본질로 본 것은 추론이라고 밝혔다.
|
||||
- §254 는 호스트에서 게스트로 가는 요청이 OUTPUT 경로라 필터를 타지 않는다고 적었다. 밖에서 게스트로 들어오는 요청은 FORWARD 경로라 libvirt 의 guest_input 체인을 지난다.
|
||||
- §207 은 DNAT 파일에 forward 체인을 두지 않은 이유를 그 파일의 주석으로 적어 두었다. libvirt 의 guest_input 체인은 virbr0 으로 나가는 프레임을 reject 하며 끝난다. nftables 에서는 앞 base 체인의 accept 가 뒤 체인의 reject 를 멈추지 못하므로 구멍을 libvirt 체인 맨 앞에 뚫었고, 그래서 그 파일에 forward 체인이 없는 것은 실수가 아니다.
|
||||
- §207 은 이 DNAT 가 PREROUTING nat 에 있어 라우팅 결정보다 먼저 돌고 호스트의 로컬 소켓보다 이긴다고 적었다. 그래서 엣지를 띄운 채 전환하고, 되돌릴 때는 테이블 하나를 지운다.
|
||||
- §207 은 DNAT 만 하고 SNAT 는 하지 않는다고 적었다. 게스트의 기본 경로가 호스트여서 응답이 이 경로를 다시 지나고 conntrack 이 변환을 알아서 되돌린다. masquerade 를 붙이면 엣지가 모든 클라이언트를 192.168.122.1 로 보게 된다.
|
||||
- §208 은 DNAT 유닛의 ExecStartPost 앞에 붙은 하이픈을 설명했다. libvirt_network 테이블은 가상 네트워크가 떠 있어야 존재하는데, 부팅 순서에 따라 이 유닛이 먼저 돌 수 있다. 하이픈이 없으면 그때 규칙 삽입이 실패하면서 DNAT 까지 같이 안 실린다. 하이픈을 두면 DNAT 는 실리고 구멍만 빠진 상태가 되어 systemctl restart 한 번으로 다시 뚫린다.
|
||||
- §208 은 그 상태에서 유닛이 active 이고 아무 오류도 없다고 적고, 유닛이 active 라는 것은 DNAT 가 실렸다는 뜻이지 구멍이 뚫렸다는 뜻이 아니라고 추론으로 밝혔다. 그 상태를 실제로 재현해 보지는 않았다고 적혀 있다.
|
||||
- §180 은 구멍이 빠졌을 때의 출력을 관측으로 남겼다. 호스트에서 게스트 주소로 친 curl 은 404 였고, 밖에서 tailnet 주소로 친 curl 은 connection refused 였다. reject 규칙의 카운터는 packets 4 bytes 240 으로 밖에서 친 횟수와 맞았다.
|
||||
- §254 는 안쪽과 바깥쪽을 한 번씩 쳐서 같은 값이 나오는지 보는 확인을 적었다. 둘 다 404 면 경로가 이어진 것이고, 안쪽만 404 면 nginx 설치 · DNAT · libvirt 구멍 셋 가운데 하나가 빠진 것이다.
|
||||
- 이 호스트에서 계층마다 패킷을 잡아 본 기록은 없다. §116 이 펼친 경로는 확인한 결과가 아니라 §94 의 기준 구조를 이 환경에 얹은 그림이다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낼 수 있고, 그 요청이 두 가상 머신 가운데 어느 쪽으로 갔는지 확인하는 쪽이 알 수 있다고 본다.
|
||||
- 밖에서 tailnet 주소로 Keycloak 요청을 한 번 보낼 수 있고, 그 요청이 두 k3s 노드 가운데 어느 쪽으로 갔는지 확인하는 쪽이 알 수 있다고 본다.
|
||||
- 네 지점에 동시에 캡처를 걸어 둘 수 있다고 전제한다. 지점마다 따로 걸면 같은 요청을 본 것인지 갈리지 않는다.
|
||||
- §116 이 그린 구조가 지금 실험 환경과 같다고 전제한다. 가상 머신이 둘이고 각각 K3s 노드와 Keycloak 을 돌린다는 것까지가 근거 문서에 적힌 전부다.
|
||||
- §116 이 그린 뒷부분 가운데 TAP 다음 구간은 지금도 같다고 전제한다. 앞부분은 §179 가 바꿔 놓았고, TAP 뒤쪽 서술이 그 이동으로 달라졌는지는 적힌 것이 없다.
|
||||
- 오프로드 설정이 캡처하는 동안 바뀌지 않는다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 호스트 Nginx 를 지난 요청이 어느 브리지를 거치는지, 그 브리지에서 어느 TAP 으로 나가는지.
|
||||
- 그 TAP 이 두 가상 머신 가운데 어느 쪽의 인터페이스인지.
|
||||
- 밖에서 온 요청이 호스트 커널 DNAT 를 지난 뒤 virbr0 에서 어느 TAP 으로 나가 엣지 게스트로 들어가는지.
|
||||
- 엣지 nginx 가 k3s 노드로 넘기는 두 번째 홉이 virbr0 안에서 L2 로만 도는지, 호스트의 L3/Netfilter 를 지나는지. §119 의 네 지점은 밖에서 게스트로 들어오는 한 홉만 본다.
|
||||
- 그 두 번째 홉의 TAP 이 kc-lab-1 과 kc-lab-2 가운데 어느 쪽의 인터페이스인지.
|
||||
- 게스트 안의 인터페이스에서 같은 요청이 보이는지.
|
||||
- 네 지점의 결과가 §116 이 펼친 그림과 같은지, 다르다면 어느 지점부터 다른지.
|
||||
- 지금 오프로드 설정이 무엇인지. 캡처에서 본 패킷 크기와 체크섬을 wire 값으로 읽어도 되는지가 이것으로 갈린다.
|
||||
@@ -73,13 +87,14 @@ source:
|
||||
- 캡처 지점의 이름을 먼저 확정해야 한다. 어느 브리지와 어느 TAP 인지 모르면 tcpdump 를 걸 곳을 고르지 못한다. 그 이름은 네트워크 구성을 묻는 물음과 인터페이스를 묻는 물음이 댄다.
|
||||
- K3s 안에서 Keycloak Pod 까지 가는 구간은 이 물음이 닫는 범위 밖이다. §116 이 CNI · Service · Pod network 를 별도 계층으로 미뤄 두었다.
|
||||
- 요청이 중간 지점에서 끊기면 그것은 이 물음의 답이 아니라 장애다. §119 가 든 세 판정 예를 따라 의심 구간을 적고 계층별 캡처 기준으로 넘긴다.
|
||||
- 이 호스트에서 잰 값이 없어 §116 의 그림을 확인된 경로로 삼지 않는다. 이 환경이 실제로 그렇다는 주장이라 재기 전에는 Case 도 Concept 도 아니라고 보고 근거가 모자란 후보로 남겨 두었으며, OQ-1 과 OQ-2, OQ-3, OQ-6 이 답하면 다시 판정한다.
|
||||
- §116 의 그림은 엣지를 옮기기 전 모양이다. 지금 구성으로 캡처하면 호스트 nginx 였던 칸에 커널 DNAT 와 엣지 게스트가 들어가므로 캡처 지점이 그만큼 늘어난다.
|
||||
- 이 호스트에서 잰 값이 없어 §116 의 그림을 확인된 경로로 삼지 않는다. 이 환경이 실제로 그렇다는 주장이라 재기 전에는 Case 도 Concept 도 아니라고 보고 근거가 모자란 후보로 남겨 두었다. OQ-1 과 OQ-2, OQ-3, OQ-6 이 답하면 다시 판정한다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 네 지점에 한 번에 걸고 요청을 한 번 보낸다
|
||||
|
||||
§119 가 든 호스트 세 지점과 게스트 한 지점에 동시에 tcpdump 를 걸어 두고, 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낸다. 같은 요청 하나가 네 지점에서 각각 보이는지로 경로가 확정되기 때문에 실행이 한 번으로 끝난다.
|
||||
§119 가 든 호스트 세 지점과 게스트 한 지점에 동시에 tcpdump 를 걸어 두고, 밖에서 tailnet 주소로 Keycloak 요청을 한 번 보낸다. 같은 요청 하나가 네 지점에서 각각 보이는지로 경로가 확정되기 때문에 실행이 한 번으로 끝난다.
|
||||
|
||||
지점 이름을 미리 확정해 두어야 하고 네 곳을 동시에 열어 두어야 한다.
|
||||
|
||||
@@ -102,8 +117,8 @@ Nginx 가 어느 주소로 요청을 넘기는지 설정만 읽어도 어느 가
|
||||
## 다음 검증
|
||||
|
||||
1. 캡처를 걸 지점의 이름을 먼저 확정한다. 어느 브리지와 어느 TAP 인지는 네트워크 구성을 묻는 물음과 인터페이스를 묻는 물음이 답한다.
|
||||
2. 호스트에서 sudo tcpdump -ni 뒤에 physical NIC 이름 · bridge 이름 · tap 또는 vnet 이름을 넣어 세 곳에 걸고, 게스트에서 같은 명령을 guest interface 이름에 건다 (§122 OQ-6 · §119).
|
||||
3. 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낸다.
|
||||
2. 호스트에서 sudo tcpdump -ni 뒤에 physical NIC 이름 · bridge 이름 · tap 또는 vnet 이름을 넣어 세 곳에 걸고, 게스트에서 같은 명령을 guest interface 이름에 건다 (§122 OQ-6 · §119). 엣지 게스트의 TAP 과 k3s 노드의 TAP 을 함께 열어야 §179 가 적은 두 홉이 한 실행에서 잡힌다.
|
||||
3. 밖에서 tailnet 주소로 Keycloak 요청을 한 번 보낸다. §179 대로라면 그 요청은 호스트 커널 DNAT 를 지나 엣지 nginx 로 가고, 거기서 다시 k3s 노드로 넘어간다.
|
||||
4. 네 지점에서 그 요청이 보였는지를 §119 처럼 O 와 X 로 적는다.
|
||||
5. 캡처하는 동안의 오프로드 상태를 함께 적는다. §113 은 오프로드가 켜져 있으면 tcpdump 에서 보이는 패킷 크기나 체크섬이 실제 wire 에서 보이는 것과 다르게 보일 수 있다고 적었다.
|
||||
|
||||
|
||||
+9
-6
@@ -22,7 +22,7 @@ source:
|
||||
|
||||
# 이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가
|
||||
|
||||
§103 은 패킷이 TAP 에서 게스트로 올라오는 길을 두 가지로 갈라 적었다. QEMU 백엔드를 직접 쓰면 QEMU virtio backend 가 그 사이에 들어가고, vhost-net 을 쓰면 호스트 커널의 vhost-net 이 들어간다. 둘 중 어느 쪽이 이 호스트에서 돌고 있는지는 SSOT 에 없어서, 이 물음은 가상 머신 두 대 각각의 데이터 경로 백엔드를 확정한다.
|
||||
§103 은 패킷이 TAP 에서 게스트로 올라오는 길을 둘로 갈라 적었다. QEMU 백엔드를 쓰면 그 사이에 QEMU virtio backend 가 들어가고, vhost-net 을 쓰면 호스트 커널의 vhost-net 이 들어간다. 어느 쪽으로 도는지가 SSOT 에 없어서, 이 물음은 가상 머신 두 대의 데이터 경로 백엔드를 각각 확정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -43,15 +43,17 @@ source:
|
||||
vhost-net 을 쓰는 경우 : TAP → vhost-net → virtqueue → Guest
|
||||
- §104 는 TAP → vhost-net → QEMU → virtqueue 를 일반적인 경로로 그리면 안 된다고 못 박았다. vhost-net 의 목적 하나가 데이터 경로에서 QEMU 사용자 공간을 우회하는 것이기 때문이다.
|
||||
- §106 은 장치를 만들고 관리하는 주체와 실제로 패킷을 나르는 주체가 다르다는 것을 CPU 가상화에 견주어 적었다. QEMU 가 vCPU 를 만들어도 게스트의 ADD · MOV · SUB 를 전부 QEMU 가 실행하지는 않는다.
|
||||
- §107 은 QEMU 사용자 공간이 패킷마다 I/O 를 처리하면 호스트 커널과 사용자 공간 사이의 전환이 쌓이고, 초당 지나는 패킷이 많아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다고 적었다.
|
||||
- §107 은 QEMU 사용자 공간이 패킷마다 I/O 를 처리하면 호스트 커널과 사용자 공간 사이의 전환이 쌓인다고 적었다. 초당 지나는 패킷이 많아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다.
|
||||
- §108 은 vhost-net 을 써도 QEMU 가 남아서 맡는 일을 열거했다.
|
||||
VM lifecycle · Virtual hardware model · virtio device 생성
|
||||
Feature negotiation · Queue configuration · Backend 연결
|
||||
Device reset · Control/configuration handling
|
||||
- §117.4 는 초당 지나는 패킷이 많은데 QEMU 사용자 공간이 데이터 경로를 직접 처리하면 CPU 오버헤드가 커질 수 있다고 밝히고, 관찰 대상으로 QEMU CPU usage · vhost thread · packet rate · latency · context switch 를 들었다.
|
||||
- §117.4 는 초당 지나는 패킷이 많은데 QEMU 사용자 공간이 데이터 경로를 직접 처리하면 CPU 오버헤드가 커질 수 있다고 밝혔다. 관찰 대상으로는 QEMU CPU usage · vhost thread · packet rate · latency · context switch 를 들었다.
|
||||
- 확인 명령으로 §122 OQ-3 과 §118 이 든 것은 lsmod | grep vhost 하나다. §122 OQ-3 은 그 뒤에 QEMU arguments 와 libvirt domain XML 을 추가로 확인한다고 적었지만, 그 둘을 읽는 명령은 제3부 어디에도 적혀 있지 않다.
|
||||
- §123 은 개념에서 열린 질문을 거쳐 Case 로 가는 순서를 설명하면서 이 물음을 예로 들었다. 개념 자리에 「vhost-net은 QEMU userspace를 우회해 packet datapath를 처리할 수 있다」를, 물음 자리에 「현재 테스트 Host에서 vhost-net이 실제 활성화되어 있는가?」를 놓고, 답이 나오면 「libvirt/QEMU virtio-net backend 구성 확인 및 vhost-net 사용 검증」이 Case 가 된다고 적었다.
|
||||
- 이 호스트의 가상 머신 두 대가 어느 백엔드로 도는지, vhost 모듈이 올라와 있는지를 확인한 기록은 SSOT 에 없다.
|
||||
- §123 은 개념에서 열린 질문을 거쳐 Case 로 가는 순서를 설명하면서 이 물음을 예로 들었다. 개념 자리에 「vhost-net은 QEMU userspace를 우회해 packet datapath를 처리할 수 있다」를, 물음 자리에 「현재 테스트 Host에서 vhost-net이 실제 활성화되어 있는가?」를 놓았다. 답이 나오면 「libvirt/QEMU virtio-net backend 구성 확인 및 vhost-net 사용 검증」이 Case 가 된다고 적었다.
|
||||
- §178 은 이 실험대의 게스트를 3대로 적었고, §202 의 철거 출력이 그 domain 이름을 kc-lab-edge · kc-lab-1 · kc-lab-2 로 남겼다. §122 OQ-3 이 vm1 과 vm2 로 적은 두 대가 그중 k3s 노드 쪽이다.
|
||||
- §197 은 이 호스트의 판 번호를 실측으로 적었다. libvirt 12.7.0 · QEMU emulator version 11.1.1 · 커널 7.2.2-arch1-1 이다. 어느 backend 로 도는지는 그 줄에서 나오지 않는다.
|
||||
- 실험대를 적은 제5부부터 제9부까지 vhost 라는 낱말이 한 번도 나오지 않는다. 두 가상 머신이 어느 백엔드로 도는지도, vhost 모듈이 올라와 있는지도 확인한 기록이 SSOT 에 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
@@ -59,6 +61,7 @@ source:
|
||||
- 모듈이 올라와 있다는 것과 그 가상 머신이 그 백엔드를 쓴다는 것을 다른 사실로 놓고 물음을 세웠다. §103 은 백엔드 선택을 가상 머신의 구성으로 적었지 모듈 적재로 적지 않았다.
|
||||
- 두 가상 머신이 같은 백엔드를 쓴다고 전제하지 않는다. 가상 머신마다 따로 읽어 각각 적는다.
|
||||
- 읽는 동안 가상 머신을 재시작하지 않는다고 전제한다. 백엔드는 §105 가 적은 설정 경로에서 정해지므로 재시작하면 달라질 수 있다.
|
||||
- 게스트가 떠 있어야 QEMU 실행 인자를 읽는다. SSOT 가 마지막으로 적은 게스트 상태는 §202 의 철거이고 그 뒤 기록이 없다.
|
||||
|
||||
## 미지수
|
||||
|
||||
@@ -94,7 +97,7 @@ lsmod | grep vhost 로 호스트에 그 기능이 있는지 먼저 보고, 나
|
||||
## 다음 검증
|
||||
|
||||
1. lsmod | grep vhost 로 vhost 커널 모듈이 올라와 있는지 본다.
|
||||
2. 두 가상 머신의 libvirt domain 설정에서 인터페이스의 driver 지정을 읽는다. 무엇으로 읽었는지 명령을 함께 적는다.
|
||||
2. libvirt domain 설정에서 인터페이스의 driver 지정을 읽는다. domain 이름은 §202 가 적은 kc-lab-1 과 kc-lab-2 를 쓰고, 엣지 게스트 kc-lab-edge 도 같이 읽는다. 무엇으로 읽었는지 명령을 함께 적는다.
|
||||
3. 같은 가상 머신의 QEMU 실행 인자에서 백엔드 지정을 읽는다. 이것도 명령을 함께 적는다.
|
||||
4. 세 출력을 가상 머신별로 짝지어 적고 실행한 명령과 함께 증거로 남긴다.
|
||||
|
||||
|
||||
+10
-5
@@ -20,7 +20,7 @@ source:
|
||||
|
||||
# 부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가
|
||||
|
||||
§117.7 은 vhost-net 과 QEMU 스레드와 softirq 도 호스트 CPU 를 쓰므로, 네트워크 문제처럼 보이는 것이 CPU 스케줄링 문제일 수 있다고 적었다. 그 셋 가운데 QEMU 스레드와 게스트 쪽 지표는 CPU 가상화를 다루는 물음 둘이 이미 같은 실험 구간에서 재기로 해 두었다. 그래서 여기서는 그 둘이 보지 않는 vhost 커널 스레드와 softirq 만 본다. Keycloak 부하 시험 구간에서 이 둘이 호스트 CPU 를 얼마나 쓰는지, 그 사용량이 네트워크 지연과 같이 움직이는지로 물음을 좁힌다.
|
||||
§117.7 은 vhost-net 과 QEMU 스레드와 softirq 도 호스트 CPU 를 쓰므로, 네트워크 문제처럼 보이는 것이 CPU 스케줄링 문제일 수 있다고 적었다. 그 셋 가운데 QEMU 스레드와 게스트 쪽 지표는 CPU 가상화를 다루는 물음 둘이 같은 실험 구간에서 이미 재기로 해 두었다. 그래서 여기서는 Keycloak 부하 시험 구간에서 vhost 커널 스레드와 softirq 가 호스트 CPU 를 얼마나 쓰는지, 그 사용량이 네트워크 지연과 같이 움직이는지만 본다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -38,8 +38,8 @@ source:
|
||||
## 사실
|
||||
|
||||
- §117.7 은 vhost-net · QEMU thread · softirq 도 호스트 CPU 를 쓰고, 따라서 네트워크 문제처럼 보여도 CPU 스케줄링 문제일 수 있다고 적었다.
|
||||
- §107 은 QEMU 사용자 공간이 패킷마다 I/O 를 처리하면 호스트 커널과 사용자 공간을 오가는 전환 비용이 쌓이고, 초당 지나는 패킷이 많아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다고 밝혔다.
|
||||
- §111 은 게스트와 호스트가 큐에 새 패킷이나 버퍼가 있음을 서로 알려야 한다고 적고, 패킷마다 인터럽트나 알림이 지나치게 많이 발생하면 오버헤드가 커지므로 batching · interrupt moderation · queueing 이 중요하다고 밝혔다.
|
||||
- §107 은 QEMU 사용자 공간이 패킷마다 I/O 를 처리하면 호스트 커널과 사용자 공간을 오가는 전환 비용이 쌓인다고 밝혔다. 초당 지나는 패킷이 많아질수록 userspace/kernel transition · scheduling · copy · notification 비용이 커질 수 있다.
|
||||
- §111 은 게스트와 호스트가 큐에 새 패킷이나 버퍼가 있음을 서로 알려야 한다고 적었다. 패킷마다 인터럽트나 알림이 지나치게 많이 발생하면 오버헤드가 커지므로 batching · interrupt moderation · queueing 이 중요하다고 밝혔다.
|
||||
- §120 은 Refresh Token 경쟁 자체가 virtio-net 문제는 아니지만 클라이언트부터 PostgreSQL/Redis 까지 같은 경로를 공유하므로 네트워크 경로를 별도로 검증한다고 적었다.
|
||||
- §120 이 Refresh Token 경쟁이나 DB lock 으로 오해할 수 있다고 든 다섯
|
||||
Node1 요청만 지연
|
||||
@@ -57,6 +57,9 @@ source:
|
||||
- 이 여섯 가운데 QEMU CPU 와 Guest CPU 는 CPU 가상화 쪽 물음이 같은 실험 구간에서 이미 잰다. §14.7 이 호스트 스레드를 보는 명령으로 적은 ps -eLo pid,tid,psr,pcpu,comm | grep qemu 는 이름이 qemu 인 스레드만 걸러 내므로 vhost 커널 스레드는 그 출력에 나오지 않는다.
|
||||
- softirq 시간을 읽는 명령이 근거 문서에 없다. §118 의 네트워크 확인 명령 목록에도, CPU 관측 명령을 모아 둔 §14 에도 softirq 항목이 없고 이 낱말은 §117.7 과 §122 OQ-7 두 곳에만 나온다.
|
||||
- §108 은 vhost-net 을 써도 QEMU 가 VM lifecycle · virtio device 생성 · feature negotiation · queue configuration · backend 연결 · device reset 을 계속 맡는다고 적었다.
|
||||
- §179 는 nginx 를 물리 호스트에서 엣지 게스트로 옮기고 호스트에는 커널 DNAT 만 두었다고 관측으로 적었다. 지금 호스트에는 `:443` 을 듣는 리스너가 없다.
|
||||
- §197 과 §218 은 이 호스트의 논리 코어가 8 이고 게스트 셋에 vCPU 2 · 2 · 1 을 배분했다고 적었다. 부하 구간의 호스트 CPU 사용량은 이 수와 나란히 읽는다.
|
||||
- §192 가 적은 스크레이프 대상은 keycloak · kubelet · node-exporter · prometheus 넷이고 node-exporter 는 게스트 노드마다 하나씩 붙는다. §193 은 이 실험대가 호스트 쪽 지표를 긁지 않는다고 적었다.
|
||||
- 이 호스트에서 부하 구간의 vhost 스레드 CPU 사용량이나 softirq 시간을 잰 기록이 없다.
|
||||
|
||||
## 가정
|
||||
@@ -65,13 +68,13 @@ source:
|
||||
- 호스트에서 vhost 커널 스레드를 스레드 단위로 구분해 볼 수 있다고 전제한다. §108 이 vhost-net 을 써도 QEMU 가 설정과 수명 주기를 계속 맡는다고 적었으므로, QEMU 프로세스의 CPU 사용량과 vhost 커널 스레드의 CPU 사용량을 따로 세야 한다.
|
||||
- 부하 도구가 네트워크 지연을 이미 내고 있다고 전제한다. 그 도구가 어떤 값을 어떤 주기로 내는지는 근거 문서에 적혀 있지 않다.
|
||||
- 호스트와 게스트 둘의 시각을 맞춰 읽을 수 있다. 시계가 어긋나면 세 값을 같은 부하 구간에 겹쳐 놓지 못한다.
|
||||
- 호스트 쪽 Nginx 도 같은 물리 CPU 를 쓴다. 부하 구간의 호스트 CPU 상승을 전부 네트워크 가상화 몫으로 읽으면 이 전제가 깨진다.
|
||||
- 엣지 게스트의 nginx 가 쓰는 CPU 는 그 게스트를 돌리는 QEMU 프로세스 쪽에 나타난다고 본다. §179 가 nginx 를 게스트로 옮긴 뒤로 호스트에는 그 프로세스가 없으므로, 부하 구간의 호스트 CPU 상승을 전부 네트워크 가상화 몫으로 읽으면 이 전제가 깨진다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 부하를 걸기 전 vhost 커널 스레드의 CPU 사용량과 softirq 시간.
|
||||
- 부하 구간에서 그 둘이 얼마나 오르는지.
|
||||
- 오른 몫이 QEMU vCPU 스레드 사용량과 어떻게 나뉘는지.
|
||||
- 오른 몫이 QEMU vCPU 스레드 사용량과 어떻게 나뉘는지. 게스트가 셋이라 엣지 게스트를 돌리는 QEMU 프로세스의 몫도 k3s 노드 두 대와 갈라 세야 한다.
|
||||
- vhost 커널 스레드와 softirq 의 움직임이 네트워크 지연과 같은 시간축에서 함께 움직이는지.
|
||||
- 두 지표가 얼마나 움직여야 실험 결과를 다르게 읽어야 하는지. 그 문턱을 아직 정하지 않았다.
|
||||
- softirq 시간을 이 환경에서 어떤 도구로 읽는지. 근거 문서가 명령을 적지 않아 실행하는 쪽이 정한다.
|
||||
@@ -81,7 +84,9 @@ source:
|
||||
- 실험 조건을 바꾸지 않고 관찰만 덧붙인다. CPU 가상화 쪽 물음이 같은 실험 구간을 쓰기로 되어 있어 부하 수준을 바꾸면 두 기록을 겹쳐 읽지 못한다.
|
||||
- 기준값을 먼저 찍는다. 부하 구간의 값만 있으면 그것이 평소 값인지 부하 때문에 오른 값인지 판정할 수 없다.
|
||||
- 이 물음이 새로 만드는 값은 vhost 커널 스레드 사용량과 softirq 시간 둘이다. QEMU CPU 와 Guest CPU 와 steal time 은 CPU 가상화 쪽 기록을 그대로 쓰고, 네트워크 지연은 부하 도구가 낸 값을 쓴다.
|
||||
- 호스트 쪽 값은 손으로 읽어 남긴다. §192 의 관측 스택은 게스트 안에서 돌고 §193 이 적은 대로 호스트 지표를 긁지 않는다. §193 은 node-exporter 가 게스트 커널이 내놓는 값을 읽으므로 그 값이 전부 게스트가 본 것이고 호스트에서 같은 것을 재면 다른 수가 나올 수 있다고 추론으로 덧붙였다.
|
||||
- 두 지표가 움직이지 않았다는 결과가 나와도 Refresh Token 실험의 결론이 바뀌지는 않는다. §120 이 Refresh Token 경쟁과 네트워크 가상화를 별개 문제로 놓았기 때문에, 여기서 갈리는 것은 그 실험 결과를 애플리케이션과 저장소 쪽으로 읽어도 되는지 하나다.
|
||||
- 스레드가 어느 논리 CPU 에서 돌았는지는 §14.7 의 psr 로 읽히지만, 그 번호가 어느 물리 코어인지는 SSOT 에서 나오지 않는다. §197 이 남긴 lscpu 출력이 grep 으로 걸러져 Model name 과 CPU(s), Thread(s) per core, Core(s) per socket 네 줄뿐이기 때문이다. vhost 스레드를 어느 CPU 에 둘지를 나중에 정하려면 그 배치를 호스트에서 다시 읽어야 한다.
|
||||
- 이 호스트에서 잰 값이 없어 다른 장비의 수치를 근거로 삼지 않는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
+28
-22
@@ -20,18 +20,18 @@ source:
|
||||
|
||||
# QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가
|
||||
|
||||
backend 는 virtqueue 를 사이에 두고 게스트와 버퍼를 주고받는 호스트 쪽을 가리킨다. §107 은 패킷 처리를 QEMU 사용자 공간(userspace)에서 호스트 커널로 옮기면 컨텍스트 스위치와 사용자 공간 오버헤드가 줄어든다고 적었다. 줄어든다는 방향만 적혀 있을 뿐 이 호스트에서 두 backend 를 나란히 재 본 값은 없다. §110 이 실제로 복사가 일어나는지는 커널 버전과 offload 를 비롯한 여러 조건에 따라 달라질 수 있다고 밝혔으므로, 다른 환경에서 나온 수치를 이 호스트의 값으로 옮겨 쓸 수도 없다. 이 물음은 §122 OQ-4 가 든 여섯 축을 이 호스트에서 나란히 재서 차이가 보이는지 가른다.
|
||||
백엔드(backend)는 virtqueue 를 사이에 두고 게스트와 버퍼를 주고받는 호스트 쪽을 가리킨다. §107 은 패킷 처리를 QEMU 사용자 공간(userspace)에서 호스트 커널로 옮기면 컨텍스트 스위치와 사용자 공간 오버헤드가 줄어든다고 적었지만, 방향만 있을 뿐 이 호스트에서 두 백엔드를 나란히 재 본 값은 없다. §110 은 실제로 복사가 일어나는지가 커널 버전과 offload 를 비롯한 여러 조건에 따라 달라질 수 있다고 밝혔으니, 다른 환경의 수치를 이 호스트 값으로 옮겨 쓸 수도 없다. 이 물음은 §122 OQ-4 가 든 여섯 축을 이 호스트에서 나란히 재서 차이가 보이는지 가른다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
그 경로에서 두 backend 가 갈리는 곳은 TAP 다음 한 칸이고, 이 물음은 거기서 무엇이 달라지는지를 잰다.
|
||||
그 경로에서 두 백엔드가 갈리는 곳은 TAP 다음 한 칸이고, 이 물음은 거기서 무엇이 달라지는지를 잰다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
지금 어느 쪽으로 돌고 있는지가 정해져야 견줄 두 값 가운데 한쪽이 고정된다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
두 물음이 QEMU CPU 와 Host CPU 를 같은 부하에서 읽으므로 측정을 한 번으로 묶을 수 있다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
backend 차이가 지연에 얼마나 들어오는지를 이 물음이 재면, 그 기준이 그 값을 가져다 쓴다.
|
||||
백엔드 차이가 지연에 얼마나 들어오는지를 이 물음이 재면, 그 기준이 그 값을 가져다 쓴다.
|
||||
|
||||
## 사실
|
||||
|
||||
@@ -40,12 +40,12 @@ backend 는 virtqueue 를 사이에 두고 게스트와 버퍼를 주고받는
|
||||
QEMU userspace backend : TAP → QEMU → virtqueue
|
||||
vhost-net kernel backend : TAP → vhost-net → virtqueue
|
||||
- §125 는 최종 기준 구조에 두 Data Path 를 나란히 그렸다. 열한 칸 가운데 다른 곳은 TAP 다음 한 칸이고, 거기에 vhost-net 이 오느냐 QEMU virtio backend 가 오느냐로 갈린다.
|
||||
- §107 이 든 최적화 방향은 패킷마다 QEMU 사용자 공간이 끼어들던 처리를 커널 backend 로 옮겨 컨텍스트 스위치와 사용자 공간 오버헤드를 줄이는 것이다.
|
||||
- §110 은 virtio · virtqueue · vhost 구조가 버퍼 디스크립터(descriptor)로 불필요한 복사와 컨텍스트 스위치를 줄이도록 설계되어 있다고 적고, 그렇다고 이를 항상 zero-copy 라고 일반화하면 안 된다고 못 박았다. 실제로 복사가 일어나는지는 아래에 따라 달라질 수 있다.
|
||||
- §107 이 든 최적화 방향은 패킷마다 QEMU 사용자 공간이 끼어들던 처리를 커널 백엔드로 옮겨 컨텍스트 스위치와 사용자 공간 오버헤드를 줄이는 것이다.
|
||||
- §110 은 virtio · virtqueue · vhost 구조가 버퍼 디스크립터(descriptor)로 불필요한 복사와 컨텍스트 스위치를 줄이도록 설계되어 있다고 적었다. 그렇다고 이를 항상 zero-copy 라고 일반화하면 안 된다고 못 박았다. 실제로 복사가 일어나는지는 아래에 따라 달라질 수 있다.
|
||||
Kernel version · QEMU version · vhost configuration
|
||||
offload · NIC capability · packet path · GSO/GRO/TSO
|
||||
- §111 은 게스트와 호스트가 큐에 새 패킷이 들어왔음을 서로 알려야 한다고 적고, 패킷마다 인터럽트와 알림이 지나치게 많이 나가면 오버헤드가 커질 수 있다고 덧붙였다. 그래서 batching 과 interrupt moderation 과 queueing 이 중요하다.
|
||||
- §117.4 는 초당 패킷 수가 높은 구간에서 QEMU 사용자 공간이 처리 경로를 직접 맡으면 CPU 오버헤드가 커질 수 있다고 밝히고, 관찰할 것으로 QEMU CPU usage · vhost thread · packet rate · latency · context switch 를 들었다.
|
||||
- §117.4 는 초당 패킷 수가 높은 구간에서 QEMU 사용자 공간이 처리 경로를 직접 맡으면 CPU 오버헤드가 커질 수 있다고 밝혔다. 관찰할 것으로는 QEMU CPU usage · vhost thread · packet rate · latency · context switch 를 들었다.
|
||||
- §122 OQ-4 는 비교할 축 여섯을 적었다.
|
||||
Latency
|
||||
Throughput
|
||||
@@ -54,53 +54,59 @@ backend 는 virtqueue 를 사이에 두고 게스트와 버퍼를 주고받는
|
||||
Context Switch
|
||||
Packet rate
|
||||
- §122 OQ-4 는 축의 이름만 적어 두었고, 여섯을 무슨 도구로 어떻게 재는지는 제3부에 없다. 같은 §122 에서 OQ-1 과 OQ-2 는 돌릴 명령을 그대로 적었고 OQ-3 은 lsmod | grep vhost 를 확인 후보로 들었다.
|
||||
- 이 호스트에서 두 backend 를 재 본 값은 SSOT 에 없다.
|
||||
- §197 은 이 호스트의 판 번호를 실측으로 적었다.
|
||||
libvirt : 12.7.0
|
||||
QEMU emulator version : 11.1.1
|
||||
커널 : 7.2.2-arch1-1
|
||||
- 그래서 §110 이 든 조건 여섯 가운데 kernel version 과 QEMU version 은 이제 적을 수 있다. vhost configuration 과 offload, NIC capability 는 이 호스트에서 읽은 값이 없다.
|
||||
- §202 와 §204 는 게스트를 지우고 다시 세울 때 무엇이 사라지고 무엇이 남는지 적었다. 게스트 디스크와 시드 ISO 는 사라지고 base.qcow2 와 libvirt 의 default 네트워크 정의는 남으며, 재구축해도 IP 가 같다. 다만 백엔드를 바꿔 다시 세운 기록은 없다.
|
||||
- 이 호스트에서 두 백엔드를 재 본 값은 SSOT 에 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 같은 가상 머신을 다른 backend 로 다시 구성해 띄울 수 있다고 본다. 그것이 이 실험 환경에서 되는지는 SSOT 에 적혀 있지 않다.
|
||||
- 같은 가상 머신을 다른 백엔드로 다시 구성해 띄울 수 있다고 본다. 그것이 이 실험 환경에서 되는지는 SSOT 에 적혀 있지 않다.
|
||||
- 두 구성에 같은 부하를 걸 수 있다고 전제한다. 부하 도구와 요청 구성이 같아야 여섯 축을 견줄 수 있기 때문이다.
|
||||
- 부하를 걸기 전 값과 부하 중 값의 차이가 backend 차이보다 작다고 전제하지 않는다. 그래서 부하 전 값을 먼저 찍어 둔다.
|
||||
- 부하를 걸기 전 값과 부하 중 값의 차이가 백엔드 차이보다 작다고 전제하지 않는다. 그래서 부하 전 값을 먼저 찍어 둔다.
|
||||
- 두 구성을 같은 시각에 나란히 돌릴 수 없다고 보고 차례로 잰다. 그 사이에 호스트의 다른 부하가 달라지면 값이 흔들릴 수 있다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 같은 부하를 두 backend 로 돌렸을 때 여섯 축이 실제로 얼마나 달라지는지.
|
||||
- 같은 부하를 두 백엔드로 돌렸을 때 여섯 축이 실제로 얼마나 달라지는지.
|
||||
- 그 차이가 이 실험의 결과를 다르게 읽어야 할 만큼인지, 아니면 측정 흔들림 안인지.
|
||||
- 이 호스트가 내는 초당 패킷 수가 §107 이 말한 「높아질수록 비용이 커지는」 구간에 들어가는지.
|
||||
- 여섯 축을 이 환경에서 무엇으로 재는지. 제3부가 도구를 적지 않아 실행하는 쪽이 정한다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 지금 backend 가 무엇인지는 이 물음이 정하지 않는다. 그것을 확정하는 물음이 닫힌 뒤에 시작한다. §116 은 이 테스트 환경의 경로를 펼치면서 TAP 다음 칸에 vhost-net 을 적어 두었는데, 그 칸이 실제로 그런지를 §122 가 OQ-3 으로 아직 묻고 있으므로 그 그림을 지금 backend 의 근거로 쓰지 않는다.
|
||||
- §110 이 든 조건들(kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO)을 함께 적지 않으면 이 측정을 다른 환경에 재사용할 수 없다.
|
||||
- 이 호스트에서 잰 값이 없어 다른 장비의 backend 비교 수치를 근거로 삼지 않는다.
|
||||
- 여기서 어느 backend 로 실험을 고정할지는 정하지 않는다. 그것은 측정 결과가 나온 뒤의 Decision 이다.
|
||||
- 지금 백엔드가 무엇인지는 이 물음이 정하지 않는다. 그것을 확정하는 물음이 닫힌 뒤에 시작한다. §116 은 이 테스트 환경의 경로를 펼치면서 TAP 다음 칸에 vhost-net 을 적어 두었다. 그 칸이 실제로 그런지를 §122 가 OQ-3 으로 아직 묻고 있으므로 그 그림을 지금 백엔드의 근거로 쓰지 않는다.
|
||||
- §110 이 든 조건들(kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO)을 함께 적지 않으면 이 측정을 다른 환경에 재사용할 수 없다. 앞의 둘은 §197 이 이미 적었으므로 잴 때 나머지를 채운다.
|
||||
- 이 호스트에서 잰 값이 없어 다른 장비의 백엔드 비교 수치를 근거로 삼지 않는다.
|
||||
- 여기서 어느 백엔드로 실험을 고정할지는 정하지 않는다. 그것은 측정 결과가 나온 뒤의 Decision 이다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 지금 backend 만 먼저 찍어 나중에 견줄 값을 만든다
|
||||
### 1. 지금 백엔드만 먼저 찍어 나중에 견줄 값을 만든다
|
||||
|
||||
구성을 바꾸지 않고 부하 전과 부하 중의 여섯 축을 한 번씩 기록한다. 가상 머신을 다시 구성하지 않으므로 지금 돌고 있는 Keycloak 실험을 멈추지 않아도 되고, 나중에 다른 backend 를 잴 때 견줄 값이 생긴다.
|
||||
구성을 바꾸지 않고 부하 전과 부하 중의 여섯 축을 한 번씩 기록한다. 가상 머신을 다시 구성하지 않으므로 지금 돌고 있는 Keycloak 실험을 멈추지 않아도 되고, 나중에 다른 백엔드를 잴 때 견줄 값이 생긴다.
|
||||
|
||||
한 구성의 값만으로는 이 물음이 닫히지 않는다.
|
||||
|
||||
### 2. 두 backend 로 바꿔 가며 같은 부하를 건다
|
||||
### 2. 두 백엔드로 바꿔 가며 같은 부하를 건다
|
||||
|
||||
§122 OQ-4 가 요구하는 비교가 이것이다. 같은 가상 머신을 다른 backend 로 다시 구성하고 같은 부하를 양쪽에 걸어 여섯 축을 같은 시각에 기록한다. 차이가 나면 그 표가 그대로 Case 가 된다.
|
||||
§122 OQ-4 가 요구하는 비교가 이것이다. 같은 가상 머신을 다른 백엔드로 다시 구성하고 같은 부하를 양쪽에 걸어 여섯 축을 같은 시각에 기록한다. 차이가 나면 그 표가 그대로 Case 가 된다.
|
||||
|
||||
가상 머신을 다시 구성하고 재시작해야 하므로 그동안 Keycloak 실험을 멈춰야 하고, 두 측정 사이에 호스트 상태가 달라지지 않도록 관리해야 한다.
|
||||
|
||||
### 3. 문헌의 backend 비교 수치를 가져다 쓴다 — 제외
|
||||
### 3. 문헌의 백엔드 비교 수치를 가져다 쓴다 — 제외
|
||||
|
||||
§110 은 실제로 복사가 일어나는지가 여러 조건에 따라 달라질 수 있다고 밝혔다. 그 조건은 kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO 다. 조건이 이만큼 걸려 있으니 다른 환경에서 나온 수치는 이 호스트의 값이 되지 못한다. 이 물음은 이 호스트에서 잰 값으로만 닫힌다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. 지금 backend 가 무엇인지 먼저 확정한다. 그것을 묻는 물음이 닫히기 전에는 견줄 두 값 가운데 한쪽이 무엇인지 알 수 없다.
|
||||
1. 지금 백엔드가 무엇인지 먼저 확정한다. 그것을 묻는 물음이 닫히기 전에는 견줄 두 값 가운데 한쪽이 무엇인지 알 수 없다.
|
||||
2. 부하를 걸기 전에 여섯 축을 한 번 찍어 둔다.
|
||||
3. 지금 구성에 부하를 걸고 여섯 축을 같은 시각에 기록한다. Latency 와 Throughput 과 Packet rate 는 부하 도구가 내는 값을 쓰고, QEMU CPU 와 Host CPU 와 Context Switch 는 호스트에서 읽는다.
|
||||
4. 같은 가상 머신을 다른 backend 로 구성하고 같은 부하를 걸어 3 을 되풀이한다.
|
||||
4. 같은 가상 머신을 다른 백엔드로 구성하고 같은 부하를 걸어 3 을 되풀이한다.
|
||||
5. 두 구성의 여섯 축을 나란히 적고, §110 이 든 조건들과 실행한 명령을 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 두 구성의 여섯 축을 나란히 놓으면 닫는다. 차이가 부하 전 값의 흔들림 안이면 이 호스트가 내는 초당 패킷 수에서는 backend 선택이 결과를 바꾸지 않는다고 적고 닫는다. 차이가 나면 그 측정이 Case 가 되고, 어느 backend 로 실험을 고정할지는 그 Case 뒤에 Decision 으로 넘긴다.
|
||||
닫는 조건 : 두 구성의 여섯 축을 나란히 놓으면 닫는다. 차이가 부하 전 값의 흔들림 안이면 이 호스트가 내는 초당 패킷 수에서는 백엔드 선택이 결과를 바꾸지 않는다고 적고 닫는다. 차이가 나면 그 측정이 Case 가 되고, 어느 백엔드로 실험을 고정할지는 그 Case 뒤에 Decision 으로 넘긴다.
|
||||
|
||||
+20
-9
@@ -19,7 +19,7 @@ source:
|
||||
|
||||
# VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가
|
||||
|
||||
§99 는 TAP 을 가상 머신의 이더넷 프레임과 호스트 리눅스 네트워크를 잇는 접점으로 놓았다. 그 접점의 이름은 호스트마다 다르게 붙는데, 이 호스트에서 두 가상 머신에 각각 무엇이 붙었는지는 SSOT 에 없다. 이름을 모르면 §119 가 적은 계층별 tcpdump 도 대상을 채우지 못하고, §117.1 이 든 「특정 VM 만 통신 불가」가 어느 가상 머신을 가리키는지도 가릴 수 없다. 이 물음은 두 가상 머신의 호스트 쪽 인터페이스 이름과 그것이 붙어 있는 곳을 확정한다.
|
||||
§99 는 TAP 을 가상 머신의 이더넷 프레임과 호스트 리눅스 네트워크를 잇는 접점으로 놓았다. 그 접점의 이름은 호스트마다 다르게 붙는데, 이 호스트의 두 가상 머신에 무엇이 붙었는지는 SSOT 에 없다. 이름을 모르면 §119 의 계층별 tcpdump 가 대상을 채우지 못하고, §117.1 이 든 「특정 VM 만 통신 불가」도 어느 가상 머신인지 가릴 수 없다. 이 물음은 두 가상 머신의 호스트 쪽 인터페이스 이름과 붙어 있는 곳을 확정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -54,20 +54,30 @@ source:
|
||||
특정 VM 만 통신 불가
|
||||
- §117.1 이 그 증상에서 확인하라고 든 명령은 ip link · bridge link · bridge fdb show · virsh domiflist 다.
|
||||
- §116 은 이 테스트 환경의 경로를 펼치면서 TAP 칸을 TAP(vm1) 과 TAP(vm2) 로 적었다. 호스트에서 읽은 이름은 그 그림에도 없다.
|
||||
- 두 가상 머신의 호스트 쪽 인터페이스 이름도, 그 인터페이스가 어느 브리지에 붙어 있는지도 SSOT 에는 없다.
|
||||
- §178 은 이 실험대의 게스트를 Debian 12 genericcloud 3대로 적었다. 엣지 1대와 k3s 2노드이고, §122 OQ-2 가 vm1 과 vm2 로 적은 두 대가 그중 k3s 노드 쪽이다.
|
||||
- §202 는 2026-09-10 에 돌린 철거 명령의 출력을 그대로 남겼고, 거기서 libvirt domain 이름이 kc-lab-edge · kc-lab-1 · kc-lab-2 로 확인된다. 한 대분 출력의 첫 줄은 Domain 'kc-lab-edge' destroyed 다.
|
||||
- §201 과 §247 이 적은 세 게스트의 MAC 주소와 IP 주소
|
||||
kc-lab-edge : `52:54:00:aa:bb:10` · 192.168.122.10
|
||||
kc-lab-1 : `52:54:00:aa:bb:11` · 192.168.122.11
|
||||
kc-lab-2 : `52:54:00:aa:bb:12` · 192.168.122.12
|
||||
- §247 은 `52:54:00` 이 QEMU/KVM 에 할당된 OUI(제조사 식별 접두사)라고 적고, 예약의 mac 과 VM 을 만들 때 준 mac 이 정확히 같아야 한다고 밝혔다. 다르면 예약이 조용히 무시되고 게스트가 동적 범위에서 아무 주소나 받는다.
|
||||
- §201 은 예약과 리스를 다른 것으로 갈라 적었다. virsh net-dumpxml 의 예약은 줄 의도이고 virsh net-dhcp-leases 는 실제로 준 기록이라 둘이 다를 수 있다. 실제로 준 기록에는 `52:54:00:aa:bb:11` 이 192.168.122.11/24 을, `52:54:00:aa:bb:12` 가 192.168.122.12/24 을 각각 kc-lab-1 과 kc-lab-2 이름으로 받은 줄이 남아 있다.
|
||||
- §178 과 §245 는 게스트가 libvirt 의 default 네트워크에 붙는다고 적었다. §245 는 VM 이 한 대라도 뜨면 그 VM 의 vnetN 인터페이스가 virbr0 에 붙으면서 브리지가 UP 으로 바뀐다고 덧붙였다.
|
||||
- §201 은 VM 세 대가 돌 때 virbr0 이 UP 이고 전부 철거한 뒤에는 DOWN 이라는 출력을 남겼다. 상태가 갈린 이유를 브리지에 붙은 tap 인터페이스가 하나도 없어서라고 적었다.
|
||||
- 호스트 쪽 인터페이스의 이름은 SSOT 에 없다. virsh domiflist 를 돌린 출력도 ip link 출력도 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트에 붙어 virsh 와 ip 계열 명령을 실행할 수 있다고 본다.
|
||||
- §122 OQ-2 가 명령에 적은 vm1 과 vm2 가 이 호스트에 실재하는 domain 이름이라고 본다. 실제 이름이 다르면 그 이름으로 바꿔 돌린다. §99 와 §118 은 같은 명령에 넣을 domain 을 비워 두었고, 가상 머신 이름을 그대로 적은 곳은 §90.1 의 virsh domiflist vm1 과 §122 OQ-2 다.
|
||||
- §122 OQ-2 는 명령에 vm1 과 vm2 를 적었지만 §202 의 철거 출력에 찍힌 domain 이름은 kc-lab-1 과 kc-lab-2 다. 그래서 명령에 넣을 이름은 뒤쪽을 쓴다. §99 와 §118 은 같은 명령에 넣을 domain 을 비워 두었다.
|
||||
- virsh domiflist 출력에 인터페이스 이름과 MAC 주소가 함께 나온다고 전제한다. §99 도 §118 도 이 명령의 출력 형식은 적지 않았다.
|
||||
- 두 가상 머신이 켜져 있는 동안 읽는다고 전제한다. 꺼진 가상 머신의 TAP 이 호스트에 남아 있는지는 SSOT 에 적혀 있지 않다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- VM1 과 VM2 의 호스트 쪽 인터페이스 이름이 각각 무엇인지.
|
||||
- 각 인터페이스의 MAC 주소와 NIC model 이 무엇인지.
|
||||
- 두 인터페이스가 같은 브리지에 붙어 있는지, 서로 다른 곳에 붙어 있는지.
|
||||
- kc-lab-1 과 kc-lab-2 의 호스트 쪽 인터페이스 이름이 각각 무엇인지. 엣지 게스트 kc-lab-edge 의 것도 같이 모른다.
|
||||
- 각 인터페이스의 NIC model 이 무엇인지. MAC 주소는 §247 의 예약이 대지만 virsh domiflist 가 같은 값을 내는지는 대조해야 갈린다.
|
||||
- 세 인터페이스가 모두 virbr0 에 붙어 있는지. §245 는 default 네트워크의 VM 들이 이 브리지에 연결된다고 적었고, bridge link 로 포트 목록을 읽은 출력은 없다.
|
||||
- ip tuntap show 에 나오는 TAP 목록과 virsh domiflist 가 대는 이름이 그대로 맞아떨어지는지.
|
||||
|
||||
## 제약
|
||||
@@ -75,12 +85,13 @@ source:
|
||||
- 이름과 어디에 붙어 있는지를 적는 데서 끊는다. 그 경로로 패킷이 실제로 흘렀는지는 tcpdump 를 쓰는 물음이 받는다.
|
||||
- 두 가상 머신을 같은 시점에 읽는다. 한쪽을 재시작한 뒤 다른 쪽을 읽으면 이름이 바뀌어도 알 수 없기 때문이다.
|
||||
- 이 호스트에서 읽은 출력이 없어 tap0 이나 vnet0 같은 §99 의 예시 이름을 이 호스트의 값으로 쓰지 않는다.
|
||||
- SSOT 가 마지막으로 적은 게스트 상태는 §202 의 철거다. 그 뒤에 다시 세웠는지는 적혀 있지 않으므로 세 게스트가 떠 있는 상태에서 읽는다. 철거된 상태로 읽으면 볼 것이 없다 — §201 은 세 대를 전부 철거한 뒤 virbr0 이 DOWN 인 이유를 브리지에 붙은 tap 인터페이스가 하나도 없어서라고 적었다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. libvirt 가 대는 이름을 먼저 받아 호스트에서 대조한다
|
||||
|
||||
virsh domiflist 로 가상 머신마다 붙은 인터페이스를 받고, 그 이름이 ip link 목록에 실재하는지 확인한 뒤 bridge link 로 어느 브리지의 port 인지 잡는다. §122 OQ-2 가 적은 네 줄이 이 순서다. 가상 머신과 인터페이스의 짝이 처음부터 정해져 나오므로 두 대의 것을 헷갈리지 않는다.
|
||||
virsh domiflist 로 가상 머신마다 붙은 인터페이스를 받고, 그 이름이 ip link 목록에 실재하는지 확인한 뒤 bridge link 로 어느 브리지의 포트인지 잡는다. §122 OQ-2 가 적은 네 줄이 이 순서다. 가상 머신과 인터페이스의 짝이 처음부터 정해져 나오므로 두 대의 것을 헷갈리지 않는다.
|
||||
|
||||
libvirt 가 모르는 인터페이스는 이 순서에서 빠진다.
|
||||
|
||||
@@ -96,9 +107,9 @@ ip link 와 ip tuntap show 로 호스트에 있는 TAP 을 모두 적고, bridge
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. virsh domiflist vm1 과 virsh domiflist vm2 로 각 가상 머신에 붙은 인터페이스를 읽는다.
|
||||
1. virsh domiflist 에 §202 가 적은 domain 이름 kc-lab-1 · kc-lab-2 · kc-lab-edge 를 차례로 넣어 각 가상 머신에 붙은 인터페이스를 읽는다.
|
||||
2. ip link 로 그 이름이 호스트에 실재하는지 대조한다.
|
||||
3. bridge link 로 각 인터페이스가 어느 브리지의 port 인지 적는다.
|
||||
3. bridge link 로 각 인터페이스가 어느 브리지의 포트인지 적는다.
|
||||
4. 두 가상 머신의 결과를 인터페이스 이름 · MAC 주소 · 붙어 있는 브리지로 나란히 적고, 실행한 명령과 출력을 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 가상 머신마다 인터페이스 이름과 MAC 주소와 붙어 있는 브리지를 적어 두 대를 나란히 놓으면 닫는다. 이 목록이 계층별 캡처 기준이 요구하는 지점의 이름이 되고, 이것이 없으면 실제 패킷 경로를 묻는 물음의 tcpdump 를 어느 인터페이스에 걸지 정할 수 없다. 두 가상 머신이 서로 다른 브리지에 붙어 있으면 §117.1 의 「특정 VM 만 통신 불가」를 진단할 때 그 사실을 먼저 본다고 적는다.
|
||||
|
||||
+12
-7
@@ -19,14 +19,14 @@ source:
|
||||
|
||||
# 이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가
|
||||
|
||||
multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성이다. §112 는 큐를 하나만 쓰면 패킷 처리가 한 vCPU 나 한 처리 경로에 몰릴 수 있어서 이것을 최적화 방향으로 들었다. 이 물음은 그 쏠림이 실제로 일어나는지를 재지 않고, 두 가상 머신이 애초에 큐를 몇 개 쓰도록 구성되어 있는지를 읽는다. 근거 문서는 multi-queue 를 쓸 수 있다고만 적었을 뿐 이 가상 머신들의 큐 수는 적지 않았다.
|
||||
multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성이다. §112 는 큐를 하나만 쓰면 패킷 처리가 한 vCPU 나 한 처리 경로에 몰릴 수 있어서 이것을 최적화 방향으로 들었을 뿐, 이 가상 머신들의 큐 수는 적지 않았다. 이 물음은 그 쏠림이 실제로 일어나는지를 재지 않고, 두 대가 애초에 큐를 몇 개 쓰도록 구성되어 있는지를 읽는다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
게스트와 호스트 backend 가 virtqueue 로 무엇을 주고받는지를 이 개념이 설명한다. 큐를 몇 개 두느냐는 그 구조 위의 설정이다.
|
||||
게스트와 호스트 백엔드가 virtqueue 로 무엇을 주고받는지를 이 개념이 설명한다. 큐를 몇 개 두느냐는 그 구조 위의 설정이다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
큐를 실제로 돌리는 backend 가 어느 쪽이냐에 따라 큐 수를 읽을 곳이 달라진다.
|
||||
큐를 실제로 돌리는 백엔드가 어느 쪽이냐에 따라 큐 수를 읽을 곳이 달라진다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
큐가 하나로 나왔을 때 그것이 실제 병목인지는 부하 구간의 vCPU 별 사용량이 답한다.
|
||||
|
||||
@@ -37,8 +37,8 @@ multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성
|
||||
Packet processing 병렬화
|
||||
Single queue bottleneck 완화
|
||||
Multi-core 활용
|
||||
- §112 는 그 효과가 workload · CPU affinity · IRQ placement · queue configuration 에 따라 달라진다고 덧붙였다. IRQ(Interrupt Request, 인터럽트 요청)는 장치가 처리할 일이 생겼음을 CPU 에 알리는 신호다. §117.5 가 그 분포를 확인 대상으로 든 것을 보면, 큐를 나눠 두어도 그 신호를 한 vCPU 가 몰아서 받으면 처리는 한 곳에 몰릴 수 있다.
|
||||
- §100 은 virtqueue 를 게스트와 호스트 backend 가 디스크립터(descriptor)를 써서 I/O 버퍼를 주고받는 공유 큐 구조로 놓고, 네트워크에서는 보통 TX/RX 큐를 쓴다고 적었다. TX virtqueue 는 게스트에서 호스트로, RX virtqueue 는 호스트에서 게스트로 버퍼를 넘긴다.
|
||||
- §112 는 그 효과가 workload · CPU affinity · IRQ placement · queue configuration 에 따라 달라진다고 덧붙였다. IRQ(Interrupt Request, 인터럽트 요청)는 장치가 처리할 일이 생겼음을 CPU 에 알리는 신호다.
|
||||
- §100 은 virtqueue 를 게스트와 호스트 백엔드가 디스크립터(descriptor)를 써서 I/O 버퍼를 주고받는 공유 큐 구조로 놓고, 네트워크에서는 보통 TX/RX 큐를 쓴다고 적었다. TX virtqueue 는 게스트에서 호스트로, RX virtqueue 는 호스트에서 게스트로 버퍼를 넘긴다.
|
||||
- §117.5 는 single queue bottleneck 을 큐 하나나 vCPU 하나에 패킷 처리가 몰리는 문제로 놓고, 확인 대상 넷을 들었다.
|
||||
virtio multi-queue
|
||||
IRQ distribution
|
||||
@@ -50,7 +50,10 @@ multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성
|
||||
queue count
|
||||
IRQ distribution
|
||||
- 같은 §122 에서 OQ-1 과 OQ-2 는 돌릴 명령을 그대로 적었고, OQ-5 는 확인 대상 넷의 이름만 적었다. §117.5 가 든 넷도 이름이다.
|
||||
- 두 가상 머신에 설정된 큐 수가 근거 문서에 없다. 게스트가 몇 개를 쓰고 있는지도, IRQ 가 어느 vCPU 에 붙어 있는지도 적혀 있지 않다.
|
||||
- §197 과 §218 은 이 실험대의 vCPU 배분을 실측으로 적었다. k3s 노드 kc-lab-1 과 kc-lab-2 가 각각 vCPU 2 이고 엣지 게스트가 1 이며, 합 5 를 논리 코어 8 위에 얹었다. §112 가 큐와 vCPU 를 하나씩 짝지어 든 예는 넷씩이라 이 게스트들의 수와 다르다.
|
||||
- §247 은 VM 이 부팅하면 게스트 커널이 virtio NIC 를 인식하고 DHCP 클라이언트가 DHCPDISCOVER 를 브로드캐스트한다고 적었다. 이 게스트들의 NIC 가 virtio 라는 것은 거기까지 나온다.
|
||||
- §201 은 게스트 안에서 본 인터페이스 이름을 한 줄 남겼다. 엣지 게스트가 첫 부팅에서 enp1s0 으로 192.168.122.10/24 을 받았다. ethtool 에 넣을 이름이 그 줄에서 나오지만 k3s 노드 두 대의 인터페이스 이름은 적혀 있지 않다.
|
||||
- 두 가상 머신에 설정된 큐 수가 SSOT 에 없다. 게스트가 몇 개를 쓰고 있는지도, IRQ 가 어느 vCPU 에 붙어 있는지도 적혀 있지 않다.
|
||||
- §126 이 적은 실습 순서 열둘 가운데 multi-queue / offload 확인은 마지막 열두째다.
|
||||
- 네트워크 계층의 확인 명령을 모아 둔 §118 에는 큐 수나 IRQ 분포를 읽는 명령이 없다. Guest NIC 항목에 적힌 것은 ip link · ip addr · ip route · ip neigh 이고, virtio 장치 항목은 lspci 와 lsmod | grep virtio 다. ethtool 은 Physical NIC 항목에서 인터페이스 이름을 받는 형태로만 나온다.
|
||||
|
||||
@@ -59,6 +62,7 @@ multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성
|
||||
- 두 가상 머신의 구성과 게스트 내부를 지금 읽을 수 있다고 본다.
|
||||
- §112 가 든 RX Queue 넷과 vCPU 넷의 짝은 multi-queue 를 설명하려고 든 예시이지 이 호스트에서 읽은 값이 아니다.
|
||||
- 설정에 적힌 큐 수와 게스트가 실제로 쓰는 큐 수를 따로 읽어야 한다고 전제한다. 설정에 여럿을 적어 두면 게스트 드라이버가 그만큼 쓴다는 서술이 근거 문서에 없기 때문이다.
|
||||
- 큐를 여럿 두어도 IRQ 를 한 vCPU 가 몰아서 받으면 처리가 한쪽에 몰린다고 본다. §117.5 는 IRQ distribution 을 확인 대상으로 들었을 뿐 그렇게 된다고 적지는 않았다.
|
||||
- 두 가상 머신의 NIC 구성이 확인하는 동안 바뀌지 않는다.
|
||||
|
||||
## 미지수
|
||||
@@ -66,7 +70,7 @@ multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성
|
||||
- 두 가상 머신의 virtio-net 에 설정된 큐 수.
|
||||
- 게스트가 실제로 쓰고 있는 큐 수, 그리고 그 수가 설정값과 같은지.
|
||||
- 각 큐의 IRQ 가 여러 vCPU 에 흩어져 있는지 한 vCPU 에 몰려 있는지.
|
||||
- 두 가상 머신의 vCPU 수. §112 가 큐와 vCPU 를 하나씩 짝지어 든 예는 두 수를 나란히 놓아야 읽히는데, vCPU 수도 네트워크 쪽 근거에는 없다.
|
||||
- 설정된 큐 수와 vCPU 수의 관계. vCPU 는 §218 이 두 노드 모두 2 로 적었으므로, 큐가 몇이면 §112 가 든 하나씩 대응이 되는지는 큐 수를 읽어야 갈린다.
|
||||
- 이 환경의 RSS/RPS/XPS 설정. §117.5 가 확인 대상으로 들었지만 값을 읽는 방법은 적지 않았다.
|
||||
|
||||
## 제약
|
||||
@@ -74,6 +78,7 @@ multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성
|
||||
- 이 호스트에서 잰 값이 하나도 없다. 근거는 개념을 정리한 문서 한 편이고 §112 의 큐 넷과 vCPU 넷은 예시 숫자다.
|
||||
- 이 물음은 큐 구성이 무엇인지까지만 답한다. 쏠림이 실제 병목인지는 부하를 걸어야 갈리고, 그 부하 측정은 다른 물음이 가져간다.
|
||||
- 확인하는 동안 NIC 구성을 바꾸지 않는다. 큐 수를 늘려 놓고 읽으면 지금 실험이 어떤 구성에서 돌았는지 못 본다.
|
||||
- 게스트 안에서 읽는 항목이 둘이라 게스트가 떠 있어야 한다. SSOT 가 마지막으로 적은 게스트 상태는 §202 의 철거이고, 그 뒤 다시 세웠는지는 적혀 있지 않다.
|
||||
- §118 이 큐 수와 IRQ 분포를 읽는 명령을 적지 않았으므로, 실행한 명령과 그 출력을 함께 증거로 남겨야 다음 사람이 같은 값을 다시 읽는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
+27
-14
@@ -21,7 +21,7 @@ source:
|
||||
|
||||
# 이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가
|
||||
|
||||
§98 은 가상 머신 네트워크를 분석하기 전에 Bridge 기반인가 · Routing 기반인가 · NAT(Network Address Translation, 네트워크 주소 변환) 기반인가를 구분하라고 적었다. 셋은 프레임이 지나는 계층이 다르고, 그에 따라 호스트의 L3 경로와 Netfilter 가 끼어드는지도 갈린다. 이 물음은 성능을 재지 않는다. 제3부가 서술한 경로 가운데 어느 절이 이 호스트에 그대로 적용되는지를 먼저 확정한다.
|
||||
이 실험대는 NAT(Network Address Translation, 네트워크 주소 변환) 를 쓴다. 이더넷 없이 WiFi 만 있어 브리지를 못 쓴다고 §178 이 관측으로 적었다. §249 가 세 모드를 견준 표에서 브리지와 macvtap 은 둘 다 「WiFi라 불가」이고 채택 표시는 NAT 한 줄에만 붙어 있다. 감수한 것도 같은 표에 적혀 있다 — VM 주소가 사설이라 LAN 에서 VM 으로 바로 들어가지 못하고 포워딩이 필요하다. 엣지를 게스트로 옮긴 뒤 호스트 커널 DNAT(Destination NAT, 목적지 주소 변환) 와 libvirt 체인의 구멍이 새로 필요해진 것이 그 포워딩이다. 다만 §122 OQ-1 이 요구한 다섯 명령의 출력이 없어 virbr0 에 무엇이 붙어 있고 라우팅이 어떻게 걸려 있는지는 아직 적지 못한다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -37,14 +37,14 @@ source:
|
||||
## 사실
|
||||
|
||||
- §96 은 Linux Bridge 를 호스트 커널 안의 L2 소프트웨어 스위치로 적었다. 이더넷 프레임의 Destination MAC 을 보고 어느 포트로 보낼지 정하고, MAC learning 을 하며, 여러 가상 포트와 물리 포트를 잇는다.
|
||||
- §97 은 Routing 을 L3 에서 IP 를 보고 내리는 결정으로 놓았다. Bridge 가 같은 이더넷 네트워크를 잇는 것과 달리 Routing 은 서로 다른 IP 네트워크를 잇고, destination IP 를 보고 어느 인터페이스나 next-hop 으로 보낼지 정한다.
|
||||
- §98 은 NAT 을 패킷의 IP/Port 정보를 바꾸는 것으로 놓고, 가상 머신이 private subnet 을 쓰면 호스트가 NAT gateway 처럼 동작할 수 있다는 예를 들었다.
|
||||
- §97 은 Routing 을 L3 에서 IP 를 보고 내리는 결정으로 놓았다. Bridge 가 같은 이더넷 네트워크를 잇는 것과 달리 Routing 은 서로 다른 IP 네트워크를 잇고, 목적지 IP 를 보고 어느 인터페이스나 next-hop 으로 보낼지 정한다.
|
||||
- §98 은 NAT 을 패킷의 IP 와 포트 정보를 바꾸는 것으로 놓고, 가상 머신이 사설 서브넷을 쓰면 호스트가 NAT 게이트웨이처럼 동작할 수 있다는 예를 들었다.
|
||||
VM : 192.168.122.10
|
||||
Host NAT 를 지난 뒤 : 203.0.113.10
|
||||
- §96 과 §97 은 절 끝에 확인 명령을 달았다. §96 은 bridge link · bridge fdb show · ip link show type bridge 를, §97 은 ip route 를 든다. 셋을 구분하라고 적은 §98 에는 확인 명령이 없다.
|
||||
- §96 과 §97 은 절 끝에 확인 명령을 달았다. §96 은 bridge link · bridge fdb show · ip link show type bridge 를, §97 은 ip route 를 들었다. 셋을 구분하라고 적은 §98 에는 확인 명령이 없다.
|
||||
- §114 는 Bridge 가 단순 L2 forwarding 만 하는 구성이면 프레임이 호스트의 일반적인 L3 TCP/IP 스택을 지나지 않고 다른 TAP 으로 나갈 수 있다고 적었다. 호스트가 Routing · NAT · Host-local termination · Firewall 을 맡으면 그때는 L3/Netfilter 경로가 끼어든다.
|
||||
- 그래서 §114 는 Physical NIC → Host TCP/IP Stack → Bridge 를 고정된 패킷 경로로 보면 안 되고, 실제 경로는 bridge/routing/NAT 구성에 따라 달라진다고 못 박았다.
|
||||
- §94 는 이 문서가 기준으로 삼은 구조를 virtio-net + vhost-net + TAP + Linux Bridge 로 적고, 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 덧붙였다.
|
||||
- §94 는 이 문서가 기준으로 삼은 구조를 virtio-net + vhost-net + TAP + Linux Bridge 로 적었다. 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 덧붙였다.
|
||||
- 확인할 명령은 §122 OQ-1 이 다섯 줄로 적어 두었다.
|
||||
정의된 가상 네트워크 열거 : virsh net-list --all
|
||||
그 가상 네트워크의 정의 읽기 : virsh net-dumpxml 에 이름을 넣는다
|
||||
@@ -52,26 +52,39 @@ source:
|
||||
어느 인터페이스가 어느 브리지의 포트인지 : bridge link
|
||||
라우팅 테이블 : ip route
|
||||
- §118 이 같은 계층에 든 명령 가운데 virsh net-info 와 ip rule 은 OQ-1 의 다섯 줄에 없다.
|
||||
- 이 호스트에서 그 명령을 돌린 출력은 SSOT 에 없다. 셋 중 무엇인지도 적혀 있지 않다.
|
||||
- §178 은 이 실험대의 대상 환경을 관측으로 적었다. test-server 는 Arch Linux 이고 이더넷 없이 WiFi 만 있어 브리지를 못 쓴다. 그래서 libvirt NAT(virbr0) 과 호스트 진입 구조를 택했고, 게스트는 Debian 12 genericcloud 3대로 엣지 1대와 k3s 2노드다.
|
||||
- §250 은 WiFi 에서 브리지가 안 되는 이유를 적었다. 802.11 데이터 프레임은 기본적으로 주소 필드가 3개다(3-address 모드). AP(Access Point, 무선 접속 장치)는 연결(association)된 단말(station)의 MAC 만 알고 있어서, 그 단말이 자기 것이 아닌 출발지 MAC 을 단 프레임을 보내면 버린다. 브리지된 가상 머신은 자기 MAC 을 출발지로 쓰므로 정확히 그런 프레임을 보낸다.
|
||||
- §250 이 든 우회 수단은 둘이다.
|
||||
4-address 모드(WDS) : AP 와 클라이언트 드라이버가 모두 지원해야 하는데 실제로는 거의 지원되지 않는다
|
||||
USB 이더넷 어댑터를 꽂는 것 : 현실적인 우회
|
||||
- §250 은 test-server 에 이더넷이 없고 wlo1 만 있어서 「VM 에 LAN IP 를 직접 주자」는 계획이 물리적으로 성립하지 않는다고 적었다. 이 제약 하나가 토폴로지 전체를 NAT + 호스트 nginx 로 확정시켰다고 밝혔다. 이더넷 인터페이스가 있는지는 ip -brief link 로 보고 무선 인터페이스 정보는 iw dev 로 본다고 확인 명령을 달았다.
|
||||
- §249 는 세 모드를 한 표로 놓고 이 실험대가 무엇을 골랐는지 적었다.
|
||||
NAT(virbr0) : VM 주소는 192.168.122.x 사설, LAN 에서 VM 접근 불가, 채택
|
||||
브리지(br0) : LAN 에서 직접 IP, WiFi 라 불가
|
||||
macvtap : LAN 에서 직접 IP(호스트↔VM 은 제외), WiFi 라 불가
|
||||
- §245 는 libvirt 의 default 네트워크를 소프트웨어 브리지 virbr0 과 거기 붙은 NAT 규칙으로 적었다. 기본 대역은 192.168.122.0/24 이고 호스트가 .1 을 가지며, VM 들은 이 브리지에 연결되어 서로 직접 통신하고 외부로 나갈 때만 호스트 IP 로 마스커레이딩된다. NAT 가 막는 것은 외부에서 VM 으로 들어오는 방향이다.
|
||||
- §201 은 이 호스트에서 ip -br addr show virbr0 을 돌린 출력을 남겼다. VM 세 대가 돌 때는 virbr0 이 UP 이고 192.168.122.1/24 을 갖고, 전부 철거한 뒤에는 주소는 그대로인 채 DOWN 이다.
|
||||
- §180 과 §255 는 밖에서 게스트로 들어오는 방향이 FORWARD 경로라 libvirt 의 guest_input 체인을 지난다고 적었다. 그 체인이 oif "virbr0" reject 로 끝나 게스트 대역으로 새로 들어오는 연결을 거절했고, 밖에서 친 curl 은 connection refused 를 받았다. 호스트 안에서 같은 게스트 주소로 친 curl 은 OUTPUT 경로라 forward 를 타지 않아 404 로 응답했다. 그 reject 줄을 범인으로 확정한 것은 카운터다. 밖에서 curl 을 네 번 쳤을 때 그 줄에 packets 4 bytes 240 이 찍혀 있었다.
|
||||
- 이 호스트에서 §122 OQ-1 의 다섯 명령을 돌린 출력은 SSOT 에 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트에 붙어 virsh 와 ip 계열 명령을 실행할 수 있다고 본다.
|
||||
- libvirt 가상 네트워크로 정의된 구성이면 virsh net-list --all 에 이름이 나온다고 본다. 호스트가 미리 만들어 둔 브리지에 가상 머신을 직접 붙인 구성이면 그 목록에 아무 이름도 나오지 않을 수 있다.
|
||||
- §201 과 §247 이 virsh net-update default 로 DHCP 예약을 넣었으므로 이 호스트의 가상 머신이 libvirt 의 default 네트워크를 쓴다고 본다. 그 네트워크 말고 다른 정의가 더 있는지는 열거해 봐야 갈린다.
|
||||
- 확인하는 동안 네트워크 구성이 바뀌지 않는다고 전제한다.
|
||||
- 셋 가운데 하나로 갈린다고 보고 물음을 세웠다. 다만 §114 가 Bridge 구성에도 Routing 과 NAT 과 Firewall 이 함께 걸릴 수 있다고 적었으므로, 하나로 갈리지 않으면 걸린 것을 모두 적는다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 이 호스트의 가상 머신 네트워크가 Bridge 기반인지 NAT 기반인지 Routing 기반인지.
|
||||
- libvirt 가상 네트워크로 정의되어 있는지, 아니면 호스트의 브리지에 가상 머신이 직접 붙어 있는지.
|
||||
- 정의되어 있다면 그 가상 네트워크의 forward mode 와 bridge 이름이 무엇인지.
|
||||
- 가상 머신을 떠난 프레임이 호스트의 L3/Netfilter 경로를 지나는지.
|
||||
- §178 과 §249 가 NAT 이라고 적은 것이 libvirt 네트워크 정의의 forward mode 로도 그렇게 적혀 있는지. virsh net-dumpxml default 를 통째로 찍은 출력이 SSOT 에 없고, §247 이 인용한 것은 그 정의의 dhcp 절뿐이다.
|
||||
- default 말고 정의된 가상 네트워크가 더 있는지. virsh net-list --all 의 출력이 없다.
|
||||
- virbr0 에 어느 인터페이스가 포트로 붙어 있는지, 그리고 이 호스트의 라우팅 테이블이 무엇인지. bridge link 와 ip route 의 출력이 없다.
|
||||
- 게스트끼리 오가는 프레임과 게스트가 밖으로 나가는 프레임이 호스트의 L3/Netfilter 경로를 지나는지. 밖에서 게스트로 들어오는 방향만 §180 이 FORWARD 로 관측했다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 구성이 셋 중 무엇인지를 확정하는 데서 끊는다. 그 구성이 지연에 얼마나 영향을 주는지는 부하 중 호스트 CPU 사용을 보는 물음이 받는다.
|
||||
- 이 호스트에서 읽은 출력이 없어 다른 장비의 구성을 근거로 삼지 않는다.
|
||||
- SSOT 에 남은 출력은 §201 의 virbr0 주소와 상태뿐이다. 나머지 네 명령은 다른 장비에서 읽은 값으로 대신하지 않는다.
|
||||
- 돌릴 명령은 §122 OQ-1 이 정해 두었다. 실행한 명령과 출력을 함께 남겨야 다음 사람이 같은 값을 다시 읽는다.
|
||||
|
||||
## 선택지
|
||||
@@ -86,11 +99,11 @@ libvirt 로 정의하지 않고 호스트 브리지에 직접 붙인 구성이
|
||||
|
||||
ip link 로 실재하는 인터페이스를 세우고, bridge link 로 어느 인터페이스가 어느 브리지의 포트인지를 잡고, ip route 로 L3 결정을 본다. libvirt 로 정의했든 안 했든 호스트에 실재하는 것을 읽으므로 구성 방식과 무관하게 답이 나온다.
|
||||
|
||||
forward mode 라는 이름으로 적힌 의도는 나오지 않으므로, NAT 이 걸려 있는지는 routing 과 방화벽 규칙을 따로 봐야 한다. §117.3 이 NAT/Firewall 오류에 든 것도 nftables · iptables · NAT rules · IP forwarding 이라는 확인 대상 이름이고 돌릴 명령이 아니다.
|
||||
forward mode 라는 이름으로 적힌 의도는 나오지 않으므로, NAT 이 걸려 있는지는 routing 과 방화벽 규칙을 따로 봐야 한다. §117.3 이 NAT/Firewall 오류에 든 것은 nftables · iptables · NAT rules · IP forwarding 이라는 확인 대상 이름이고 돌릴 명령이 아니다. 방화벽 쪽 명령은 §255 가 대신 적어 두었다 — libvirt 체인 하나를 열어 보는 sudo nft -a list chain ip libvirt_network guest_input 이다. 그 명령이 통하는 것은 이 호스트가 nftables 백엔드이기 때문이고, §180 은 libvirt 의 firewall_backend 가 iptables 일 때도 같은지는 재지 않았다고 적었다.
|
||||
|
||||
### 3. tcpdump 로 경로부터 잡는다 — 제외
|
||||
|
||||
§119 는 Host NIC · Bridge · TAP · Guest NIC 에서 tcpdump 로 패킷을 추적하는 순서를 적어 두었다. 다만 그 추적은 캡처를 걸 인터페이스 이름을 이미 알고 있을 때 성립한다. 지금은 브리지 이름도 TAP 이름도 모르므로 명령의 대상을 채울 수 없다. §126 의 실습 순서에서도 Bridge/NAT/Route 확인이 셋째이고 Host Nginx → VM packet path tcpdump 는 여덟째다. 이 방법은 이 물음이 닫힌 뒤 실제 패킷 경로를 묻는 물음이 받는다.
|
||||
§119 는 Host NIC · Bridge · TAP · Guest NIC 에서 tcpdump 로 패킷을 추적하는 순서를 적어 두었다. 다만 그 추적은 캡처를 걸 인터페이스 이름을 이미 알고 있을 때 성립한다. 브리지 이름은 §245 와 §201 이 virbr0 으로 적었지만 TAP 이름은 아직 없으므로 게스트 쪽 대상을 채울 수 없다. §126 의 실습 순서에서도 Bridge/NAT/Route 확인이 셋째이고 Host Nginx → VM packet path tcpdump 는 여덟째다. 이 방법은 이 물음이 닫힌 뒤 실제 패킷 경로를 묻는 물음이 받는다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
|
||||
+8
-6
@@ -23,9 +23,7 @@ source:
|
||||
|
||||
# packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
|
||||
|
||||
가상 머신이 밖과 통신하지 못할 때 게스트 안에서만 원인을 찾으면 호스트의 브리지와 TAP 연결은 마지막에야 보게 된다. 그 사이의 계층은 애플리케이션 로그에 아무것도 남기지 않는다.
|
||||
|
||||
그래서 패킷이 지나야 할 지점마다 캡처를 걸고 어디까지 보였는지로 구간을 좁힌다. 호스트의 물리 NIC(Network Interface Card) 와 브리지, 가상 머신에 붙은 TAP, 게스트 안의 인터페이스 넷이 그 지점이고, 보이지 않은 첫 지점의 앞 구간이 의심 구간이 된다.
|
||||
가상 머신이 밖과 통신하지 못하면 게스트부터 뒤지지 말고 패킷이 지나야 할 네 지점에 캡처를 걸어 어디까지 보였는지로 구간을 좁힌다. 호스트의 물리 NIC(Network Interface Card) 와 브리지, 가상 머신에 붙은 TAP, 게스트 안의 인터페이스가 그 지점이다. 보이지 않은 첫 지점의 앞 구간이 의심 구간이 된다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -44,7 +42,7 @@ source:
|
||||
|
||||
이 기준은 두 가지를 막는다.
|
||||
|
||||
가상 머신이 통신하지 못할 때 게스트 안쪽과 애플리케이션부터 뒤지느라 호스트의 브리지와 TAP 연결을 늦게 보는 일이 하나다.
|
||||
가상 머신이 통신하지 못할 때 게스트 안쪽과 애플리케이션부터 뒤지느라 호스트의 브리지와 TAP 연결을 늦게 보는 일이 하나다. 그 사이의 계층은 애플리케이션 로그에 아무것도 남기지 않는다.
|
||||
|
||||
오프로드 때문에 실제 wire 와 다르게 보이는 정상 패킷을 결함으로 판정하는 일이 다른 하나다.
|
||||
|
||||
@@ -90,7 +88,9 @@ tap 에는 보이는데 게스트 NIC 에 안 보이면 virtio 와 vhost, 게스
|
||||
|
||||
가상 머신에서 인터넷으로 나가지 못하거나 외부에서 가상 머신에 접근하지 못하거나 특정 포트만 실패하면 nftables 와 iptables, NAT(Network Address Translation) 규칙, IP(Internet Protocol) forwarding 설정을 확인 대상으로 둔다.
|
||||
|
||||
증상 셋을 각각 다른 기준으로 나누지 않은 것은 셋이 모두 어느 지점에서 끊겼는가로 환원되기 때문이다. 따로 적으면 같은 규칙의 부분 증상이 셋으로 늘어난다.
|
||||
이 실험대가 가장 오래 막힌 지점도 여기였다. 밖에서 온 요청만 엣지 게스트에 닿지 않았고, 거절한 것은 libvirt 가 자기 테이블의 guest_input 체인 끝에 둔 reject 규칙이었다(§180).
|
||||
|
||||
증상 셋을 각각 다른 기준으로 나누지 않은 것은 셋이 모두 어느 지점에서 끊겼는가 하나로 모이기 때문이다. 따로 적으면 같은 규칙의 부분 증상이 셋으로 늘어난다.
|
||||
|
||||
### 5. 패킷 크기와 체크섬이 예상과 다르다는 이유만으로 결함이라고 읽지 않는다
|
||||
|
||||
@@ -122,10 +122,12 @@ KVM(Kernel-based Virtual Machine)/QEMU/libvirt 로 만든 가상 머신이 외
|
||||
|
||||
브리지가 L2 전달만 하는 구성에서는 호스트의 L3 관측에 안 보이는 것이 정상인데, 여섯 번째 규칙이 그 경우다.
|
||||
|
||||
네 지점이 모두 보이는데 느린 경우는 이 기준이 다루지 않는다. Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다 쪽으로 넘긴다.
|
||||
네 지점이 모두 보이는데 느린 경우는 이 기준이 다루지 않는다. 「Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다」 쪽으로 넘긴다.
|
||||
|
||||
이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없다. 여기 적은 판독은 원문 문서가 서술한 것이고 이 호스트의 캡처로 확인한 것이 아니다.
|
||||
|
||||
§180 의 사건에서도 구간을 좁힌 것은 네 지점 캡처가 아니었다. 호스트에서 친 curl 은 404 를 받는데 밖에서 친 curl 만 connection refused 를 받았다는 차이가 단서였고, 범인은 그 reject 규칙의 카운터가 4 패킷 240 바이트로 밖에서 친 횟수와 맞아떨어져서 확정했다.
|
||||
|
||||
## 예시
|
||||
|
||||
- 물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보임 : 호스트의 브리지와 tap 연결을 먼저 확인한다
|
||||
|
||||
+6
-4
@@ -20,9 +20,7 @@ source:
|
||||
|
||||
# Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다
|
||||
|
||||
Refresh Token 경쟁 자체는 virtio-net 문제가 아니다. 다만 그 실험은 클라이언트에서 Nginx 와 가상 머신, K3s, Keycloak 을 거쳐 PostgreSQL 또는 Redis 까지 가는 경로를 여러 노드가 함께 쓴다. 그 경로 위의 네트워크 가상화 문제는 애플리케이션 동시성 문제와 비슷한 증상으로 나타난다.
|
||||
|
||||
노드 하나만 느리거나 특정 가상 머신에서만 요청이 실패하는 것을 Refresh Token 경쟁이나 데이터베이스 락으로 결론내지 않으려면, 실험 결과를 원인에 귀속하기 전에 네트워크 경로를 따로 검증한다.
|
||||
Refresh Token 경쟁 자체는 virtio-net 문제가 아니다. 다만 그 실험에서는 클라이언트에서 Nginx 와 가상 머신, K3s, Keycloak 을 거쳐 PostgreSQL 또는 Redis 까지 가는 경로를 여러 노드가 함께 쓴다. 그 경로 위의 네트워크 가상화 문제는 애플리케이션 동시성 문제와 비슷한 증상으로 나타난다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -55,6 +53,8 @@ Keycloak 멀티 노드 실험에서 관측되는 지연과 실패에는 네트
|
||||
|
||||
경로를 적지 않으면 어느 관측이 어느 구간을 덮는지 정해지지 않는다.
|
||||
|
||||
이 실험대에서 그렇게 어긋난 확인이 한 번 있었다. 04 단계의 확인 명령을 엣지 가상 머신 안에서 tailnet 주소로 쳤더니 connection refused 가 돌아왔는데, 엣지에서 나간 패킷은 호스트의 virbr0 으로 들어가고, 들어온 패킷의 도착지 주소를 바꿔 넘기는 호스트의 DNAT(Destination NAT, 도착지 주소 변환) 규칙은 tailscale0 으로 들어온 것만 매칭해서 안 걸렸기 때문이다(§190 · §182). 「설정 문제가 아니라 친 위치 문제다」가 그 단계가 남긴 한 줄이다.
|
||||
|
||||
### 2. 노드 하나에서만 나는 증상을 애플리케이션 동시성으로 먼저 읽지 않는다
|
||||
|
||||
노드 하나만 지연되거나 가상 머신 하나에서만 실패하는 증상은 그 노드로 가는 경로 쪽에서도 나올 수 있다. 호스트 브리지 구성 오류, NAT 와 conntrack 문제, 그 가상 머신 쪽 패킷 유실이 같은 모양으로 관측된다.
|
||||
@@ -91,7 +91,7 @@ vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다. 그래서
|
||||
|
||||
## 예외
|
||||
|
||||
이 기준은 애플리케이션 쪽 관측을 늘려서는 적용되지 않는다. Keycloak 이 게스트 소켓 위에서만 동작하므로 애플리케이션 로그로는 이 계층이 원인인지 가릴 수 없다.
|
||||
애플리케이션 쪽 관측을 늘리는 것으로는 이 기준을 적용할 수 없다. Keycloak 이 게스트 소켓 위에서만 동작하므로 애플리케이션 로그로는 이 계층이 원인인지 가릴 수 없다.
|
||||
|
||||
네트워크 계층이 깨끗하다고 해서 이 기준이 애플리케이션 결함을 배제해 주지는 않는다. 여기서 나오는 것은 네트워크가 원인이 아니라는 것까지다.
|
||||
|
||||
@@ -99,6 +99,8 @@ vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다. 그래서
|
||||
|
||||
원문 문서가 이 테스트 환경에 얹어 그린 경로는 확인된 것이 아니라 기준 구조를 그대로 옮겨 놓은 그림이다. 이 저장소에는 이 기준으로 원인을 실제로 가른 실험이 아직 없다.
|
||||
|
||||
가까운 것은 실험대를 세울 때 한 번 있었다. 밖에서 온 요청만 엣지에 닿지 않았는데 원인은 게스트 안이 아니라 호스트의 libvirt 방화벽 규칙이었고, 그때 엣지 nginx 는 호스트에서 친 요청에 404 로 응답하고 있었다(§180).
|
||||
|
||||
## 예시
|
||||
|
||||
- Keycloak 노드 하나만 응답이 느림 : 그 노드가 있는 가상 머신까지의 경로부터 확인한다
|
||||
|
||||
Reference in New Issue
Block a user