Live Migration in OpenStack Cloud: Wie wir die Downtime auf 500 ms reduzierten

Live-Migrationen, also das Verschieben einer laufenden virtuellen Maschine auf eine andere Hardware Node, gehören bei unserer OpenStack Cloud, dem SysEleven Stack, zu den Routineaufgaben, wenn es beispielsweise um Wartung oder Skalierung geht. Eine Downtime ist hier nicht zu 100 Prozent vermeidbar. Allerdings hat sie bei unserer Cloud vereinzelt mehrere Minuten betragen und das wollten wir ändern. Deswegen haben wir uns die Komponenten genauer angesehen, die bei der Live-Migration beteiligt sind und haben Wege gefunden, die Downtime auf eine halbe Sekunde zu reduzieren. Wir erklären in diesem Beitrag, wie wir das geschafft haben.

Step 1: Warum bei Live-Migrationen eine Downtime entsteht 

Bevor wir eine Lösung für die lange Downtime finden konnten, mussten wir uns zunächst ansehen, welche Schritte eine Live-Migration in der OpenStack Cloud durchläuft:

  • Eine Software, die bei uns automatisch Server neu startet (der Rebootmanager) erkennt, dass ein Neustart notwendig ist. Er prüft automatisch, ob genügend Redundanz im Cluster vorhanden ist (n+1 oder n+2), damit ein Server neugestartet werden kann.
  • In diesem Rahmen läuft ein Python Script, das vor dem Neustart die Live-Migration aller virtuellen Maschinen über die OpenStack API auslöst und überwacht.
  • Wenn alle VMs migriert und das Script durch ist, startet der Rebootmanager die Maschinen neu.

Bei der Live-Migration selbst sind folgende Komponenten involviert:

  • Nova ist die OpenStack-Komponente, die für das Management von virtuellen Maschinen (Compute) zuständig ist.
  • Libvirt/qemu/kvm ist der Virtualisierungsstack, auf den Nova zurückgreift.
  • Midonet stellt das Software-defined Networking.

Bei Vanilla OpenStack passiert bei der Live-Migration entsprechend Folgendes:

  1. Vor der Live-Migration bindet Nova das Networking Interface an den neuen Hypervisor.
  2. Libvirt kopiert den Zustand der virtuellen Maschine (hauptsächlich die Inhalte des Arbeitsspeichers) auf den neuen Hypervisor.
  3. Libvirt setzt die Ausführung der virtuellen Maschine auf dem neuen Hypervisor fort.
  4. Nova löst die Verbindung zwischen Network Interface und dem alten Hypervisor.

Midonet sendet also den Traffic an den neuen Hypervisor, während die VM jedoch noch auf dem alten Hypervisor läuft.

 

Wir haben bemerkt, dass Schritt 2 im Extremfall mehrere Minuten benötigt – insbesondere dann, wenn die Applikation dauerhaft viel Arbeitsspeicher überschreibt. In dieser Zeit ist die VM nicht erreichbar.

 

Wir glauben, dass Nova annimmt, dass das Software-defined Network Traffic an beide Compute Nodes sendet. Midonet verhält sich aber nicht so, wie Nova es erwartet. In der Konsequenz ist die VM während der Migration offline.

Step 2: Wie wir über mehrere Schritte die Downtime bei OpenStack reduziert haben

Wir haben verschiedene Maßnahmen ergriffen, um die Downtime zu kürzen.

Beim ersten Schritt haben wir die OpenStack-Komponente Nova so gepatcht, dass es den Port nach der Migration bindet. Allein dieser Schritt hat viel bewirkt: Die Downtime lag „nur“ noch bei exakt 10 Sekunden, egal wie lange Libvirt braucht, um den Arbeitsspeicher zu kopieren.

Ein großer Erfolg, aber für anspruchsvollere Kundenprojekte war das noch nicht genug: Wir haben Kunden auf der Cloud liegen, bei denen die Downtime nicht spürbar sein darf, beispielsweise für Anwendungsfälle wie Live-Video-Streaming. Wir wollten sie also weiter reduzieren.

Der zweite Schritt: Um herauszufinden, wann der beste Zeitpunkt ist um den Port zu binden, haben wir einen völlig Stupiden, nicht ganz eleganten Einzeiler geschrieben, der die Timestamps im selben Format schreibt wie es bei den Logs von Nova der Fall ist:

while true; do timeout 0.05 ping <IP Address> -c 1 > /dev/null || echo "$(date +%H:%M:%S.%3N): VM offline"; sleep .01; done

Damit konnten wir sehen, ob Nova etwas im selben Augenblick loggt, wenn eine VM offline geht. An diesem Punkt nämlich müssten wir den Networking Port an den neuen Hypervisor binden. Dabei haben wir herausgefunden, dass Nova ein „resumed“ event von Libvirt erhält, sobald die VM zum neuen Hypervisor bewegt wurde. Indem wir an dieser Stelle direkt den Port binden ließen, konnten wir die Downtime weiter reduzieren: auf etwa 1,5 Sekunden.

In einem dritten Schritt haben wir uns intensiver mit dem Port Binding beschäftigt – und weitere unnötige Verzögerungen festgestellt. Der Hintergrund dazu:

  • Nova lässt einen Shell-Befehl von Midonet laufen, der „mm-ctl“ heißt und mithilfe von nova-rootwrap aufgerufen wird.
  • mm-ctl sendet eine HTTP-Anfrage an eine UNIX Socket Datei, um den Port zu binden.

Das Problem ist, dass nova-rootwrap sehr langsam arbeitet und eine Verzögerung von einer Sekunde auslöst. Wir haben also die Socket File Permissions so geändert, dass Nova die HTTP-Anfrage direkt sendet. Klingt zunächst einfach, ist aber kein Kinderspiel gewesen, da auch hier wiederum Patches bei Midonet nötig waren. Dafür aber konnten wir diese eine Sekunde Verzögerung streichen.

Ergebnis: Downtime von 500 Millisekunden!

Share: