feat: 가상화 문서들 추가
This commit is contained in:
+341
@@ -0,0 +1,341 @@
|
||||
---
|
||||
id: 5b1de31c-0495-4226-8607-73ed7284b314
|
||||
kind: CONCEPT
|
||||
slug: guest-packet-path-to-physical-nic
|
||||
title: Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
basisVersion: Linux KVM/QEMU/libvirt · virtio-net frontend · vhost-net kernel backend · TAP · Linux Bridge
|
||||
studio: "https://hyeonworks.com/studio/documents/5b1de31c-0495-4226-8607-73ed7284b314/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
assets:
|
||||
- key: packet-control-and-data-paths
|
||||
file: ../../../final/assets/diagrams/packet-control-and-data-paths/packet-control-and-data-paths.svg
|
||||
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
|
||||
---
|
||||
|
||||
# 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 멀티 노드 실험을 돌리면 요청이 느려지거나 아예 닿지 않는 일이 생긴다. 이 경로를 알아 두면 그 증상을 애플리케이션·저장소 쪽 문제와 네트워크 가상화 계층 문제로 갈라 볼 수 있다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
|
||||
이 글이 세운 계층을 그대로 관측 지점으로 쓰는 절차다. 어느 계층까지 패킷이 보였는지로 의심 구간을 좁힌다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
이 경로가 실험의 여러 노드에 공유되기 때문에 생기는 오귀속을 막는 기준이다.
|
||||
- **이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가**
|
||||
이 글은 Bridge 와 라우팅, NAT 가 각각 무엇을 하는지까지만 적었다. 이 호스트가 그중 무엇으로 구성돼 있는지는 확인하지 않았다.
|
||||
- **VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가**
|
||||
TAP 이 게스트의 이더넷 프레임과 호스트 네트워크를 잇는 접점이라는 설명이 이 물음의 전제다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
백엔드가 QEMU 사용자 공간일 수도 vhost-net 일 수도 있다고 적었다. 이 호스트가 어느 쪽인지는 아직 모른다.
|
||||
- **QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가**
|
||||
두 백엔드의 경로 차이는 여기 적었지만, 그 차이가 지연이나 CPU 사용량으로 드러나는지는 재지 않았다.
|
||||
- **이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가**
|
||||
큐를 하나만 쓰면 부하가 몰릴 수 있다고만 적었다. 지금 큐가 몇 개인지는 확인하지 않았다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
여기 그린 경로는 가장 기본적인 조합을 기준으로 한 것이고, 이 테스트 환경의 실제 경로는 추적하지 않았다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다는 것까지가 이 글의 범위다.
|
||||
- **KVM 에서 vCPU 가 물리 CPU 에서 실행되기까지**
|
||||
QEMU 가 장치를 만들지만 반복 실행은 커널이 맡는다는 구조가 CPU 쪽과 같다. 그쪽 글이 같은 구분을 명령 실행으로 설명한다.
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## virtio-net 은 어디에 있는가
|
||||
|
||||
virtio 는 명령어가 아니고 프로그램 하나도 커널 모듈 하나도 아니다. 게스트와 호스트/하이퍼바이저가 가상 I/O 장치를 효율적으로 쓰려고 정해 둔 표준화된 인터페이스이자 프로토콜이다. 그 계열에는 네트워크의 virtio-net 과 블록 I/O 의 virtio-blk 가 있다. SCSI(Small Computer System Interface) 의 virtio-scsi 와 메모리 벌룬의 virtio-balloon 도 같은 계열이고, 이 글은 그중 virtio-net 을 다룬다.
|
||||
|
||||
가상 NIC 를 성립시키는 구현은 게스트와 호스트로 나뉘어 있다. 게스트 커널 쪽에는 TCP/IP 스택과 virtio-net 프런트엔드 드라이버, virtqueue 가 들어 있다.
|
||||
|
||||
```text label="Guest 측"
|
||||
Guest Kernel
|
||||
├─ TCP/IP Stack
|
||||
├─ virtio-net Frontend Driver
|
||||
└─ virtqueue
|
||||
```
|
||||
|
||||
호스트 쪽은 사용자 공간과 커널로 다시 갈린다. QEMU 프로세스 안에 virtio-net 장치 모델이 있고, 커널에는 vhost-net 과 TAP, Linux Bridge 와 라우팅·NAT, 물리 NIC 드라이버가 있다.
|
||||
|
||||
```text label="Host 측"
|
||||
Host Userspace
|
||||
└─ QEMU virtio-net Device Model
|
||||
|
||||
Host Kernel
|
||||
├─ vhost-net (사용하는 경우)
|
||||
├─ TAP
|
||||
├─ Linux Bridge / Routing / NAT
|
||||
└─ Physical NIC Driver
|
||||
```
|
||||
|
||||
그래서 virtio 는 특정 커널 계층 자체가 아니라 게스트 쪽 프런트엔드(frontend)와 호스트 쪽 백엔드(backend) 사이의 I/O 계약이다. 프런트엔드는 게스트 커널의 virtio-net 드라이버이고, 백엔드는 게스트가 넘긴 패킷 버퍼를 호스트 쪽에서 처리하는 구현이다. 이 백엔드 자리에는 QEMU 사용자 공간이 올 수도 있고 호스트 커널의 vhost-net 이 올 수도 있다.
|
||||
|
||||
둘 사이에 놓인 virtqueue 는 NIC 도 아니고 Linux 네트워크 인터페이스도 아니다. 게스트와 호스트 백엔드가 I/O 버퍼를 주고받으려고 쓰는 디스크립터 기반 공유 큐다. 네트워크에서는 보통 게스트에서 호스트로 가는 TX(transmit) virtqueue 와 호스트에서 게스트로 가는 RX(receive) virtqueue 를 쓴다. 페이로드를 매번 전통적인 사용자 공간 API 호출로 넘기는 방식이 아니라, 게스트 메모리의 버퍼와 디스크립터를 효율적으로 공유하고 참조하도록 설계돼 있다.
|
||||
|
||||
게스트 입장에서는 이 구조가 보이지 않는다. 가상 머신을 시작할 때 QEMU 가 가상 PCI(Peripheral Component Interconnect) 버스에 virtio NIC 를 노출한다. 그러면 게스트 Linux 가 그 장치를 발견하고 virtio-net 드라이버를 붙여 `ens3` 나 `eth0` 같은 인터페이스를 만든다. 그다음부터 게스트는 QEMU 를 호출한다고 동작하지 않고 자기 NIC 를 쓴다고 동작한다.
|
||||
|
||||
## 장치를 만드는 쪽과 패킷을 나르는 쪽
|
||||
|
||||
`virsh` 는 사용자가 libvirt 에 가상 머신 관리 명령을 전달하는 명령줄 도구여서 패킷이 지나는 길에는 직접 참여하지 않는다. libvirt 는 그 아래에서 vCPU 와 메모리, 디스크, NIC 모델, MAC 주소, 가상 네트워크, 브리지, QEMU 인자 같은 가상 머신의 수명 주기와 구성을 관리한다. 실제 프로세스로 실행되는 것은 QEMU 다.
|
||||
|
||||
QEMU 안의 virtio 장치 모델이 하는 일은 둘로 갈라서 봐야 뒤가 이어진다. 하나는 장치를 만들고 설정하고 관리하는 일이다. virtio-net 장치 모델을 만들어 게스트에게 노출하고, 기능 협상(feature negotiation)을 하고, virtqueue 를 설정하고, 백엔드를 연결한다. 다른 하나는 패킷을 실제로 나르는 처리인데, 이쪽은 QEMU 가 맡을 수도 맡지 않을 수도 있다. QEMU 백엔드를 직접 쓰면 패킷이 QEMU 를 지난다.
|
||||
|
||||
```text label="QEMU backend 를 직접 사용하는 경우"
|
||||
TAP
|
||||
↓
|
||||
QEMU virtio backend
|
||||
↓
|
||||
virtqueue
|
||||
↓
|
||||
Guest
|
||||
```
|
||||
|
||||
vhost-net 을 쓰면 반복되는 패킷 I/O 를 호스트 커널에서 처리하고 QEMU 사용자 공간을 우회한다.
|
||||
|
||||
```text label="vhost-net 을 사용하는 경우"
|
||||
TAP
|
||||
↓
|
||||
vhost-net
|
||||
↓
|
||||
virtqueue
|
||||
↓
|
||||
Guest
|
||||
```
|
||||
|
||||
이 구분에는 경로 이름이 따로 붙어 있다. 설정 경로(control/setup path)와 데이터 경로(data path)다. 여기서 control 은 Kubernetes 의 Control Plane 을 뜻하지 않고, 일반적인 시스템 용어로 설정·제어 경로를 가리킨다. `virsh` 에서 libvirt 와 QEMU, virtio-net 장치 모델로 내려가면서 기능 협상과 virtqueue 설정, vhost-net 설정이 일어나는 쪽이 설정 경로다. 그 설정이 끝난 뒤 패킷이 반복해서 흐르는 쪽이 데이터 경로다.
|
||||
|
||||
## 밖에서 들어온 패킷이 Keycloak 까지 올라오는 순서
|
||||
|
||||
가장 기본적인 virtio-net 과 vhost-net, TAP, Linux Bridge 조합을 기준으로 하면 수신 방향은 이 순서다.
|
||||
|
||||
```text label="수신 방향"
|
||||
Internet / Client
|
||||
↓
|
||||
Physical NIC
|
||||
↓
|
||||
Physical NIC Driver
|
||||
↓
|
||||
Linux Bridge / Routing / NAT
|
||||
↓
|
||||
TAP
|
||||
↓
|
||||
vhost-net
|
||||
↓
|
||||
RX virtqueue
|
||||
↓
|
||||
virtio-net Frontend Driver
|
||||
↓
|
||||
Guest TCP/IP Stack
|
||||
↓
|
||||
Socket
|
||||
↓
|
||||
Keycloak
|
||||
```
|
||||
|
||||
송신은 이 순서를 거꾸로 밟는다. Keycloak 이 소켓에 쓰면 게스트 TCP/IP 스택과 virtio-net 프런트엔드 드라이버를 지나 TX virtqueue 에 실린다. 거기서부터는 vhost-net 과 TAP, Linux Bridge 와 라우팅·NAT, 물리 NIC 드라이버를 차례로 지나 물리 NIC 로 나간다.
|
||||
|
||||
맨 앞의 물리 NIC(Network Interface Card, 네트워크 인터페이스 카드) 는 실제 네트워크 링크와 서버를 잇는 하드웨어다. 그 하드웨어를 호스트 커널의 드라이버가 제어하고 Linux 가 인터페이스로 노출하기 때문에, `ip link` 에 보이는 `enp3s0` 같은 인터페이스와 NIC 하드웨어를 같은 것으로 세지 않는다.
|
||||
|
||||
그다음의 Linux Bridge 는 호스트 커널 안에 있는 L2 소프트웨어 스위치다. 이더넷 프레임의 목적지 MAC(Media Access Control) 주소를 보고 어느 포트로 넘길지 정하고, MAC 주소를 학습하고, 여러 가상·물리 포트를 잇는다.
|
||||
|
||||
라우팅은 다른 계층에서 다른 값을 본다. 브리지가 L2 에서 MAC 주소를 보고 같은 이더넷 네트워크를 잇는다면, 라우팅은 L3 에서 목적지 IP(Internet Protocol) 주소를 보고 어느 인터페이스나 next-hop 으로 패킷을 보낼지 정한다. NAT(Network Address Translation) 는 또 다른 일을 해서 패킷의 IP 와 포트 정보를 바꾼다. 가상 머신이 사설 서브넷을 쓰면 호스트가 NAT 게이트웨이처럼 동작할 수 있다.
|
||||
|
||||
경로 그림에서는 셋이 한 줄에 나란히 적히지만 보는 값도 바꾸는 값도 서로 다르다. 그래서 실제 가상 머신 네트워크를 분석할 때는 브리지 기반인지 라우팅 기반인지 NAT 기반인지를 먼저 가른다.
|
||||
|
||||
TAP 은 호스트 Linux 커널이 제공하는 가상 이더넷 인터페이스이고 물리 장치가 아니다. `tap0` 나 `vnet0` 같은 이름으로 보이며, 가상 머신의 이더넷 프레임과 호스트 Linux 네트워크를 잇는 접점이 된다. 수신할 때는 Linux Bridge 에서 TAP 을 거쳐 가상 머신으로 들어가고, 송신할 때는 가상 머신에서 TAP 을 거쳐 Linux Bridge 로 나온다.
|
||||
|
||||
TAP 을 지나 게스트 안으로 들어오면 그다음은 평범한 Linux 네트워크 스택이다. 게스트의 TCP/IP 스택도 게스트 Linux 커널의 실제 스택이어서, 게스트 커널에는 소켓과 TCP, UDP, IP, 라우팅, neighbor/ARP, 방화벽, 네트워크 드라이버가 그대로 있다. TCP 는 연결 관리와 포트, 시퀀스, 순서 보장, 재전송, 중복 처리, 흐름 제어, 혼잡 제어를 맡는다. IP 계층은 IP 주소와 라우팅을 담당하고, NIC 에 가까운 계층에서는 이더넷 프레임과 MAC 주소를 다룬다.
|
||||
|
||||
그 위에서 애플리케이션이 보는 것은 소켓 하나다. 이더넷 프레임이 IP 패킷과 TCP 세그먼트를 지나 소켓에 닿고 그 위에서 HTTP 로 읽히면 Keycloak 이 요청을 처리한다.
|
||||
|
||||
```text label="Keycloak 이 요청 하나를 받기까지의 계층"
|
||||
Ethernet Frame
|
||||
↓
|
||||
IP Packet
|
||||
↓
|
||||
TCP Segment / Stream
|
||||
↓
|
||||
Socket
|
||||
↓
|
||||
HTTP
|
||||
↓
|
||||
Keycloak
|
||||
```
|
||||
|
||||
그래서 Keycloak 은 virtqueue 와 vhost-net, TAP, Bridge, 물리 NIC 를 직접 알 필요가 없고, 게스트 Linux 가 주는 TCP 소켓 위에서만 동작한다. 아래쪽 계층이 어긋나도 애플리케이션 로그에는 느렸다는 것과 실패했다는 것만 남는 이유가 여기에 있다.
|
||||
|
||||
## vhost-net 이 우회하는 것
|
||||
|
||||
QEMU 사용자 공간이 패킷마다 I/O 를 처리하면 호스트 커널과 사용자 공간을 오가는 전환 비용이 쌓인다. 초당 지나는 패킷이 많아질수록 그 전환과 스케줄링, 복사, 알림 비용이 커질 수 있다. vhost-net 은 그 반복 경로를 호스트 커널 쪽으로 옮겨서 컨텍스트 스위치와 사용자 공간 오버헤드를 줄인다.
|
||||
|
||||
QEMU 가 장치를 만들고 관리하는 주체라는 것과, 흐르는 패킷을 전부 QEMU 가 처리한다는 것은 다른 말이다. CPU 가상화에서 같은 구분을 이미 한 번 한다. QEMU 가 vCPU 를 만들지만 게스트의 `ADD`, `MOV`, `SUB` 를 전부 QEMU 가 실행하지는 않는다. 그 명령은 KVM(Kernel-based Virtual Machine) 과 VMX(Virtual Machine Extensions) 가 실행한다. 네트워크에서도 QEMU 가 가상 NIC 를 만들지만, 패킷 100만 개를 반드시 QEMU 가 하나씩 처리할 필요는 없다.
|
||||
|
||||
vhost-net 을 써도 QEMU 는 계속 필요하다. 가상 머신 수명 주기와 가상 하드웨어 모델, virtio 장치 생성, 기능 협상, 큐 설정, 백엔드 연결, 장치 reset, 설정 처리가 QEMU 에 남는다. 그래서 vhost-net 은 QEMU 를 없애는 것이 아니라, QEMU 가 맡던 반복적인 virtio 데이터 경로의 상당 부분을 호스트 커널로 넘긴다고 읽는다.
|
||||
|
||||
두 경로에는 이름이 따로 있다. 자주 반복되는 패킷 전달과 데이터 전송이 fast path 다. 장치 초기화와 기능 협상, 큐 설정, 설정 변경, 장치 reset 처럼 드물게 일어나면서 설정과 예외 처리를 맡는 쪽이 control/slow path 다. QEMU 는 뒤쪽에서 계속 중요한 역할을 한다.
|
||||
|
||||

|
||||
|
||||
## 이 경로를 일반화할 때 어긋나는 것
|
||||
|
||||
경로를 한 줄로 굳혀 놓으면 틀리는 그림이 셋 있다. 첫째는 패킷이 vhost-net 다음에 QEMU 를 반드시 지나는 것처럼 그린 것이다.
|
||||
|
||||
```text label="이렇게 일반화하지 않는다"
|
||||
TAP
|
||||
↓
|
||||
vhost-net
|
||||
↓
|
||||
QEMU
|
||||
↓
|
||||
virtqueue
|
||||
```
|
||||
|
||||
vhost-net 의 중요한 목적 하나가 데이터 경로에서 QEMU 사용자 공간을 우회하는 데 있다. 그래서 vhost-net 을 쓸 때의 fast path 는 TAP 에서 vhost-net 과 virtqueue 를 지나 게스트로 간다. QEMU 는 사라지지 않고 장치의 수명 주기와 설정을 관리한다.
|
||||
|
||||
둘째는 Bridge 를 지나는 프레임이 항상 호스트의 TCP/IP 스택을 거친다고 본 것이다. Bridge 가 L2 전달만 하는 경우 프레임이 호스트의 일반적인 L3 TCP/IP 스택을 반드시 거치지는 않는다. VM1 의 TAP 에서 Linux Bridge 를 지나 VM2 의 TAP 으로 가는 경로가 그렇다. 호스트가 라우팅이나 NAT, host-local termination, 방화벽 역할을 하면 그때 L3/Netfilter 경로가 개입한다. 그래서 물리 NIC 에서 호스트 TCP/IP 스택을 거쳐 Bridge 로 간다는 순서를 고정된 경로로 두지 않는다. 실제 경로는 브리지와 라우팅, NAT 구성에 따라 달라진다.
|
||||
|
||||
셋째는 호스트 물리 NIC 로 나갈 때 virtio 를 한 번 더 거친다고 본 것이다.
|
||||
|
||||
```text label="Host 물리 NIC 로 나가는 경로"
|
||||
Guest
|
||||
virtio-net
|
||||
↓
|
||||
vhost-net
|
||||
↓
|
||||
TAP
|
||||
↓
|
||||
Linux Bridge
|
||||
↓
|
||||
Intel NIC Driver
|
||||
↓
|
||||
Intel Physical NIC
|
||||
```
|
||||
|
||||
게스트 virtio 에서 호스트 virtio 를 거쳐 물리 NIC 로 가는 구조가 아니다. virtio 는 게스트의 가상 I/O 장치와 호스트 백엔드 사이의 인터페이스이고, 물리 NIC 로 나갈 때는 그 카드의 실제 드라이버를 쓴다.
|
||||
|
||||
## 복사와 알림, 큐 개수와 오프로드
|
||||
|
||||
네트워크 성능에서 큰 비용 하나가 패킷 데이터를 복사하는 일이다. virtio 와 virtqueue, vhost 구조는 버퍼 디스크립터를 써서 불필요한 복사와 컨텍스트 스위치를 줄이는 방향으로 설계돼 있다. 다만 이것을 항상 zero-copy 라고 일반화하지 않는다. 실제로 복사가 일어나는지는 커널 버전과 QEMU 버전, vhost 설정, 오프로드, NIC 의 기능, 패킷이 지나는 경로, GSO/GRO/TSO 에 따라 달라질 수 있다.
|
||||
|
||||
게스트와 호스트는 큐에 새 패킷이나 버퍼가 들어왔다는 것을 서로 알려야 한다. 게스트가 보낼 때는 virtqueue 에 디스크립터를 등록하고 호스트 백엔드에 알리면 백엔드가 처리하고, 받을 때는 호스트가 virtqueue 에 버퍼를 반영하고 게스트에 알리면 게스트 드라이버가 처리한다. 패킷마다 인터럽트와 알림이 지나치게 많이 발생하면 오버헤드가 커지기 때문에 batching 과 interrupt moderation, queueing 을 쓴다.
|
||||
|
||||
큐를 하나만 쓰면 특정 vCPU 나 처리 경로에 부하가 몰릴 수 있다. virtio-net 은 multi-queue 를 쓸 수 있고, RX 큐를 vCPU 마다 하나씩 붙여 패킷 처리를 병렬로 돌리고 큐 하나에 몰리는 병목을 완화한다. 효과는 부하의 성격과 CPU affinity, IRQ(Interrupt Request) 배치, 큐 설정에 따라 달라진다.
|
||||
|
||||
오프로드는 작은 패킷을 하나씩 처리하는 CPU 부담과 나누고 합치는 비용을 줄인다. TSO(TCP Segmentation Offload)와 GSO(Generic Segmentation Offload), GRO(Generic Receive Offload), 그리고 checksum offload 가 대표적이다. 오프로드가 켜져 있으면 `tcpdump` 에서 보이는 패킷 크기나 checksum 이 실제 wire 에서 보이는 것과 다르게 보일 수 있다.
|
||||
|
||||
## 이 구조에서 성능이 갈리는 두 조건
|
||||
|
||||
초당 지나는 패킷이 많은데 QEMU 사용자 공간이 데이터 경로를 직접 처리하면 CPU 부담이 커질 수 있다. 그때는 아래 다섯 가지를 함께 본다.
|
||||
|
||||
```text label="vhost-net 미사용 또는 비효율적 datapath 일 때 관찰"
|
||||
QEMU CPU usage
|
||||
vhost thread
|
||||
packet rate
|
||||
latency
|
||||
context switch
|
||||
```
|
||||
|
||||
큐 하나나 vCPU 하나에 패킷 처리가 몰릴 수도 있다. 이때는 큐 개수와 분산 설정을 확인 대상으로 둔다.
|
||||
|
||||
```text label="single queue bottleneck 일 때 확인 대상"
|
||||
virtio multi-queue
|
||||
IRQ distribution
|
||||
per-vCPU CPU usage
|
||||
RSS/RPS/XPS
|
||||
```
|
||||
|
||||
두 조건 모두 호스트 CPU 를 함께 쓴다. vhost-net 과 QEMU 스레드, softirq 가 호스트 CPU 를 쓰기 때문에, 네트워크 문제처럼 보이는 지연이 실은 CPU 스케줄링 문제일 수도 있다.
|
||||
|
||||
## 호스트에서 이 경로를 확인하는 명령
|
||||
|
||||
여기까지가 구조이고, 이 호스트가 실제로 그 구조인지는 명령으로 하나씩 확인한다. 물리 NIC 와 Bridge 는 인터페이스 목록과 전달 상태로 본다.
|
||||
|
||||
```bash label="Physical NIC 와 Linux Bridge"
|
||||
ip link
|
||||
ip addr
|
||||
ethtool <interface>
|
||||
ip link show type bridge
|
||||
bridge link
|
||||
bridge fdb show
|
||||
```
|
||||
|
||||
TAP 과 가상 머신의 NIC 연결, libvirt 가상 네트워크는 libvirt 쪽에서 확인한다. `virsh domiflist` 가 어느 가상 머신이 어느 TAP 에 붙어 있는지 알려 주고, `virsh net-dumpxml` 이 그 네트워크가 어떤 구성인지 알려 준다.
|
||||
|
||||
```bash label="TAP 과 libvirt VM NIC · 가상 network"
|
||||
ip tuntap show
|
||||
virsh domiflist <domain>
|
||||
virsh net-list --all
|
||||
virsh net-info <network>
|
||||
virsh net-dumpxml <network>
|
||||
```
|
||||
|
||||
라우팅과 게스트 안쪽, 그리고 virtio 장치와 vhost 모듈이 실제로 올라와 있는지는 각각 따로 본다.
|
||||
|
||||
```bash label="Routing · Guest NIC · virtio 와 vhost 모듈"
|
||||
ip route
|
||||
ip rule
|
||||
ip neigh
|
||||
lspci
|
||||
lsmod | grep virtio
|
||||
lsmod | grep vhost
|
||||
```
|
||||
|
||||
경로 위의 어느 지점까지 패킷이 보이는지는 계층마다 캡처해서 가른다.
|
||||
|
||||
```bash label="계층마다 packet 이 보이는지"
|
||||
sudo tcpdump -ni <physical-nic>
|
||||
sudo tcpdump -ni <bridge>
|
||||
sudo tcpdump -ni <tap-or-vnet>
|
||||
sudo tcpdump -ni <guest-interface>
|
||||
```
|
||||
|
||||
## 이 문서가 확인하지 않은 것
|
||||
|
||||
이 호스트에서 잰 값은 하나도 없다. 위의 명령들은 무엇을 볼 수 있는지 적어 둔 목록이고 아직 실행하지 않았다. 이 가상 머신들의 네트워크가 Bridge 인지 NAT 인지 라우팅인지, VM1 과 VM2 의 TAP 또는 vnet 인터페이스가 무엇인지를 아직 확인하지 않았다. vhost-net 이 실제로 데이터 경로를 맡고 있는지, multi-queue 가 켜져 있는지도 마찬가지다. 그래서 이 글은 「이 구조에서는 이렇게 동작한다」까지만 말하고 「이 서버가 그 구조다」라고는 말하지 않는다. QEMU 백엔드와 vhost-net 의 성능 차이가 이 호스트에서 관찰되는지, Keycloak 부하 시험에서 네트워크 가상화가 지연에 영향을 줄 만큼 호스트 CPU 를 쓰는지도 같은 상태다.
|
||||
|
||||
이 문서가 Keycloak 테스트 환경에 얹어 그린 경로도 마찬가지다. 호스트 Nginx 아래에 가상 머신 두 대가 있고 그 안에서 K3s 와 Keycloak 노드가 돈다는 앞부분은 실험 구성으로 밝혀 두었다. 그 아래를 브리지와 라우팅·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 의 기능에 따라 달라지므로, 버전이 바뀌어 이 서술이 낡았는지는 위 확인 명령을 실제 호스트에서 돌릴 때 드러난다.
|
||||
|
||||
가상 머신 위에 올린 K3s 안쪽도 이 문서 밖이다. K3s 의 CNI 와 Service, Pod 네트워크는 이 네트워크 가상화 위에 더해지는 계층이라 따로 분석한다.
|
||||
|
||||
확인 순서는 물리 NIC 에서 시작한다. 그다음 libvirt 가상 네트워크와 Bridge·NAT·Route 구성, 가상 머신별 TAP 또는 vnet, virtio-net 장치, vhost-net 사용 여부, 게스트 NIC 와 route 를 차례로 본다. 이어서 호스트 Nginx 에서 가상 머신까지 패킷이 지나는 길을 `tcpdump` 로 추적하고, VM1 과 VM2 사이의 경로와 Keycloak 요청 때의 패킷 흐름을 확인한다. 마지막으로 부하를 걸었을 때 QEMU 와 vhost 의 CPU 사용량을 비교하고 multi-queue 와 오프로드 설정을 본다. 검증되지 않은 항목은 열린 질문으로 두고, 실제 결과가 나오면 재현 조건을 붙인 기록으로 옮긴다.
|
||||
|
||||
<!-- body:end -->
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
---
|
||||
id: 600a2621-f6d8-42df-9629-7db65011545d
|
||||
kind: QUESTION
|
||||
slug: actual-packet-path-nginx-to-keycloak
|
||||
title: Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/600a2621-f6d8-42df-9629-7db65011545d/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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-최종-기준-구조
|
||||
---
|
||||
|
||||
# Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가
|
||||
|
||||
§116 은 이 테스트 환경의 요청 경로를 클라이언트에서 Keycloak 까지 한 줄로 그렸다. 가상 머신 네트워크까지 펼치면 물리 NIC 에서 브리지와 TAP 을 지나 vhost-net 과 virtqueue 를 거쳐 게스트 안으로 들어간다고 적었다. 그 펼친 그림은 §94 가 기준으로 삼은 구조를 이 환경에 얹은 것이고, 이 호스트에서 패킷을 잡아 본 결과가 아니다. 여기서 묻는 것은 호스트 Nginx 를 지난 요청이 실제로 어느 브리지와 어느 TAP 을 거쳐 어느 가상 머신으로 들어가는가 하나다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
§94 와 §125 가 그린 기준 경로를 이 개념이 설명한다. 이 물음은 그 경로가 이 호스트에서도 같은지를 묻는다.
|
||||
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
|
||||
§119 가 든 계층별 캡처 방법을 규칙으로 편 기준이다. 요청이 중간에서 끊기면 그쪽이 받는다.
|
||||
- **이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가**
|
||||
구성이 셋 중 무엇이냐에 따라 캡처를 걸 지점이 달라진다.
|
||||
- **VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가**
|
||||
tcpdump 를 걸 인터페이스의 이름을 그쪽이 댄다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
§120 이 요구한 별도 검증에서 이 경로 확인이 첫 항목이 된다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §116 이 그린 테스트 환경의 요청 경로
|
||||
Client → Host Physical NIC → Host Nginx → Host Network → VM1 / VM2 → K3s → Keycloak Node 1 / 2
|
||||
- §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 에 따라 달라질 수 있다고 밝혔다.
|
||||
- §125 는 같은 경로를 vhost-net 을 쓸 때와 QEMU backend 를 쓸 때로 나눠 다시 그렸다. 두 그림은 TAP 다음이 vhost-net 인지 QEMU virtio backend 인지에서 갈리고 나머지 구간은 같다.
|
||||
- §119 는 경로를 확인하는 방법으로 호스트의 physical NIC · bridge · tap 또는 vnet 세 곳과 게스트의 guest interface 한 곳에 sudo tcpdump -ni 를 걸고, 어디까지 보이는지로 의심 구간을 좁히라고 적었다.
|
||||
- §119 가 든 판정 예 셋
|
||||
Physical NIC O · Bridge O · TAP X : Guest 내부보다 먼저 Host Bridge/TAP mapping 을 의심한다
|
||||
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 의 기준 구조를 이 환경에 얹은 그림이다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낼 수 있고, 그 요청이 두 가상 머신 가운데 어느 쪽으로 갔는지 확인하는 쪽이 알 수 있다고 본다.
|
||||
- 네 지점에 동시에 캡처를 걸어 둘 수 있다고 전제한다. 지점마다 따로 걸면 같은 요청을 본 것인지 갈리지 않는다.
|
||||
- §116 이 그린 구조가 지금 실험 환경과 같다고 전제한다. 가상 머신이 둘이고 각각 K3s 노드와 Keycloak 을 돌린다는 것까지가 근거 문서에 적힌 전부다.
|
||||
- 오프로드 설정이 캡처하는 동안 바뀌지 않는다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 호스트 Nginx 를 지난 요청이 어느 브리지를 거치는지, 그 브리지에서 어느 TAP 으로 나가는지.
|
||||
- 그 TAP 이 두 가상 머신 가운데 어느 쪽의 인터페이스인지.
|
||||
- 게스트 안의 인터페이스에서 같은 요청이 보이는지.
|
||||
- 네 지점의 결과가 §116 이 펼친 그림과 같은지, 다르다면 어느 지점부터 다른지.
|
||||
- 지금 오프로드 설정이 무엇인지. 캡처에서 본 패킷 크기와 체크섬을 wire 값으로 읽어도 되는지가 이것으로 갈린다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 캡처 지점의 이름을 먼저 확정해야 한다. 어느 브리지와 어느 TAP 인지 모르면 tcpdump 를 걸 곳을 고르지 못한다. 그 이름은 네트워크 구성을 묻는 물음과 인터페이스를 묻는 물음이 댄다.
|
||||
- K3s 안에서 Keycloak Pod 까지 가는 구간은 이 물음이 닫는 범위 밖이다. §116 이 CNI · Service · Pod network 를 별도 계층으로 미뤄 두었다.
|
||||
- 요청이 중간 지점에서 끊기면 그것은 이 물음의 답이 아니라 장애다. §119 가 든 세 판정 예를 따라 의심 구간을 적고 계층별 캡처 기준으로 넘긴다.
|
||||
- 이 호스트에서 잰 값이 없어 §116 의 그림을 확인된 경로로 삼지 않는다. 이 환경이 실제로 그렇다는 주장이라 재기 전에는 Case 도 Concept 도 아니라고 보고 근거가 모자란 후보로 남겨 두었으며, OQ-1 과 OQ-2, OQ-3, OQ-6 이 답하면 다시 판정한다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 네 지점에 한 번에 걸고 요청을 한 번 보낸다
|
||||
|
||||
§119 가 든 호스트 세 지점과 게스트 한 지점에 동시에 tcpdump 를 걸어 두고, 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낸다. 같은 요청 하나가 네 지점에서 각각 보이는지로 경로가 확정되기 때문에 실행이 한 번으로 끝난다.
|
||||
|
||||
지점 이름을 미리 확정해 두어야 하고 네 곳을 동시에 열어 두어야 한다.
|
||||
|
||||
### 2. 바깥에서 안쪽으로 한 지점씩 옮겨 간다
|
||||
|
||||
물리 NIC 에서 시작해 브리지, TAP, 게스트 인터페이스 순으로 한 지점씩 옮기며 같은 요청을 반복해서 보낸다. 여러 곳을 동시에 열지 않아도 되고 어디서부터 안 보이는지가 바로 드러난다.
|
||||
|
||||
요청을 여러 번 보내야 해서 매번 같은 경로로 갔다고 전제해야 한다. 두 가상 머신에 요청이 번갈아 가면 그 전제가 깨진다.
|
||||
|
||||
### 3. 두 가상 머신 쪽 TAP 을 모두 열어 놓고 한 번 보낸다
|
||||
|
||||
VM1 과 VM2 의 TAP 을 둘 다 열어 두면 요청이 어느 쪽으로 갔는지까지 같은 실행에서 나온다. §120 이 든 「Node1 요청만 지연」 같은 증상을 나중에 볼 때 어느 경로를 먼저 열어야 하는지도 이 기록에서 나온다.
|
||||
|
||||
캡처 지점이 다섯으로 늘어난다.
|
||||
|
||||
### 4. 제외 — 호스트 Nginx 설정에서 경로를 읽는다
|
||||
|
||||
Nginx 가 어느 주소로 요청을 넘기는지 설정만 읽어도 어느 가상 머신으로 가는지는 알 수 있다. 그러나 이 물음은 설정이 말하는 경로가 아니라 패킷이 실제로 지나는 계층을 묻는다. §116 이 그린 그림이 확인된 것이 아니라는 데서 물음이 시작했으므로, 설정을 읽으면 같은 종류의 근거가 하나 더 늘어난다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. 캡처를 걸 지점의 이름을 먼저 확정한다. 어느 브리지와 어느 TAP 인지는 네트워크 구성을 묻는 물음과 인터페이스를 묻는 물음이 답한다.
|
||||
2. 호스트에서 sudo tcpdump -ni 뒤에 physical NIC 이름 · bridge 이름 · tap 또는 vnet 이름을 넣어 세 곳에 걸고, 게스트에서 같은 명령을 guest interface 이름에 건다 (§122 OQ-6 · §119).
|
||||
3. 호스트 Nginx 를 통해 Keycloak 요청을 한 번 보낸다.
|
||||
4. 네 지점에서 그 요청이 보였는지를 §119 처럼 O 와 X 로 적는다.
|
||||
5. 캡처하는 동안의 오프로드 상태를 함께 적는다. §113 은 오프로드가 켜져 있으면 tcpdump 에서 보이는 패킷 크기나 체크섬이 실제 wire 에서 보이는 것과 다르게 보일 수 있다고 적었다.
|
||||
|
||||
닫는 조건 : 네 지점의 캡처 결과로 실제 경로를 한 줄로 적으면 닫는다. §116 이 펼친 그림과 같으면 그 그림을 이 호스트에서 확인된 경로로 올리고, §116 을 근거로 삼는 후보를 다시 판정한다. 다르면 어느 지점부터 다른지를 적고 §119 의 판정 예대로 그 구간을 의심 구간으로 넘긴다. 요청이 중간 지점에서 끊기면 그것은 이 물음의 답이 아니므로 계층별 캡처 기준으로 넘긴다.
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
---
|
||||
id: 484fd832-c7d3-413e-897a-97892e4e10ac
|
||||
kind: QUESTION
|
||||
slug: is-vhost-net-actually-in-use
|
||||
title: 이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/484fd832-c7d3-413e-897a-97892e4e10ac/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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
|
||||
---
|
||||
|
||||
# 이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가
|
||||
|
||||
§103 은 패킷이 TAP 에서 게스트로 올라오는 길을 두 가지로 갈라 적었다. QEMU 백엔드를 직접 쓰면 QEMU virtio backend 가 그 사이에 들어가고, vhost-net 을 쓰면 호스트 커널의 vhost-net 이 들어간다. 둘 중 어느 쪽이 이 호스트에서 돌고 있는지는 SSOT 에 없어서, 이 물음은 가상 머신 두 대 각각의 데이터 경로 백엔드를 확정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
그 경로 그림이 vhost-net 을 쓰는 구성을 기준으로 그려져 있어서, 이 호스트가 그 기준에 해당하는지를 이 물음이 정한다.
|
||||
- **QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가**
|
||||
비교하려면 지금 어느 백엔드로 돌고 있는지가 먼저 정해져야 한다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
§117.4 가 든 CPU 오버헤드는 QEMU 사용자 공간이 데이터 경로를 직접 처리할 때의 이야기다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
TAP 과 virtqueue 사이에 무엇이 있는지가 그 경로 서술의 한 칸을 채운다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §103 은 QEMU 의 virtio Device Model 이 호스트 사용자 공간의 QEMU 프로세스 안에 있다고 적고, 그 역할을 둘로 나눴다. 하나는 장치 생성/설정/관리이고 다른 하나는 실제로 패킷을 나르는 처리다.
|
||||
- §103 이 적은 데이터 경로 두 가지는 이렇게 갈린다.
|
||||
QEMU backend 를 직접 쓰는 경우 : TAP → QEMU virtio backend → virtqueue → Guest
|
||||
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 비용이 커질 수 있다고 적었다.
|
||||
- §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 를 들었다.
|
||||
- 확인 명령으로 §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 에 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트에 붙어 lsmod 를 실행하고 libvirt 설정을 읽을 수 있다고 본다.
|
||||
- 모듈이 올라와 있다는 것과 그 가상 머신이 그 백엔드를 쓴다는 것을 다른 사실로 놓고 물음을 세웠다. §103 은 백엔드 선택을 가상 머신의 구성으로 적었지 모듈 적재로 적지 않았다.
|
||||
- 두 가상 머신이 같은 백엔드를 쓴다고 전제하지 않는다. 가상 머신마다 따로 읽어 각각 적는다.
|
||||
- 읽는 동안 가상 머신을 재시작하지 않는다고 전제한다. 백엔드는 §105 가 적은 설정 경로에서 정해지므로 재시작하면 달라질 수 있다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 이 호스트에 vhost 커널 모듈이 올라와 있는지.
|
||||
- 두 가상 머신의 libvirt domain 설정과 QEMU arguments 가 vhost 백엔드를 쓰도록 되어 있는지.
|
||||
- 그래서 지금 흐르는 패킷이 §103 이 그린 두 경로 가운데 어느 쪽으로 가는지.
|
||||
- QEMU arguments 와 libvirt domain XML 을 이 환경에서 어떤 명령으로 읽는지. 제3부가 그 명령을 적지 않아 실행하는 쪽이 정한다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 백엔드가 무엇인지를 확정하는 데서 끊는다. 두 백엔드의 성능 차이는 그것을 비교하는 물음이 받는다.
|
||||
- 이 호스트에서 읽은 설정이 없어 §94 와 §125 가 기준으로 삼은 vhost-net 구성을 이 호스트의 값으로 쓰지 않는다.
|
||||
- 명령을 SSOT 가 하나만 주었으므로, 나머지 둘을 무엇으로 읽었는지 실행한 명령과 출력을 함께 남긴다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 모듈 적재부터 보고 가상 머신 설정으로 좁힌다
|
||||
|
||||
lsmod | grep vhost 로 호스트에 그 기능이 있는지 먼저 보고, 나오면 가상 머신마다 설정을 읽어 실제로 쓰는지 좁힌다. 모듈이 아예 없으면 두 대 모두 QEMU 백엔드라는 답이 한 번에 나온다.
|
||||
|
||||
모듈이 있을 때는 이 명령만으로 아무것도 정해지지 않아서 결국 가상 머신 설정을 읽어야 한다.
|
||||
|
||||
### 2. 가상 머신 설정부터 읽고 모듈 적재로 뒷받침한다
|
||||
|
||||
두 가상 머신의 libvirt domain 설정과 QEMU arguments 에서 백엔드 지정을 먼저 읽고, lsmod 출력으로 그 설정이 실제로 성립할 수 있는지 뒷받침한다. 가상 머신마다 다른 답이 나오는 경우까지 한 번에 잡힌다.
|
||||
|
||||
설정을 읽는 명령을 SSOT 가 주지 않아서 무엇으로 읽었는지 따로 적어야 한다.
|
||||
|
||||
### 3. §117.4 의 관찰 대상으로 되짚는다 — 제외
|
||||
|
||||
호스트에 vhost 스레드가 보이는지, 부하 중 QEMU CPU 가 어떻게 움직이는지로 백엔드를 역추정하자는 방법이다. 그 관찰은 부하를 걸어야 값이 생기고, §117.4 는 그 목록을 성능 문제를 진단할 때 볼 것으로 적었다. 지금 필요한 것은 설정이 무엇으로 되어 있는가 하나다. 그것은 부하 없이 읽힌다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. lsmod | grep vhost 로 vhost 커널 모듈이 올라와 있는지 본다.
|
||||
2. 두 가상 머신의 libvirt domain 설정에서 인터페이스의 driver 지정을 읽는다. 무엇으로 읽었는지 명령을 함께 적는다.
|
||||
3. 같은 가상 머신의 QEMU 실행 인자에서 백엔드 지정을 읽는다. 이것도 명령을 함께 적는다.
|
||||
4. 세 출력을 가상 머신별로 짝지어 적고 실행한 명령과 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 가상 머신 두 대 각각의 데이터 경로 백엔드가 vhost-net 인지 QEMU 사용자 공간인지 설정으로 확정되면 닫는다. vhost-net 이면 §125 의 「Data Path - vhost-net 사용」 이 이 호스트의 경로라고 적고, QEMU 백엔드면 「Data Path - QEMU backend 사용」 쪽이라고 적는다. 어느 쪽이든 그 결과가 QEMU backend 와 vhost-net 을 견주는 물음의 비교 대상 하나를 고정한다. 두 대가 서로 다르게 나오면 그 사실을 적고, 이후 측정에서 둘을 같은 조건으로 묶지 않는다.
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
---
|
||||
id: 79ac61d6-cbe6-483b-9961-02ca8c02b5c2
|
||||
kind: QUESTION
|
||||
slug: network-virtualization-cpu-cost-under-load
|
||||
title: 부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/79ac61d6-cbe6-483b-9961-02ca8c02b5c2/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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-실험과의-관계
|
||||
---
|
||||
|
||||
# 부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가
|
||||
|
||||
§117.7 은 vhost-net 과 QEMU 스레드와 softirq 도 호스트 CPU 를 쓰므로, 네트워크 문제처럼 보이는 것이 CPU 스케줄링 문제일 수 있다고 적었다. 그 셋 가운데 QEMU 스레드와 게스트 쪽 지표는 CPU 가상화를 다루는 물음 둘이 이미 같은 실험 구간에서 재기로 해 두었다. 그래서 여기서는 그 둘이 보지 않는 vhost 커널 스레드와 softirq 만 본다. Keycloak 부하 시험 구간에서 이 둘이 호스트 CPU 를 얼마나 쓰는지, 그 사용량이 네트워크 지연과 같이 움직이는지로 물음을 좁힌다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
vhost-net 이 데이터 경로의 어느 구간을 맡는지를 이 개념이 설명한다. 여기서 재려는 커널 스레드가 그 구간을 돌린다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
§120 이 요구한 별도 검증을 규칙으로 편 기준이다. 이 측정이 없으면 그 검증을 마쳤다고 적을 수 없다.
|
||||
- **QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가**
|
||||
백엔드를 바꿔 견주는 물음이라 §122 가 든 관찰 대상을 상당 부분 함께 쓴다. 여기서 찍은 기준값을 그쪽이 그대로 받는다.
|
||||
- **이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가**
|
||||
큐가 하나로 나오면 §117.5 가 든 쏠림이 이 측정의 vCPU 별 사용량에서 드러난다.
|
||||
- **Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가**
|
||||
Guest steal time 과 QEMU vCPU 스레드는 그쪽이 잰다. 같은 실험 구간에서 두 기록을 함께 남기고 여기서는 vhost 커널 스레드와 softirq 만 새로 잰다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §117.7 은 vhost-net · QEMU thread · softirq 도 호스트 CPU 를 쓰고, 따라서 네트워크 문제처럼 보여도 CPU 스케줄링 문제일 수 있다고 적었다.
|
||||
- §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 요청만 지연
|
||||
VM2 packet loss
|
||||
Host bridge misconfiguration
|
||||
NAT/conntrack issue
|
||||
Host CPU contention으로 vhost 처리 지연
|
||||
- §122 OQ-7 이 든 관찰 대상 여섯
|
||||
QEMU CPU
|
||||
vhost thread
|
||||
softirq
|
||||
Host CPU
|
||||
Guest CPU
|
||||
network latency
|
||||
- 이 여섯 가운데 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 을 계속 맡는다고 적었다.
|
||||
- 이 호스트에서 부하 구간의 vhost 스레드 CPU 사용량이나 softirq 시간을 잰 기록이 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- Keycloak 부하 시험을 돌릴 수 있고, 부하 구간과 그 직전 구간을 나눠 기록할 수 있다고 본다.
|
||||
- 호스트에서 vhost 커널 스레드를 스레드 단위로 구분해 볼 수 있다고 전제한다. §108 이 vhost-net 을 써도 QEMU 가 설정과 수명 주기를 계속 맡는다고 적었으므로, QEMU 프로세스의 CPU 사용량과 vhost 커널 스레드의 CPU 사용량을 따로 세야 한다.
|
||||
- 부하 도구가 네트워크 지연을 이미 내고 있다고 전제한다. 그 도구가 어떤 값을 어떤 주기로 내는지는 근거 문서에 적혀 있지 않다.
|
||||
- 호스트와 게스트 둘의 시각을 맞춰 읽을 수 있다. 시계가 어긋나면 세 값을 같은 부하 구간에 겹쳐 놓지 못한다.
|
||||
- 호스트 쪽 Nginx 도 같은 물리 CPU 를 쓴다. 부하 구간의 호스트 CPU 상승을 전부 네트워크 가상화 몫으로 읽으면 이 전제가 깨진다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 부하를 걸기 전 vhost 커널 스레드의 CPU 사용량과 softirq 시간.
|
||||
- 부하 구간에서 그 둘이 얼마나 오르는지.
|
||||
- 오른 몫이 QEMU vCPU 스레드 사용량과 어떻게 나뉘는지.
|
||||
- vhost 커널 스레드와 softirq 의 움직임이 네트워크 지연과 같은 시간축에서 함께 움직이는지.
|
||||
- 두 지표가 얼마나 움직여야 실험 결과를 다르게 읽어야 하는지. 그 문턱을 아직 정하지 않았다.
|
||||
- softirq 시간을 이 환경에서 어떤 도구로 읽는지. 근거 문서가 명령을 적지 않아 실행하는 쪽이 정한다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 실험 조건을 바꾸지 않고 관찰만 덧붙인다. CPU 가상화 쪽 물음이 같은 실험 구간을 쓰기로 되어 있어 부하 수준을 바꾸면 두 기록을 겹쳐 읽지 못한다.
|
||||
- 기준값을 먼저 찍는다. 부하 구간의 값만 있으면 그것이 평소 값인지 부하 때문에 오른 값인지 판정할 수 없다.
|
||||
- 이 물음이 새로 만드는 값은 vhost 커널 스레드 사용량과 softirq 시간 둘이다. QEMU CPU 와 Guest CPU 와 steal time 은 CPU 가상화 쪽 기록을 그대로 쓰고, 네트워크 지연은 부하 도구가 낸 값을 쓴다.
|
||||
- 두 지표가 움직이지 않았다는 결과가 나와도 Refresh Token 실험의 결론이 바뀌지는 않는다. §120 이 Refresh Token 경쟁과 네트워크 가상화를 별개 문제로 놓았기 때문에, 여기서 갈리는 것은 그 실험 결과를 애플리케이션과 저장소 쪽으로 읽어도 되는지 하나다.
|
||||
- 이 호스트에서 잰 값이 없어 다른 장비의 수치를 근거로 삼지 않는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 실험을 그대로 두고 vhost 스레드와 softirq 만 덧붙여 잰다
|
||||
|
||||
CPU 가상화 쪽 물음이 이미 같은 구간에서 Guest steal time 과 QEMU vCPU 스레드를 기록하므로, 여기서는 그 기록에 없는 둘을 같은 시각에 붙인다. 실험 조건을 건드리지 않아서 두 기록을 겹쳐 읽을 수 있다.
|
||||
|
||||
이 방법으로는 이번 부하 수준에서 두 지표가 움직였는지 하나만 알 수 있다.
|
||||
|
||||
### 2. 부하 직전 구간을 기준값으로 따로 찍는다
|
||||
|
||||
부하를 걸기 전에 §122 OQ-7 의 여섯을 한 번 찍어 두면 부하 구간의 값을 견줄 대상이 생긴다. 기준값 없이 부하 구간만 찍으면 vhost 스레드 사용량이 어떤 값으로 나오든 그것이 평소 값인지 부하 때문에 오른 값인지 판정하지 못한다.
|
||||
|
||||
### 3. network latency 를 같은 시간축에 올려 함께 본다
|
||||
|
||||
vhost 스레드와 softirq 가 올라도 지연이 그대로면 이 부하 수준에서는 지연을 바꾸지 않았다고 적을 수 있다. §122 OQ-7 이 network latency 를 여섯째 관찰 대상으로 둔 이유가 여기에 있다. 대신 호스트와 부하 도구의 시각을 맞춰야 세 값을 겹쳐 놓을 수 있다.
|
||||
|
||||
### 4. 제외 — 초당 패킷 수를 올려 vhost 처리를 포화시켜 견준다
|
||||
|
||||
§107 은 초당 지나는 패킷이 많아질수록 전환과 복사와 알림 비용이 커질 수 있다고 적었으므로, 그 수를 올리면 vhost 처리 비용이 더 잘 드러난다. 그러나 이 물음은 Keycloak 부하 시험 구간에서 네트워크 가상화가 결과를 흔들었는지를 묻는 것이라, 부하를 다르게 걸고 잰 값은 그 답이 되지 않는다. 포화 구간과 견주는 측정은 별도 부하 Case 로 뺀다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. 부하를 걸기 전 §122 OQ-7 이 든 여섯을 한 번 찍어 기준값으로 둔다.
|
||||
2. Keycloak 부하 시험을 돌리면서 같은 여섯을 같은 시각에 기록한다. 호스트에서는 QEMU 프로세스와 vhost 커널 스레드의 CPU 사용량을 스레드 단위로, softirq 시간을, 호스트 전체 CPU 를 적는다.
|
||||
3. 각 게스트의 CPU 사용량과 부하 도구가 낸 네트워크 지연을 같은 구간에서 적는다.
|
||||
4. vhost 커널 스레드와 softirq 를 읽는 데 쓴 명령을 함께 남긴다. §14.7 의 ps -eLo pid,tid,psr,pcpu,comm | grep qemu 는 qemu 로 걸러 내 vhost 커널 스레드를 내지 않고, softirq 를 읽는 명령은 근거 문서에 없다.
|
||||
5. Guest steal time 과 QEMU vCPU 스레드 쪽은 「Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가」가 같은 구간에서 재므로, 두 기록을 한 실험에서 함께 남긴다.
|
||||
|
||||
닫는 조건 : 부하 구간의 vhost 커널 스레드 사용량과 softirq 시간이 기준값과 다르지 않고 네트워크 지연도 움직이지 않으면, 이 부하 수준에서는 네트워크 가상화가 지연에 영향을 줄 만큼 호스트 CPU 를 쓰지 않는다고 적고 닫는다. 셋 중 하나라도 움직이면 그 부하 전후 표가 Case 가 되고, vhost 스레드를 어느 CPU 에 둘지나 multi-queue 를 켤지는 그 Case 뒤에 Decision 으로 넘긴다. 어느 쪽이든 이 결과가 없으면 §120 이 경고한 오귀속, 곧 네트워크 지연을 Refresh Token 경쟁으로 읽는 것을 배제했다고 적을 근거가 없다.
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
---
|
||||
id: bded6560-dc8d-473d-966c-5b037bb84c4c
|
||||
kind: QUESTION
|
||||
slug: qemu-backend-vs-vhost-net-on-this-host
|
||||
title: QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/bded6560-dc8d-473d-966c-5b037bb84c4c/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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
|
||||
---
|
||||
|
||||
# QEMU backend 와 vhost-net 의 차이가 이 호스트에서 실제로 보이는가
|
||||
|
||||
backend 는 virtqueue 를 사이에 두고 게스트와 버퍼를 주고받는 호스트 쪽을 가리킨다. §107 은 패킷 처리를 QEMU 사용자 공간(userspace)에서 호스트 커널로 옮기면 컨텍스트 스위치와 사용자 공간 오버헤드가 줄어든다고 적었다. 줄어든다는 방향만 적혀 있을 뿐 이 호스트에서 두 backend 를 나란히 재 본 값은 없다. §110 이 실제로 복사가 일어나는지는 커널 버전과 offload 를 비롯한 여러 조건에 따라 달라질 수 있다고 밝혔으므로, 다른 환경에서 나온 수치를 이 호스트의 값으로 옮겨 쓸 수도 없다. 이 물음은 §122 OQ-4 가 든 여섯 축을 이 호스트에서 나란히 재서 차이가 보이는지 가른다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
그 경로에서 두 backend 가 갈리는 곳은 TAP 다음 한 칸이고, 이 물음은 거기서 무엇이 달라지는지를 잰다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
지금 어느 쪽으로 돌고 있는지가 정해져야 견줄 두 값 가운데 한쪽이 고정된다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
두 물음이 QEMU CPU 와 Host CPU 를 같은 부하에서 읽으므로 측정을 한 번으로 묶을 수 있다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
backend 차이가 지연에 얼마나 들어오는지를 이 물음이 재면, 그 기준이 그 값을 가져다 쓴다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §107 은 QEMU 가 사용자 공간에서 패킷마다 I/O 를 처리하면 호스트 커널과 QEMU 사용자 공간 사이를 오가는 전환이 쌓인다고 적었다. 초당 패킷 수(packet rate)가 높아질수록 사용자 공간과 커널 사이의 전환 · 스케줄링 · 복사 · 알림 비용이 커질 수 있다.
|
||||
- §107 이 적은 두 구성은 TAP 다음에 무엇이 오는지로 갈린다.
|
||||
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 라고 일반화하면 안 된다고 못 박았다. 실제로 복사가 일어나는지는 아래에 따라 달라질 수 있다.
|
||||
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 를 들었다.
|
||||
- §122 OQ-4 는 비교할 축 여섯을 적었다.
|
||||
Latency
|
||||
Throughput
|
||||
QEMU CPU
|
||||
Host CPU
|
||||
Context Switch
|
||||
Packet rate
|
||||
- §122 OQ-4 는 축의 이름만 적어 두었고, 여섯을 무슨 도구로 어떻게 재는지는 제3부에 없다. 같은 §122 에서 OQ-1 과 OQ-2 는 돌릴 명령을 그대로 적었고 OQ-3 은 lsmod | grep vhost 를 확인 후보로 들었다.
|
||||
- 이 호스트에서 두 backend 를 재 본 값은 SSOT 에 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 같은 가상 머신을 다른 backend 로 다시 구성해 띄울 수 있다고 본다. 그것이 이 실험 환경에서 되는지는 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 이다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 지금 backend 만 먼저 찍어 나중에 견줄 값을 만든다
|
||||
|
||||
구성을 바꾸지 않고 부하 전과 부하 중의 여섯 축을 한 번씩 기록한다. 가상 머신을 다시 구성하지 않으므로 지금 돌고 있는 Keycloak 실험을 멈추지 않아도 되고, 나중에 다른 backend 를 잴 때 견줄 값이 생긴다.
|
||||
|
||||
한 구성의 값만으로는 이 물음이 닫히지 않는다.
|
||||
|
||||
### 2. 두 backend 로 바꿔 가며 같은 부하를 건다
|
||||
|
||||
§122 OQ-4 가 요구하는 비교가 이것이다. 같은 가상 머신을 다른 backend 로 다시 구성하고 같은 부하를 양쪽에 걸어 여섯 축을 같은 시각에 기록한다. 차이가 나면 그 표가 그대로 Case 가 된다.
|
||||
|
||||
가상 머신을 다시 구성하고 재시작해야 하므로 그동안 Keycloak 실험을 멈춰야 하고, 두 측정 사이에 호스트 상태가 달라지지 않도록 관리해야 한다.
|
||||
|
||||
### 3. 문헌의 backend 비교 수치를 가져다 쓴다 — 제외
|
||||
|
||||
§110 은 실제로 복사가 일어나는지가 여러 조건에 따라 달라질 수 있다고 밝혔다. 그 조건은 kernel version · QEMU version · vhost configuration · offload · NIC capability · packet path · GSO/GRO/TSO 다. 조건이 이만큼 걸려 있으니 다른 환경에서 나온 수치는 이 호스트의 값이 되지 못한다. 이 물음은 이 호스트에서 잰 값으로만 닫힌다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. 지금 backend 가 무엇인지 먼저 확정한다. 그것을 묻는 물음이 닫히기 전에는 견줄 두 값 가운데 한쪽이 무엇인지 알 수 없다.
|
||||
2. 부하를 걸기 전에 여섯 축을 한 번 찍어 둔다.
|
||||
3. 지금 구성에 부하를 걸고 여섯 축을 같은 시각에 기록한다. Latency 와 Throughput 과 Packet rate 는 부하 도구가 내는 값을 쓰고, QEMU CPU 와 Host CPU 와 Context Switch 는 호스트에서 읽는다.
|
||||
4. 같은 가상 머신을 다른 backend 로 구성하고 같은 부하를 걸어 3 을 되풀이한다.
|
||||
5. 두 구성의 여섯 축을 나란히 적고, §110 이 든 조건들과 실행한 명령을 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 두 구성의 여섯 축을 나란히 놓으면 닫는다. 차이가 부하 전 값의 흔들림 안이면 이 호스트가 내는 초당 패킷 수에서는 backend 선택이 결과를 바꾸지 않는다고 적고 닫는다. 차이가 나면 그 측정이 Case 가 되고, 어느 backend 로 실험을 고정할지는 그 Case 뒤에 Decision 으로 넘긴다.
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
---
|
||||
id: 397c4789-0272-449b-86d6-2c4a3a122401
|
||||
kind: QUESTION
|
||||
slug: tap-interface-to-vm-mapping
|
||||
title: VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/397c4789-0272-449b-86d6-2c4a3a122401/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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에서-확인할-명령어
|
||||
---
|
||||
|
||||
# VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가
|
||||
|
||||
§99 는 TAP 을 가상 머신의 이더넷 프레임과 호스트 리눅스 네트워크를 잇는 접점으로 놓았다. 그 접점의 이름은 호스트마다 다르게 붙는데, 이 호스트에서 두 가상 머신에 각각 무엇이 붙었는지는 SSOT 에 없다. 이름을 모르면 §119 가 적은 계층별 tcpdump 도 대상을 채우지 못하고, §117.1 이 든 「특정 VM 만 통신 불가」가 어느 가상 머신을 가리키는지도 가릴 수 없다. 이 물음은 두 가상 머신의 호스트 쪽 인터페이스 이름과 그것이 붙어 있는 곳을 확정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
그 경로에서 TAP 이 무엇을 하는지 이미 설명해 두었으므로 이 물음은 거기서 이어진다.
|
||||
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
|
||||
그 기준이 요구하는 캡처 지점의 이름을 이 물음이 댄다.
|
||||
- **이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가**
|
||||
ip link 와 bridge link 를 두 물음이 같이 쓰므로 한 번 찍어 둘을 함께 읽는다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
tcpdump 를 어느 인터페이스에 걸지가 이 물음의 답에서 나온다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §99 는 TAP 을 호스트 리눅스 커널이 제공하는 가상 이더넷 네트워크 인터페이스로 적었다. 물리 장치가 아니고, 이름의 예로 tap0 과 vnet0 을 들었다.
|
||||
- §99 가 적은 TAP 의 역할은 가상 머신의 이더넷 프레임과 호스트 리눅스 네트워크를 연결하는 접점이다.
|
||||
수신 : Linux Bridge → TAP → VM
|
||||
송신 : VM → TAP → Linux Bridge
|
||||
- §99 는 확인 명령으로 ip link · ip tuntap show · bridge link · virsh domiflist 넷을 들었고, §118 이 같은 명령을 계층별 목록으로 다시 적었다.
|
||||
TAP/vnet : ip link · ip tuntap show
|
||||
libvirt VM NIC : virsh domiflist 에 domain 이름을 넣는다
|
||||
Linux Bridge : ip link show type bridge · bridge link · bridge fdb show
|
||||
- §122 OQ-2 는 이 호스트에서 돌릴 명령을 네 줄로 적었다.
|
||||
virsh domiflist vm1
|
||||
virsh domiflist vm2
|
||||
ip link
|
||||
bridge link
|
||||
- §99 와 §118 이 TAP 확인 명령으로 든 ip tuntap show 는 OQ-2 의 네 줄에 없다.
|
||||
- §117.1 은 TAP/Bridge 연결 오류의 증상 셋을 들었다.
|
||||
VM 외부 통신 불가
|
||||
Host ↔ VM 통신 불가
|
||||
특정 VM 만 통신 불가
|
||||
- §117.1 이 그 증상에서 확인하라고 든 명령은 ip link · bridge link · bridge fdb show · virsh domiflist 다.
|
||||
- §116 은 이 테스트 환경의 경로를 펼치면서 TAP 칸을 TAP(vm1) 과 TAP(vm2) 로 적었다. 호스트에서 읽은 이름은 그 그림에도 없다.
|
||||
- 두 가상 머신의 호스트 쪽 인터페이스 이름도, 그 인터페이스가 어느 브리지에 붙어 있는지도 SSOT 에는 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트에 붙어 virsh 와 ip 계열 명령을 실행할 수 있다고 본다.
|
||||
- §122 OQ-2 가 명령에 적은 vm1 과 vm2 가 이 호스트에 실재하는 domain 이름이라고 본다. 실제 이름이 다르면 그 이름으로 바꿔 돌린다. §99 와 §118 은 같은 명령에 넣을 domain 을 비워 두었고, 가상 머신 이름을 그대로 적은 곳은 §90.1 의 virsh domiflist vm1 과 §122 OQ-2 다.
|
||||
- virsh domiflist 출력에 인터페이스 이름과 MAC 주소가 함께 나온다고 전제한다. §99 도 §118 도 이 명령의 출력 형식은 적지 않았다.
|
||||
- 두 가상 머신이 켜져 있는 동안 읽는다고 전제한다. 꺼진 가상 머신의 TAP 이 호스트에 남아 있는지는 SSOT 에 적혀 있지 않다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- VM1 과 VM2 의 호스트 쪽 인터페이스 이름이 각각 무엇인지.
|
||||
- 각 인터페이스의 MAC 주소와 NIC model 이 무엇인지.
|
||||
- 두 인터페이스가 같은 브리지에 붙어 있는지, 서로 다른 곳에 붙어 있는지.
|
||||
- ip tuntap show 에 나오는 TAP 목록과 virsh domiflist 가 대는 이름이 그대로 맞아떨어지는지.
|
||||
|
||||
## 제약
|
||||
|
||||
- 이름과 어디에 붙어 있는지를 적는 데서 끊는다. 그 경로로 패킷이 실제로 흘렀는지는 tcpdump 를 쓰는 물음이 받는다.
|
||||
- 두 가상 머신을 같은 시점에 읽는다. 한쪽을 재시작한 뒤 다른 쪽을 읽으면 이름이 바뀌어도 알 수 없기 때문이다.
|
||||
- 이 호스트에서 읽은 출력이 없어 tap0 이나 vnet0 같은 §99 의 예시 이름을 이 호스트의 값으로 쓰지 않는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. libvirt 가 대는 이름을 먼저 받아 호스트에서 대조한다
|
||||
|
||||
virsh domiflist 로 가상 머신마다 붙은 인터페이스를 받고, 그 이름이 ip link 목록에 실재하는지 확인한 뒤 bridge link 로 어느 브리지의 port 인지 잡는다. §122 OQ-2 가 적은 네 줄이 이 순서다. 가상 머신과 인터페이스의 짝이 처음부터 정해져 나오므로 두 대의 것을 헷갈리지 않는다.
|
||||
|
||||
libvirt 가 모르는 인터페이스는 이 순서에서 빠진다.
|
||||
|
||||
### 2. 호스트의 인터페이스를 전부 세우고 가상 머신으로 되짚는다
|
||||
|
||||
ip link 와 ip tuntap show 로 호스트에 있는 TAP 을 모두 적고, bridge link 로 어느 브리지에 붙었는지 잡는다. 그다음 virsh domiflist 로 각각이 어느 가상 머신의 것인지 되짚는다. libvirt 밖에서 만들어진 TAP 이 있어도 목록에 남는다.
|
||||
|
||||
가상 머신이 두 대뿐인데 호스트에 TAP 이 여럿이면 짝짓는 데 MAC 주소를 다시 대조해야 한다.
|
||||
|
||||
### 3. 통신이 안 될 때 §117.1 의 확인 목록으로 함께 본다 — 제외
|
||||
|
||||
§117.1 이 증상과 확인 명령을 이미 묶어 두었으니 장애가 났을 때 같이 보자는 방법이다. 지금 필요한 것은 정상일 때의 이름과 붙어 있는 곳이고, 그것이 있어야 장애 때 무엇이 달라졌는지 견줄 수 있다. 증상이 난 뒤에 처음 읽으면 그 값이 원래 그랬는지 그때 바뀐 것인지 가릴 수 없다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. virsh domiflist vm1 과 virsh domiflist vm2 로 각 가상 머신에 붙은 인터페이스를 읽는다.
|
||||
2. ip link 로 그 이름이 호스트에 실재하는지 대조한다.
|
||||
3. bridge link 로 각 인터페이스가 어느 브리지의 port 인지 적는다.
|
||||
4. 두 가상 머신의 결과를 인터페이스 이름 · MAC 주소 · 붙어 있는 브리지로 나란히 적고, 실행한 명령과 출력을 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 가상 머신마다 인터페이스 이름과 MAC 주소와 붙어 있는 브리지를 적어 두 대를 나란히 놓으면 닫는다. 이 목록이 계층별 캡처 기준이 요구하는 지점의 이름이 되고, 이것이 없으면 실제 패킷 경로를 묻는 물음의 tcpdump 를 어느 인터페이스에 걸지 정할 수 없다. 두 가상 머신이 서로 다른 브리지에 붙어 있으면 §117.1 의 「특정 VM 만 통신 불가」를 진단할 때 그 사실을 먼저 본다고 적는다.
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
---
|
||||
id: 1a996f8d-b04e-49d2-88ef-4877e21f7c0e
|
||||
kind: QUESTION
|
||||
slug: virtio-net-multi-queue-enabled
|
||||
title: 이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/1a996f8d-b04e-49d2-88ef-4877e21f7c0e/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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
|
||||
---
|
||||
|
||||
# 이 가상 머신들의 virtio-net 에 multi-queue 가 켜져 있는가
|
||||
|
||||
multi-queue 는 virtio-net 이 송수신 큐를 여러 개 두고 쓰는 구성이다. §112 는 큐를 하나만 쓰면 패킷 처리가 한 vCPU 나 한 처리 경로에 몰릴 수 있어서 이것을 최적화 방향으로 들었다. 이 물음은 그 쏠림이 실제로 일어나는지를 재지 않고, 두 가상 머신이 애초에 큐를 몇 개 쓰도록 구성되어 있는지를 읽는다. 근거 문서는 multi-queue 를 쓸 수 있다고만 적었을 뿐 이 가상 머신들의 큐 수는 적지 않았다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
게스트와 호스트 backend 가 virtqueue 로 무엇을 주고받는지를 이 개념이 설명한다. 큐를 몇 개 두느냐는 그 구조 위의 설정이다.
|
||||
- **이 호스트에서 vhost-net 이 실제로 packet datapath 를 맡고 있는가**
|
||||
큐를 실제로 돌리는 backend 가 어느 쪽이냐에 따라 큐 수를 읽을 곳이 달라진다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
큐가 하나로 나왔을 때 그것이 실제 병목인지는 부하 구간의 vCPU 별 사용량이 답한다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §112 는 큐를 하나만 쓰면 특정 vCPU 나 처리 경로에 부하가 몰릴 수 있다고 적었고, virtio-net 이 multi-queue 를 쓸 수 있다고 밝혔다. 든 예는 RX Queue 0 부터 3 까지를 vCPU 0 부터 3 까지에 하나씩 대응시킨 구성이다.
|
||||
- §112 가 적은 multi-queue 의 목적 셋
|
||||
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 는 호스트에서 게스트로 버퍼를 넘긴다.
|
||||
- §117.5 는 single queue bottleneck 을 큐 하나나 vCPU 하나에 패킷 처리가 몰리는 문제로 놓고, 확인 대상 넷을 들었다.
|
||||
virtio multi-queue
|
||||
IRQ distribution
|
||||
per-vCPU CPU usage
|
||||
RSS/RPS/XPS
|
||||
- §122 OQ-5 가 적은 확인 대상 넷
|
||||
QEMU/libvirt NIC configuration
|
||||
Guest ethtool
|
||||
queue count
|
||||
IRQ distribution
|
||||
- 같은 §122 에서 OQ-1 과 OQ-2 는 돌릴 명령을 그대로 적었고, OQ-5 는 확인 대상 넷의 이름만 적었다. §117.5 가 든 넷도 이름이다.
|
||||
- 두 가상 머신에 설정된 큐 수가 근거 문서에 없다. 게스트가 몇 개를 쓰고 있는지도, 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 항목에서 인터페이스 이름을 받는 형태로만 나온다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 두 가상 머신의 구성과 게스트 내부를 지금 읽을 수 있다고 본다.
|
||||
- §112 가 든 RX Queue 넷과 vCPU 넷의 짝은 multi-queue 를 설명하려고 든 예시이지 이 호스트에서 읽은 값이 아니다.
|
||||
- 설정에 적힌 큐 수와 게스트가 실제로 쓰는 큐 수를 따로 읽어야 한다고 전제한다. 설정에 여럿을 적어 두면 게스트 드라이버가 그만큼 쓴다는 서술이 근거 문서에 없기 때문이다.
|
||||
- 두 가상 머신의 NIC 구성이 확인하는 동안 바뀌지 않는다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 두 가상 머신의 virtio-net 에 설정된 큐 수.
|
||||
- 게스트가 실제로 쓰고 있는 큐 수, 그리고 그 수가 설정값과 같은지.
|
||||
- 각 큐의 IRQ 가 여러 vCPU 에 흩어져 있는지 한 vCPU 에 몰려 있는지.
|
||||
- 두 가상 머신의 vCPU 수. §112 가 큐와 vCPU 를 하나씩 짝지어 든 예는 두 수를 나란히 놓아야 읽히는데, vCPU 수도 네트워크 쪽 근거에는 없다.
|
||||
- 이 환경의 RSS/RPS/XPS 설정. §117.5 가 확인 대상으로 들었지만 값을 읽는 방법은 적지 않았다.
|
||||
|
||||
## 제약
|
||||
|
||||
- 이 호스트에서 잰 값이 하나도 없다. 근거는 개념을 정리한 문서 한 편이고 §112 의 큐 넷과 vCPU 넷은 예시 숫자다.
|
||||
- 이 물음은 큐 구성이 무엇인지까지만 답한다. 쏠림이 실제 병목인지는 부하를 걸어야 갈리고, 그 부하 측정은 다른 물음이 가져간다.
|
||||
- 확인하는 동안 NIC 구성을 바꾸지 않는다. 큐 수를 늘려 놓고 읽으면 지금 실험이 어떤 구성에서 돌았는지 못 본다.
|
||||
- §118 이 큐 수와 IRQ 분포를 읽는 명령을 적지 않았으므로, 실행한 명령과 그 출력을 함께 증거로 남겨야 다음 사람이 같은 값을 다시 읽는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 호스트 쪽 설정값만 먼저 읽는다
|
||||
|
||||
libvirt 와 QEMU 쪽 NIC 구성에 큐 수가 적혀 있는지부터 본다. §90.2 가 libvirt 의 관리 대상 예로 든 여덟은 vCPU · Memory · Disk · NIC model · MAC address · Virtual network · Bridge · QEMU arguments 이고, 큐 수는 그 목록에 없다. 가상 머신에 들어가지 않고 호스트에서 끝나고, 큐가 하나로 적혀 있으면 그 구성은 single queue 로 확정된다.
|
||||
|
||||
설정에 큐를 여럿 적어 두었을 때 게스트가 그만큼 쓰는지는 이 확인으로 알 수 없다.
|
||||
|
||||
### 2. 설정값과 게스트 쪽 채널 수를 함께 읽는다
|
||||
|
||||
§122 OQ-5 가 든 넷 가운데 앞의 셋에 해당한다. 호스트의 NIC 구성과 게스트 안에서 본 채널 수를 같이 적으면 둘이 어긋나는 경우까지 잡힌다. 가상 머신 두 대에 각각 들어가야 해서 실행 횟수가 늘어난다.
|
||||
|
||||
### 3. IRQ 분포까지 한 번에 읽는다
|
||||
|
||||
큐가 여럿이어도 IRQ 가 한 vCPU 에 몰려 있으면 §117.5 가 든 쏠림은 그대로 생길 수 있다. §122 OQ-5 가 IRQ distribution 을 넷째 확인 대상으로 둔 이유가 여기에 있다. 세 항목을 한 번에 받아 적으면 큐 수만으로 판정을 끝내지 않게 된다.
|
||||
|
||||
### 4. 제외 — 큐 수를 바꿔 가며 견준다
|
||||
|
||||
multi-queue 를 켜고 끄면서 재면 이 환경에서 큐 수가 무엇을 바꾸는지 바로 보인다. 그러나 지금 물음은 실험이 어떤 구성에서 돌고 있는지를 읽는 것이라, 구성을 바꾸고 잰 값은 답이 되지 않는다. 켜고 끈 두 구성을 견주는 측정은 별도 Case 로 뺀다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. 호스트에서 두 가상 머신의 libvirt/QEMU NIC configuration 을 열어 큐 수가 적혀 있는지 읽는다. §122 에서 libvirt domain XML 을 확인하라고 적은 곳은 OQ-3 이고 OQ-5 에는 그 문장이 없다. §118 이 이 확인의 명령을 적지 않았으므로 무엇을 실행했는지 함께 기록한다.
|
||||
2. 각 게스트에서 ethtool 로 채널 수를 읽고, 실제 queue count 를 그 옆에 적는다. §122 OQ-5 가 Guest ethtool 과 queue count 를 나눠 적었으므로 둘을 따로 남긴다.
|
||||
3. 각 게스트의 IRQ 분포를 읽어 큐마다 어느 vCPU 에 붙어 있는지 적는다.
|
||||
4. 두 가상 머신의 결과를 vCPU 수와 나란히 한 표로 정리한다.
|
||||
|
||||
닫는 조건 : 가상 머신마다 설정된 큐 수 · 게스트가 쓰는 큐 수 · IRQ 분포를 한 표로 적으면 닫는다. 큐가 하나로 나오면 §117.5 가 든 single queue bottleneck 이 이 환경에서도 일어날 수 있는 구성이라고 적는다. 그것이 실제 병목인지는 부하를 건 뒤 vCPU 별 CPU 사용량이 답하기 때문에 「부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가」로 넘긴다. 큐가 여럿이고 IRQ 도 흩어져 있으면 이 항목은 지금 실험에서 우선순위를 낮추고 닫는다.
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
---
|
||||
id: 38716d7f-1aa1-48d8-ab4c-3fc505332128
|
||||
kind: QUESTION
|
||||
slug: vm-network-mode-bridge-nat-or-routed
|
||||
title: 이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/38716d7f-1aa1-48d8-ab4c-3fc505332128/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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-전체-네트워크-계층
|
||||
---
|
||||
|
||||
# 이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가
|
||||
|
||||
§98 은 가상 머신 네트워크를 분석하기 전에 Bridge 기반인가 · Routing 기반인가 · NAT(Network Address Translation, 네트워크 주소 변환) 기반인가를 구분하라고 적었다. 셋은 프레임이 지나는 계층이 다르고, 그에 따라 호스트의 L3 경로와 Netfilter 가 끼어드는지도 갈린다. 이 물음은 성능을 재지 않는다. 제3부가 서술한 경로 가운데 어느 절이 이 호스트에 그대로 적용되는지를 먼저 확정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
그 경로 그림에서 TAP 과 Physical NIC 사이에 놓인 계층이 이 물음이 확정하려는 부분이다.
|
||||
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
|
||||
구성이 무엇이냐에 따라 캡처를 걸 계층의 이름이 달라진다.
|
||||
- **VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가**
|
||||
ip link 와 bridge link 를 두 물음이 같이 쓰므로 한 번 찍어 둘을 함께 읽는다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
이 물음이 닫혀야 그 추적에서 tcpdump 를 걸 대상이 정해진다.
|
||||
|
||||
## 사실
|
||||
|
||||
- §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 처럼 동작할 수 있다는 예를 들었다.
|
||||
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 에는 확인 명령이 없다.
|
||||
- §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 에 따라 달라질 수 있다고 덧붙였다.
|
||||
- 확인할 명령은 §122 OQ-1 이 다섯 줄로 적어 두었다.
|
||||
정의된 가상 네트워크 열거 : virsh net-list --all
|
||||
그 가상 네트워크의 정의 읽기 : virsh net-dumpxml 에 이름을 넣는다
|
||||
호스트 인터페이스 목록 : ip link
|
||||
어느 인터페이스가 어느 브리지의 포트인지 : bridge link
|
||||
라우팅 테이블 : ip route
|
||||
- §118 이 같은 계층에 든 명령 가운데 virsh net-info 와 ip rule 은 OQ-1 의 다섯 줄에 없다.
|
||||
- 이 호스트에서 그 명령을 돌린 출력은 SSOT 에 없다. 셋 중 무엇인지도 적혀 있지 않다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 호스트에 붙어 virsh 와 ip 계열 명령을 실행할 수 있다고 본다.
|
||||
- libvirt 가상 네트워크로 정의된 구성이면 virsh net-list --all 에 이름이 나온다고 본다. 호스트가 미리 만들어 둔 브리지에 가상 머신을 직접 붙인 구성이면 그 목록에 아무 이름도 나오지 않을 수 있다.
|
||||
- 확인하는 동안 네트워크 구성이 바뀌지 않는다고 전제한다.
|
||||
- 셋 가운데 하나로 갈린다고 보고 물음을 세웠다. 다만 §114 가 Bridge 구성에도 Routing 과 NAT 과 Firewall 이 함께 걸릴 수 있다고 적었으므로, 하나로 갈리지 않으면 걸린 것을 모두 적는다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 이 호스트의 가상 머신 네트워크가 Bridge 기반인지 NAT 기반인지 Routing 기반인지.
|
||||
- libvirt 가상 네트워크로 정의되어 있는지, 아니면 호스트의 브리지에 가상 머신이 직접 붙어 있는지.
|
||||
- 정의되어 있다면 그 가상 네트워크의 forward mode 와 bridge 이름이 무엇인지.
|
||||
- 가상 머신을 떠난 프레임이 호스트의 L3/Netfilter 경로를 지나는지.
|
||||
|
||||
## 제약
|
||||
|
||||
- 구성이 셋 중 무엇인지를 확정하는 데서 끊는다. 그 구성이 지연에 얼마나 영향을 주는지는 부하 중 호스트 CPU 사용을 보는 물음이 받는다.
|
||||
- 이 호스트에서 읽은 출력이 없어 다른 장비의 구성을 근거로 삼지 않는다.
|
||||
- 돌릴 명령은 §122 OQ-1 이 정해 두었다. 실행한 명령과 출력을 함께 남겨야 다음 사람이 같은 값을 다시 읽는다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. libvirt 쪽부터 읽는다
|
||||
|
||||
virsh net-list --all 로 정의된 가상 네트워크를 열거하고, 나온 이름마다 virsh net-dumpxml 로 forward mode 와 bridge 이름을 읽는다. forward mode 하나로 Bridge 인지 NAT 인지 Routed 인지가 갈리므로 확인이 짧다.
|
||||
|
||||
libvirt 로 정의하지 않고 호스트 브리지에 직접 붙인 구성이면 목록이 비어 나오고, 그때는 호스트 인터페이스 쪽을 다시 읽어야 한다.
|
||||
|
||||
### 2. 호스트 인터페이스 쪽부터 읽는다
|
||||
|
||||
ip link 로 실재하는 인터페이스를 세우고, bridge link 로 어느 인터페이스가 어느 브리지의 포트인지를 잡고, ip route 로 L3 결정을 본다. libvirt 로 정의했든 안 했든 호스트에 실재하는 것을 읽으므로 구성 방식과 무관하게 답이 나온다.
|
||||
|
||||
forward mode 라는 이름으로 적힌 의도는 나오지 않으므로, NAT 이 걸려 있는지는 routing 과 방화벽 규칙을 따로 봐야 한다. §117.3 이 NAT/Firewall 오류에 든 것도 nftables · iptables · NAT rules · IP forwarding 이라는 확인 대상 이름이고 돌릴 명령이 아니다.
|
||||
|
||||
### 3. tcpdump 로 경로부터 잡는다 — 제외
|
||||
|
||||
§119 는 Host NIC · Bridge · TAP · Guest NIC 에서 tcpdump 로 패킷을 추적하는 순서를 적어 두었다. 다만 그 추적은 캡처를 걸 인터페이스 이름을 이미 알고 있을 때 성립한다. 지금은 브리지 이름도 TAP 이름도 모르므로 명령의 대상을 채울 수 없다. §126 의 실습 순서에서도 Bridge/NAT/Route 확인이 셋째이고 Host Nginx → VM packet path tcpdump 는 여덟째다. 이 방법은 이 물음이 닫힌 뒤 실제 패킷 경로를 묻는 물음이 받는다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
1. virsh net-list --all 로 정의된 가상 네트워크를 열거한다.
|
||||
2. 나온 이름마다 virsh net-dumpxml 에 그 이름을 넣어 forward mode 와 bridge 이름을 읽는다.
|
||||
3. ip link 로 호스트의 인터페이스 목록을 적는다.
|
||||
4. bridge link 로 어느 인터페이스가 어느 브리지에 붙어 있는지 적는다.
|
||||
5. ip route 로 라우팅 테이블을 적는다.
|
||||
6. 다섯 출력을 실행한 명령과 함께 증거로 남긴다.
|
||||
|
||||
닫는 조건 : 세 구성 가운데 무엇인지가 출력으로 확정되면 닫는다. Bridge 로 나오면 §96 과 §114 의 L2 forwarding 서술이 이 호스트에 적용된다고 적는다. NAT 으로 나오면 §98 의 주소 변환이 경로에 들어가고, Routing 으로 나오면 §97 의 L3 결정이 들어간다. 어느 쪽이든 그 결과로 실제 패킷 경로를 묻는 물음의 캡처 지점이 정해진다. §94 가 기준으로 삼은 구조와 다르게 나오면 제3부의 서술 가운데 이 호스트에 적용되지 않는 절을 함께 적는다.
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
---
|
||||
id: 68a848c7-eaff-4421-ad25-de21673ca40c
|
||||
kind: REFERENCE
|
||||
slug: bisect-the-packet-path-with-capture-points
|
||||
title: packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
studio: "https://hyeonworks.com/studio/documents/68a848c7-eaff-4421-ad25-de21673ca40c/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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의-역할
|
||||
---
|
||||
|
||||
# packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
|
||||
|
||||
가상 머신이 밖과 통신하지 못할 때 게스트 안에서만 원인을 찾으면 호스트의 브리지와 TAP 연결은 마지막에야 보게 된다. 그 사이의 계층은 애플리케이션 로그에 아무것도 남기지 않는다.
|
||||
|
||||
그래서 패킷이 지나야 할 지점마다 캡처를 걸고 어디까지 보였는지로 구간을 좁힌다. 호스트의 물리 NIC(Network Interface Card) 와 브리지, 가상 머신에 붙은 TAP, 게스트 안의 인터페이스 넷이 그 지점이고, 보이지 않은 첫 지점의 앞 구간이 의심 구간이 된다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
이 절차가 관측 지점으로 쓰는 계층을 세운 글이다. 어느 계층이 무엇을 하는지는 그쪽에 있다.
|
||||
- **Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다**
|
||||
그 기준은 문제가 네트워크인지 아닌지를 가르고, 이 절차는 네트워크 안에서 어느 구간인지를 가른다.
|
||||
- **이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가**
|
||||
캡처 지점 이름을 확정하는 첫 규칙이 그대로 이 물음의 확인 절차다.
|
||||
- **VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가**
|
||||
TAP 이름을 모르면 이 절차의 세 번째 지점에 캡처를 걸 수 없다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
그 경로를 처음 확인할 때 쓰는 절차다.
|
||||
|
||||
## 목적
|
||||
|
||||
이 기준은 두 가지를 막는다.
|
||||
|
||||
가상 머신이 통신하지 못할 때 게스트 안쪽과 애플리케이션부터 뒤지느라 호스트의 브리지와 TAP 연결을 늦게 보는 일이 하나다.
|
||||
|
||||
오프로드 때문에 실제 wire 와 다르게 보이는 정상 패킷을 결함으로 판정하는 일이 다른 하나다.
|
||||
|
||||
이 순서는 물음 셋이 함께 쓴다. 이 호스트의 가상 머신 네트워크가 무엇으로 구성돼 있는지, TAP 인터페이스가 무엇인지, 호스트 Nginx 에서 Keycloak 까지 패킷이 어디를 지나는지 셋이 모두 이 순서 위에서 돈다. 그래서 세 곳에 같은 절차를 되풀이하지 않고 한 편에 두었다.
|
||||
|
||||
## 규칙
|
||||
|
||||
### 1. 캡처할 지점의 이름을 먼저 확정한다
|
||||
|
||||
관측 지점은 넷이다. 호스트의 물리 NIC, 호스트의 브리지, 가상 머신에 붙은 tap 또는 vnet, 그리고 게스트 안의 인터페이스.
|
||||
|
||||
이름을 모른 채 시작하면 없는 인터페이스에 캡처를 걸어 놓고 패킷이 안 보인다고 판정하게 된다.
|
||||
|
||||
인터페이스 목록은 ip link 로 본다.
|
||||
브리지에 무엇이 붙어 있는지는 bridge link 와 bridge fdb show 가 알려 준다.
|
||||
tap 목록은 ip tuntap show 로 본다.
|
||||
어느 가상 머신이 어느 tap 에 붙어 있는지는 virsh domiflist 에 도메인 이름을 붙여 확인한다.
|
||||
libvirt 가 만든 가상 네트워크가 무엇인지는 virsh net-list --all 과 virsh net-dumpxml 로 확인한다.
|
||||
라우팅이 개입하는 구성이면 ip route 와 ip rule 도 함께 본다.
|
||||
|
||||
### 2. 네 지점에 같은 요청을 흘리면서 캡처를 건다
|
||||
|
||||
호스트에서는 물리 NIC 와 브리지, tap 또는 vnet 에 각각 tcpdump -ni 로 캡처를 건다.
|
||||
게스트에서는 게스트 인터페이스에 같은 방식으로 건다.
|
||||
|
||||
### 3. 보이지 않은 첫 지점의 앞 구간을 의심 구간으로 삼는다
|
||||
|
||||
판독은 어느 지점까지 보였는가로만 한다.
|
||||
|
||||
물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보이면, 게스트 내부보다 먼저 호스트의 브리지와 tap 연결을 의심한다.
|
||||
|
||||
tap 에는 보이는데 게스트 NIC 에 안 보이면 virtio 와 vhost, 게스트 NIC 계층을 의심한다.
|
||||
|
||||
게스트 NIC 에는 보이는데 소켓까지 오지 않으면 게스트의 라우팅과 방화벽, listen 상태를 의심한다.
|
||||
|
||||
### 4. 증상마다 다음에 볼 명령을 미리 정해 둔다
|
||||
|
||||
의심 구간이 나오면 그 구간의 증상에 맞는 확인으로 넘어간다.
|
||||
|
||||
가상 머신이 외부와 통신하지 못하거나 호스트와 통신하지 못하거나 특정 가상 머신만 통신하지 못하면 tap 과 브리지 연결을 본다. ip link, bridge link, bridge fdb show, virsh domiflist 가 그 확인이다.
|
||||
|
||||
같은 서브넷은 통신되는데 다른 서브넷이 안 되거나 게이트웨이까지는 가는데 외부 통신이 실패하면 라우팅을 본다. ip route 와 ip rule 이다.
|
||||
|
||||
가상 머신에서 인터넷으로 나가지 못하거나 외부에서 가상 머신에 접근하지 못하거나 특정 포트만 실패하면 nftables 와 iptables, NAT(Network Address Translation) 규칙, IP(Internet Protocol) forwarding 설정을 확인 대상으로 둔다.
|
||||
|
||||
증상 셋을 각각 다른 기준으로 나누지 않은 것은 셋이 모두 어느 지점에서 끊겼는가로 환원되기 때문이다. 따로 적으면 같은 규칙의 부분 증상이 셋으로 늘어난다.
|
||||
|
||||
### 5. 패킷 크기와 체크섬이 예상과 다르다는 이유만으로 결함이라고 읽지 않는다
|
||||
|
||||
오프로드가 켜져 있으면 캡처에서 보이는 패킷 크기나 체크섬이 실제 wire 에서 보이는 것과 다르게 보일 수 있다. 원인 후보는 GSO(Generic Segmentation Offload), GRO(Generic Receive Offload), TSO(TCP Segmentation Offload), checksum offload 다.
|
||||
|
||||
크기와 체크섬이 예상과 다르면 오프로드 설정을 먼저 확인하고, 그 값만으로 판정하지 않는다.
|
||||
|
||||
### 6. 호스트의 L3 쪽에서 안 보이는 것을 곧바로 실패로 읽지 않는다
|
||||
|
||||
브리지가 L2 전달만 하는 경우 프레임이 호스트의 일반적인 L3 TCP/IP 스택을 반드시 거치지는 않는다. 한 가상 머신의 tap 에서 브리지를 지나 다른 가상 머신의 tap 으로 가는 경로가 그렇다.
|
||||
|
||||
호스트가 라우팅이나 NAT, host-local termination, 방화벽 역할을 할 때 L3 와 Netfilter 경로가 개입한다. 그래서 구성에 따라 호스트의 L3 관측에서 안 보이는 것이 정상이다.
|
||||
|
||||
### 7. 네 지점이 모두 보이는데 느리기만 한 경우는 이 절차가 답하지 않는다
|
||||
|
||||
이 절차가 가르는 것은 패킷이 어디서 끊겼는가다. 끊기지 않고 느리기만 하면 다른 기준으로 넘긴다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
KVM(Kernel-based Virtual Machine)/QEMU/libvirt 로 만든 가상 머신이 외부와 통신하지 못할 때.
|
||||
|
||||
특정 구간에서만 통신이 실패할 때.
|
||||
|
||||
실제 패킷 경로를 처음 확인할 때.
|
||||
|
||||
## 예외
|
||||
|
||||
오프로드가 켜진 구성에서는 패킷 크기와 체크섬이 그대로 증거가 되지 않는데, 다섯 번째 규칙이 그 경우다.
|
||||
|
||||
브리지가 L2 전달만 하는 구성에서는 호스트의 L3 관측에 안 보이는 것이 정상인데, 여섯 번째 규칙이 그 경우다.
|
||||
|
||||
네 지점이 모두 보이는데 느린 경우는 이 기준이 다루지 않는다. Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다 쪽으로 넘긴다.
|
||||
|
||||
이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없다. 여기 적은 판독은 원문 문서가 서술한 것이고 이 호스트의 캡처로 확인한 것이 아니다.
|
||||
|
||||
## 예시
|
||||
|
||||
- 물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보임 : 호스트의 브리지와 tap 연결을 먼저 확인한다
|
||||
- tap 에 보이는데 게스트 NIC 에 안 보임 : virtio 와 vhost, 게스트 NIC 계층을 확인한다
|
||||
- 게스트 NIC 에 보이는데 소켓까지 안 옴 : 게스트의 라우팅과 방화벽, listen 상태를 확인한다
|
||||
- 특정 가상 머신만 통신 불가 : ip link 와 bridge link, virsh domiflist 로 그 가상 머신의 tap 이 브리지에 붙어 있는지 본다
|
||||
- 같은 서브넷은 되고 다른 서브넷만 실패 : ip route 와 ip rule 을 본다
|
||||
- 캡처에 보이는 패킷이 예상보다 크고 체크섬이 어긋남 : 오프로드 설정을 먼저 확인한다
|
||||
- 네 지점이 모두 보이는데 응답만 느림 : 이 절차를 여기서 멈춘다
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
---
|
||||
id: ca36f0db-9028-4761-91a8-afb7eb30f2b9
|
||||
kind: REFERENCE
|
||||
slug: verify-the-network-path-before-blaming-the-application
|
||||
title: Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다
|
||||
topic: network-virtualization
|
||||
topicName: 네트워크 가상화
|
||||
project: virtualization
|
||||
status: 초안
|
||||
studio: "https://hyeonworks.com/studio/documents/ca36f0db-9028-4761-91a8-afb7eb30f2b9/edit"
|
||||
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
|
||||
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까지-올라오는-과정
|
||||
---
|
||||
|
||||
# Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다
|
||||
|
||||
Refresh Token 경쟁 자체는 virtio-net 문제가 아니다. 다만 그 실험은 클라이언트에서 Nginx 와 가상 머신, K3s, Keycloak 을 거쳐 PostgreSQL 또는 Redis 까지 가는 경로를 여러 노드가 함께 쓴다. 그 경로 위의 네트워크 가상화 문제는 애플리케이션 동시성 문제와 비슷한 증상으로 나타난다.
|
||||
|
||||
노드 하나만 느리거나 특정 가상 머신에서만 요청이 실패하는 것을 Refresh Token 경쟁이나 데이터베이스 락으로 결론내지 않으려면, 실험 결과를 원인에 귀속하기 전에 네트워크 경로를 따로 검증한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
|
||||
이 기준이 「따로 검증한다」고 말하는 계층을 세운 글이다.
|
||||
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
|
||||
이 기준이 문제가 네트워크인지 아닌지를 가른다면, 그 절차는 네트워크 안에서 어느 구간인지를 가른다.
|
||||
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
|
||||
검증 순서의 첫 항목이다. 경로를 모르면 무엇을 관측할지도 정해지지 않는다.
|
||||
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
|
||||
검증 순서의 마지막 항목이고, 네트워크 처리와 CPU 경쟁을 가르는 관측이다.
|
||||
- **Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가**
|
||||
같은 실험을 CPU 쪽에서 본 물음이다. 두 계층이 같은 지연으로 보이므로 함께 기록한다.
|
||||
|
||||
## 목적
|
||||
|
||||
이 기준은 실험 결과를 잘못된 원인에 붙이는 일을 막는다.
|
||||
|
||||
Keycloak 멀티 노드 실험에서 관측되는 지연과 실패에는 네트워크 가상화 쪽 원인이 섞일 수 있다. 노드 하나만 지연되는 경우, 가상 머신 하나에서만 패킷이 유실되는 경우, 호스트 브리지 구성이 잘못된 경우, NAT(Network Address Translation) 나 conntrack 문제, 호스트 CPU 경쟁 때문에 vhost 처리가 밀리는 경우가 여기 들어간다.
|
||||
|
||||
이 원인들을 확인하지 않은 채 결과를 Refresh Token 경쟁이나 데이터베이스 락으로 적으면, 고칠 곳이 아닌 곳을 고치게 된다.
|
||||
|
||||
이 분리는 실험 결과를 보고 나서 세운 규칙이 아니다. 원문 문서는 이 실험 기반으로 검증하려는 항목을 일곱 개 적어 두었고, 그 마지막이 「네트워크 계층 문제와 애플리케이션/저장소 문제의 분리」였다.
|
||||
|
||||
## 규칙
|
||||
|
||||
### 1. 실험이 지나는 경로를 먼저 적고 시작한다
|
||||
|
||||
요청은 클라이언트에서 Nginx 로 가고, 거기서 가상 머신 두 대 중 하나로, 그 안의 K3s 를 지나 Keycloak 으로, 다시 PostgreSQL 또는 Redis 로 간다. 이 경로를 노드들이 공유한다.
|
||||
|
||||
경로를 적지 않으면 어느 관측이 어느 구간을 덮는지 정해지지 않는다.
|
||||
|
||||
### 2. 노드 하나에서만 나는 증상을 애플리케이션 동시성으로 먼저 읽지 않는다
|
||||
|
||||
노드 하나만 지연되거나 가상 머신 하나에서만 실패하는 증상은 그 노드로 가는 경로 쪽에서도 나올 수 있다. 호스트 브리지 구성 오류, NAT 와 conntrack 문제, 그 가상 머신 쪽 패킷 유실이 같은 모양으로 관측된다.
|
||||
|
||||
증상이 노드별로 갈리면 그 노드까지 가는 경로를 먼저 확인한다.
|
||||
|
||||
### 3. 애플리케이션 로그만으로 네트워크 계층을 배제하지 않는다
|
||||
|
||||
Keycloak 은 virtqueue 와 vhost-net, TAP, Bridge, 물리 NIC(Network Interface Card) 를 직접 알지 못하고, 게스트가 주는 소켓 위에서만 동작한다. 아래 계층이 어긋나도 애플리케이션 로그에는 느렸다는 것과 실패했다는 것만 남는다.
|
||||
|
||||
그래서 애플리케이션 쪽 관측을 아무리 늘려도 이 계층이 원인인지 아닌지는 갈리지 않는다.
|
||||
|
||||
### 4. 네트워크 처리가 쓰는 호스트 CPU 를 실험과 같은 시간축에 기록한다
|
||||
|
||||
vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다. 그래서 네트워크 문제처럼 보이는 지연이 CPU 스케줄링 문제일 수도 있다. 앞의 세 규칙이 애플리케이션 증상을 네트워크 쪽으로 되돌린다면 이 규칙은 네트워크 증상을 CPU 쪽으로 되돌린다. 방향이 반대라서 둘을 한 기준에 둔다.
|
||||
|
||||
부하 실험을 돌릴 때 QEMU 와 vhost 의 CPU 사용량, 호스트와 게스트의 CPU, 네트워크 지연을 같은 시간축에 남긴다. 나중에 따로 재면 그때의 부하를 다시 만들어야 한다.
|
||||
|
||||
### 5. 세 가지 검증을 마친 뒤에 원인을 적는다
|
||||
|
||||
경로가 무엇인지, 그 경로가 끊기지 않았는지, 네트워크 처리가 호스트 CPU 를 얼마나 쓰는지 셋을 확인한다.
|
||||
|
||||
첫째는 호스트 Nginx 에서 Keycloak 까지의 실제 패킷 경로를 추적해서, 둘째는 계층마다 캡처해서, 셋째는 부하 중 CPU 사용량을 재서 답한다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
여러 노드가 같은 네트워크 경로를 공유하는 실험의 결과를 원인에 귀속할 때.
|
||||
|
||||
노드별로만 나타나는 지연을 볼 때.
|
||||
|
||||
특정 가상 머신에서만 나는 실패를 볼 때.
|
||||
|
||||
부하 구간에서만 커지는 지연을 애플리케이션 동시성이나 저장소 lock 으로 결론내려 할 때.
|
||||
|
||||
## 예외
|
||||
|
||||
이 기준은 애플리케이션 쪽 관측을 늘려서는 적용되지 않는다. Keycloak 이 게스트 소켓 위에서만 동작하므로 애플리케이션 로그로는 이 계층이 원인인지 가릴 수 없다.
|
||||
|
||||
네트워크 계층이 깨끗하다고 해서 이 기준이 애플리케이션 결함을 배제해 주지는 않는다. 여기서 나오는 것은 네트워크가 원인이 아니라는 것까지다.
|
||||
|
||||
가상 머신 위 K3s 안쪽은 이 기준의 범위 밖이다. CNI(Container Network Interface) 와 Service, Pod 네트워크는 별도 계층으로 두고 따로 분석한다.
|
||||
|
||||
원문 문서가 이 테스트 환경에 얹어 그린 경로는 확인된 것이 아니라 기준 구조를 그대로 옮겨 놓은 그림이다. 이 저장소에는 이 기준으로 원인을 실제로 가른 실험이 아직 없다.
|
||||
|
||||
## 예시
|
||||
|
||||
- Keycloak 노드 하나만 응답이 느림 : 그 노드가 있는 가상 머신까지의 경로부터 확인한다
|
||||
- 가상 머신 하나에서만 요청이 실패 : 호스트 브리지 구성과 그 가상 머신의 tap 연결을 본다
|
||||
- 부하를 올릴수록 지연이 커짐 : QEMU 와 vhost 의 CPU 사용량을 같은 시간축에서 함께 본다
|
||||
- 동시 갱신 실험에서 두 번째 요청이 거부됨 : 네트워크 검증 셋을 마친 뒤에 Refresh Token 경쟁으로 적는다
|
||||
- 네트워크 검증이 전부 깨끗함 : 네트워크가 원인이 아니라는 것까지만 적고 애플리케이션 쪽을 계속 본다
|
||||
Reference in New Issue
Block a user