KVM: rendimiento de red en máquinas virtuales GNU/Linux

Hace algunos días me comentaron en el artículo Virtualización en CentOS 6.2 utilizando KVM acerca de problemas con el rendimiento de la red. Hasta ahora nunca tuve problemas de rendimiento de ninguna clase con mis máquinas virtuales KVM, por lo que decidí investigar un poco. Este es el resultado de las pruebas.



Cuando comencé la investigación, el primer material que encontré que trata de problemas de rendimiento de red en KVM fue esta sección de la guía Virtualization Administration Guide:

Por defecto, a las máquinas virtuales KVM se les asigna una interfaz de red (NIC - network interface controller) virtual Realtek 8139 si son guests Windows, o si no se ha especificado el tipo de guest (los resultados presentados en este artículo muestran la importancia de seleccionar correctamente el tipo de guest durante la creación de la máquina virtual, ya que ésto define que tipo de hardware le será asignado e impacta notoriamente en el rendimiento). En cambio a los guests GNU/Linux por defecto se les asigna una interfaz de red "virtio".

Virtio es un estándar Linux para drivers de dispositivos de disco y red donde el driver de dispositivo en el guest entiende que está ejecutando en un entorno virtualizado, y coopera con el hypervisor. Esto permite que los guest obtengan alto rendimiento en las operaciones de disco y red, y otorga la mayoría de los beneficios de rendimiento de la paravirtualización.

Virtio es diferente, pero su arquitectura es similar, a los drivers de dispositivo paravirtualizados de Xen o a VMware Guest Tools (las herramientas que se instalan en un guest Windows para mejorar su rendimiento).

Volviendo al punto de interés de este artículo, los dispositivos virtuales rtl8139 que se utilizan en máquinas virtuales KVM funcionan adecuadamente en la mayoría de los casos. Sin embargo, pueden sufrir problemas de degradación de rendimiento en algunas redes, por ejemplo, una red 10 Gigabit Ethernet.

Por lo tanto, para mejorar la performance se debe cambiar al driver de red paravirtualizado "virtio".

Experimento

Contando con un host CentOS 6.3 y una máquina virtual KVM con Ubuntu Server 12.04, realicé pruebas de performance con diferentes dispositivos de red virtuales, utilizando la herramienta iperf. Iperf mide el rendimiento del ancho de banda de los protocolos TCP y UDP.

Instalación de iperf

En la máquina virtual Ubuntu Server 12.04 utilizo iperf en modo servidor (escucha peticiones de clientes para iniciar tests). Previamente se debe instalar iperf mediante:

# apt-get install iperf

Para iniciar iperf en modo servidor, ejecutar:

iperf -s -f M

La configuración de red del guest Ubuntu Server 12.04 es la siguiente:

root@ubuntu:/home/pepe# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 52:54:00:ef:6a:e0
          inet addr:192.168.122.196  Bcast:192.168.122.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:feef:6ae0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:629896 errors:0 dropped:0 overruns:0 frame:0
          TX packets:288820 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:26484721658 (26.4 GB)  TX bytes:19662684 (19.6 MB)

En el host CentOS 6.3 utilizo iperf en modo cliente (se conecta a un servidor iperf para realizar tests). Se puede instalar utilizando el manejador de paquetes yum agregando el repositorio RPMforge:

yum install iperf

Para iniciar iperf en modo cliente, y conectarse al servidor iperf (previamente iniciado en la máquina virtual Ubuntu), ejecutar:

iperf -c 192.168.122.196 -f M

La configuración de red del host CentOS 6.3 es la siguiente:

# ifconfig virbr1
virbr1    Link encap:Ethernet  HWaddr 52:54:00:BF:C1:9B
          inet addr:192.168.222.1  Bcast:192.168.222.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:34 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:5528 (5.3 KiB)

Los parámetros -f M se utilizan para expresar las unidades en Megabytes/segundo.

Cambiar interfaz de red en máquinas virtuales KVM

Para cambiar un dispositivo en una máquina virtual KVM se deben seguir los siguientes pasos:

  1. Apagar el sistema operativo del guest.
  2. Editar la configuración del guest (en este caso "ubuntu") utilizando el comando virsh:
    virsh edit ubuntu
  3. Encontrar la sección de configuración de la interfaz de red:
    <interface type='network'>
      [...]
      <model type='rtl8139' />
    </interface>
  4. Cambiar el atributo "type" del elemento "model":
    <interface type='network'>
      [...]
      <model type='virtio' />
    </interface>
  5. Guardar los cambios, salir del editor y reiniciar el sistema operativo en el guest.

Resultados

Los resultados del experimento utilizando diferentes dispositivos de red en la máquina virtual KVM con GNU/Linux como sistema operativo guest fueron los siguientes.

pcnet

Luego de cambiar el dispositivo de red a pcnet, la herramienta ethtool muestra que la interfaz eth0 está utilizando el driver pcnet32:

root@ubuntu:/home/pepe# ethtool -i eth0
driver: pcnet32
version: 1.35
firmware-version:
bus-info: 0000:00:03.0
supports-statistics: no
supports-test: yes
supports-eeprom-access: no
supports-register-dump: yes

La velocidad del enlace es 1 Gigabit:

root@ubuntu:/home/pepe# ip link show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 52:54:00:ef:6a:e0 brd ff:ff:ff:ff:ff:ff

Los resultados de tres pruebas utilizando el driver pcnet son los siguientes:

  • Desde el cliente iperf 192.168.122.1 (host CentOS):
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39407 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   728 MBytes  72.8 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39414 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   534 MBytes  53.4 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39415 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   540 MBytes  54.0 MBytes/sec
    
  • En el servidor iperf 192.168.122.196 (máquina virtual Ubuntu) se observan las conexiones desde el cliente 192.168.122.1 (host CentOS):
    root@ubuntu:/home/pepe# iperf -s -f M
    ------------------------------------------------------------
    Server listening on TCP port 5001
    TCP window size: 0.08 MByte (default)
    ------------------------------------------------------------
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39407
    [ ID] Interval       Transfer     Bandwidth
    [  4]  0.0-10.0 sec   728 MBytes  72.8 MBytes/sec
    [  5] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39414
    [  5]  0.0-10.0 sec   534 MBytes  53.3 MBytes/sec
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39415
    [  4]  0.0-10.0 sec   540 MBytes  54.0 MBytes/sec
    ^C
    
    Se debe detener el servidor enviando la combinación de teclas Ctrl+C.

El ancho de banda promedio utilizando el driver pcnet es 60.03 MBytes/sec.

rtl8139

Luego de cambiar el dispositivo de red a rtl8139, la herramienta ethtool muestra que la interfaz eth0 está utilizando el driver 8139cp:

root@ubuntu:/home/pepe# ethtool -i eth0
driver: 8139cp
version: 1.3
firmware-version:
bus-info: 0000:00:03.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes

La velocidad del enlace es 1 Gigabit:

root@ubuntu:/home/pepe# ethtool eth0
Settings for eth0:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
        Advertised pause frame use: Symmetric
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
        Link partner advertised pause frame use: Symmetric
        Link partner advertised auto-negotiation: No
        Speed: 100Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 32
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: d
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes
root@ubuntu:/home/pepe# ip link show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:ef:6a:e0 brd ff:ff:ff:ff:ff:ff

Los resultados de tres pruebas utilizando el driver rtl8139 son los siguientes:

  • Desde el cliente iperf 192.168.122.1 (host CentOS):
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39360 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   690 MBytes  69.0 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39362 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   720 MBytes  71.9 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39369 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec   657 MBytes  65.7 MBytes/sec
    
  • Conexiones entrantes en el servidor iperf 192.168.122.196 (máquina virtual Ubuntu) desde el cliente 192.168.122.1 (host CentOS):
    root@ubuntu:/home/pepe# iperf -s -f M
    ------------------------------------------------------------
    Server listening on TCP port 5001
    TCP window size: 0.08 MByte (default)
    ------------------------------------------------------------
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39360
    [ ID] Interval       Transfer     Bandwidth
    [  4]  0.0-10.0 sec   690 MBytes  69.0 MBytes/sec
    [  5] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39362
    [  5]  0.0-10.0 sec   720 MBytes  71.9 MBytes/sec
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39369
    [  4]  0.0-10.0 sec   657 MBytes  65.7 MBytes/sec
    ^C
    

El ancho de banda promedio utilizando el driver rtl8139 es 68.86 MBytes/sec.

virtio

Luego de cambiar al dispositivo de red paravirtualizado virtio, la herramienta ethtool muestra que la interfaz eth0 está utilizando el driver virtio_net:

root@ubuntu:/home/pepe# ethtool -i eth0
driver: virtio_net
version:
firmware-version:
bus-info: virtio0
supports-statistics: no
supports-test: no
supports-eeprom-access: no
supports-register-dump: no

La velocidad del enlace es 1 Gigabit:

root@ubuntu:/home/pepe# ip link show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:ef:6a:e0 brd ff:ff:ff:ff:ff:ff

Los resultados de tres pruebas utilizando el driver virtio son los siguientes:

  • Desde el cliente iperf 192.168.122.1 (host CentOS):
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39322 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec  13006 MBytes  1301 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39323 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec  12985 MBytes  1298 MBytes/sec
    
    # iperf -c 192.168.122.196 -f M
    ------------------------------------------------------------
    Client connecting to 192.168.122.196, TCP port 5001
    TCP window size: 0.02 MByte (default)
    ------------------------------------------------------------
    [  3] local 192.168.122.1 port 39331 connected with 192.168.122.196 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec  12684 MBytes  1268 MBytes/sec
    
  • Conexiones entrantes en el servidor iperf 192.168.122.196 (máquina virtual Ubuntu) desde el cliente 192.168.122.1 (host CentOS):
    root@ubuntu:/home/pepe# iperf -s -f M
    ------------------------------------------------------------
    Server listening on TCP port 5001
    TCP window size: 0.08 MByte (default)
    ------------------------------------------------------------
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39322
    [ ID] Interval       Transfer     Bandwidth
    [  4]  0.0-10.0 sec  13006 MBytes  1300 MBytes/sec
    [  5] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39323
    [  5]  0.0-10.0 sec  12985 MBytes  1297 MBytes/sec
    [  4] local 192.168.122.196 port 5001 connected with 192.168.122.1 port 39331
    [  4]  0.0-10.0 sec  12684 MBytes  1268 MBytes/sec
    ^C
    

El ancho de banda promedio utilizando el driver virtio es 1288 MBytes/sec.

Conclusión

Luego de realizar pruebas con dispositivos de red emulados (pcnet, rtl8139) y con el dispositivo paravirtualizado "virtio", se observa una importante diferencia de rendimiento. El dispositivo virtio supera en rendimiento de red ampliamente a los dispositivos emulados. Por lo tanto si se encuentran problemas de rendimiento de red en máquinas virtuales KVM, debe cambiarse al dispositivo paravirtualizado, tal como lo recomienda la guía de Red Hat.

Próximamente... Pruebas de rendimiento de red con guests Windows.



Suscribirse

    Registrate para recibir las novedades y artículos por correo electrónico.

Linuxito en G+