Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

Younghun Go

Virtio 개념 정리 본문

클라우드 컴퓨팅

Virtio 개념 정리

고영훈 2021. 8. 26. 11:07

가상화를 공부하면서 개념이 복잡하고 이해하기 쉽지 않다는 걸 느낀다. 그래서 이렇게나마 정리를 해둬야 기억하기 편할 것 같다.

 

아래 글은 Red Hat의 블로그와 Virtio 논문을 참고하여 작성했습니다.

 


Virtio는 Virtual I/O의 약자로, 반가상화 I/O를 지원하기 위한 표준화된 인터페이스이다. 그 중에서 Virtio-net은 가상 이더넷 카드를 말한다.

 

Virtio의 구성 요소

  • KVM

 KVM(Kernel based Virtual Machine)은 Linux가 기존의 OS 역할뿐만 아니라 하이퍼바이저의 역할을 가능하게 한다. 즉 Linux는 Guest라는 독립된 공간을 만들어주고, 이 공간에서 가상 머신이 동작한다. Guest는 Linux 입장에서 하나의 프로세스다. 리눅스가 하이퍼바이저 역할을 수행하기 때문에 KVM이 다른 VMM(Virtual Machine Monitor)보다 더 가볍다고 말할 수 있다. 다른 VMM은 OS와 하이퍼바이저가 분리되어있고, Mode를 변경하며 동작한다. 그러나 KVM은 VMM mode와 host mode를 구분하지 않기 때문에 mode switching을 줄일 수 있다. KVM은 Linux 커널 모듈에 내장되어 있어서 커널 컴파일 하기 전에 .config 파일을 수정해서 모듈 load 여부를 설정할 수 있다. 또한 KVM은 메모리 관리, 스케줄링, 네트워크 스택 등 일반적인 하이퍼바이저의 역할을 수행한다. 

 

  • QEMU

QEMU는 에뮬레이션을 통해 Guest가 물리 장치의 스펙에 구애받지 않고 어떤 장치던 소프트웨어적인 방식으로 장치를 사용 가능하게 한다. Guest는 Qemu 명령줄 인터페이스(CLI)를 통해 실행되며, KVM과 함께 사용하는 것이 일반적이다.

 

KVM과 QEMU에 대한 설명은 이전의 포스팅 가상화 기본 개념을 보자.

 

  • Libvirt

xml 형태의 파일을 qemu CLI로 변환해주는 인터페이스이다.  아래 xml 코드처럼 간단한 설정 값들만 입력하면 Libvirt가 Qemu CLI로 변환한다.

<disk type='file' device='disk'>
	<driver name='qemu' type='raw' />
	<source file='/home/--/virtual_machines/virtual_machine' />
	<target dev='sdb' bus='scsi' />
</disk>

 

일반적으로 VM에 접근할 때 Libvirt를 통하여 Qemu process에 접근한다. 아래 그림은 하나의 Guest(VM)가 active 상태인 시스템 구성을 보여준다. KVM은 커널의 모듈로서 동작하기 때문에 Kernel space에서 동작하고, Libvirt와 Qemu process는 각각 하나의 User Process로 보기 때문에 유저 스페이스에서 동작한다. Qemu process는 하나의 VM을 담고 있다. 즉 N개의 VM을 생성하면 N개의 Qemu process가 생성되어 Libvirt와 통신한다.

 

 

가상 머신을 만들고 top 명령을 수행해보면 아래 그림과 같은 결과를 얻을 수 있다. 아래 그림의 qemu-system-x86가 위 그림의 Qemu process에 해당한다.

 

 

Virtio 스펙과 vhost 프로토콜

글의 시작에서 Virtio는 반가상화 I/O를 지원하는 표준화된 인터페이스라고 이야기했다. Virtio의 스펙과 vhost 프로토콜이 뭔지 알아보자.

 

virtio-networking에 대해 이야기할 때 두 계층으로 나눠서 이야기한다.

  1. Control plane - data plane을 제어하기 위한 Host와 Guest간의 통신을 제어한다.
  2. Data plane - Host와 Guest간에 실제 데이터(패킷)를 전송하는데 사용

두 계층으로 분리해서 생각해야 하는 이유는 구현 방식도 다르고 성능도 다르기 때문이다.

 

data plane은 최대한 효율적이고 빠르게 패킷을 전송해야할 필요가 있다. 즉, 높은 네트워크 대역폭을 가져야한다.

반면 control plane은 최대한 유연하게 다른 장치를 제어할 수 있어야한다. 두 역할이 다르기 때문에 계층을 분리한 것으로 보인다.

 

본론으로 들어가서, Virtio는 Guest가 Host의 디바이스에 다이렉트 접근을 가능하게 하는 반가상화 방식의 인터페이스다. 즉, 하이퍼바이저를 통하지 않고 직접 물리 머신에 접근한다.

 

Virtio는 두 파트로 분리할 수 있다.

  1.  Virtio spec - OASIS라는 오픈소스 관련 표준화 기구에서 관리하는 Virtio spec은 control plane과 data plane를 구성하는 방식을 표준화한다. 즉 이 spec을 알아야 Virtio를 어떻게 구성해야하는지 알 수 있다.
  2.  vhost protocol - 커널 모듈이나 유저 프로세스의 역할을 줄여 성능을 향상시키는 data plane의 구현을 가능하게하는 프로토콜이다. vhost-net과 virtio-net 아키텍처를 보면 보다 잘 이해할 수 있을 것이다.

Virtio의 control plane은 Virtio의 spec에 따라 qemu process에 구현된다. 이와 반대로 data plane은 그렇지 않다. 그럼 왜 data plane은 qemu process에 구현하지 않는지 질문할 수 있다. 이유는 성능 때문이다.

 

만약 qemu에 data plane을 구현한다면 커널에서 Guest로 가는 패킷마다 컨텍스트 스위치가 일어난다. 이 연산은 latency를 증가시키고 더 많은 시간을 필요로하기 때문에 되도록 피해야만한다.

 

vhost로 이 문제를 해결할 수 있다. vhost는 qemu process를 우회하여 호스트의 커널에서 Guest로 가는 data plane을 구축할 수 있다. 그러나 vhost protocol은 data plane을 구축하는 방법만 설명한다. 실제로는 호스트와 게스트 모두 실제 패킷이 오고가는 통로인 ring layout을 구현해야 한다.

 

이제는 kernel에서 동작할 vhost-net과 user-space에서 동작할 vhost-user를 구현하는 방법을 알아야한다. 아래부터는 vhost-net의 동작에 초첨을 둔다.

 

vhost-net/virtio-net 아키텍처

virtio 인터페이스에 대해 이야기할 때 백엔드와 프론트엔드로 구분한다. 백엔드는 host side, 프론트엔드는 guest side를 말한다.

 

  • vhost-net은 host 커널 공간에서 동작하는 백엔드를 말한다.
  • virtio-net은 guest 커널 공간에서 동작하는 프론트엔드를 말한다.

아래 그림을 보자.

여기서 몇가지 짚고 넘어가야할 것은

  • vhost-net과 virtio-net은 각각 host와 guest 커널공간에서 동작하기 때문에 driver라고 부를 수 있으며 "vhost-net driver" 라고 표현해도 같은 것으로 생각하면 됨.
  • 위 그림처럼 data plane과 control plane이 분리되어있고, control plane은 virtio spec을 구현한다. 그림에 표현되어있지는 않지만 중간에 shared memory를 두어 data plane의 역할인 host와 guest간 패킷 전송을 수행한다.

일반적으로 data plane의 데이터 전송은 RX와 TX로 구분하며 dedicated queue를 통해 전송된다.

 

guest마다 vCPU를 할당할 수 있고 RX/TX Queue가 각 vCPU마다 생성된다. 아래 그림은 data plane만 보여준다.

 

 

 

virtio 아키텍처를 활용하면 컨텍스트 스위칭이 안 일어날까? 아니다. 일단 virtio는 interrupt 방식으로 동작한다.  

guest가 열심히 패킷을 shared queue에 쌓아두다가 일정 임계치가 넘어가면 host side에 interrupt(vIRQ)를 보내게 된다. 이 때 잠자고 있던 vhost thread가 깨어나 패킷을 처리하게 된다. interrupt 방식으로 처리하다보면 패킷이 쌓일 때마다 VM-Exit, VM-Entry 연산을 초래하게 되고, 이 역시 가상화에서 다루고 있는 오버헤드이다. 그래도 virtio로 어느정도 오버헤드를 완화시킬 수 있다. 

 

virtio-networking and OVS

한 guest에서 같은 host 안에 있는 다른 guest에게 패킷을 전송하거나, 외부(internet)로 패킷을 전송하고자 할 때 OVS를 사용한다.

 

OVS는 생략.

 

 

참고

https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net

 

Introduction to virtio-networking and vhost-net

Virtio was developed as a standardized open interface for virtual machines (VMs) to access simplified devices such as block devices and network adaptors. Virtio-net is a virtual ethernet card and is the most complex device supported so far by virtio.

www.redhat.com

https://www.sciencedirect.com/science/article/abs/pii/S0920548911000559

 

지적 감사합니다.

Comments