Pe cât de practic poate fi HotPlug/HotAdd-ul VMware ?

Mulți din noi suntem deja familiarizați cu funcționalitatea prin care putem reconfigura din mers capacitățile vRAM și vCPU a mașinilor virtuale pe un hypervizor ESXi. Aplicată pe un VM, funcționalitatea ne promite reconfigurare dinamică și fără downtime a mașinii virtuale. Mecanismul pare a avea potențial practic, mai ales in scenarii cu aplicații critice găzduite in VM-uri ce au nevoie la un moment dat de capacități in plus dar totodată nu pot fi întrerupte pentru upgrade. Chiar dacă există in hypervizor, utilizarea funcției nu întotdeauna e fezabilă în practică. Pe de o parte există factori care depind de OS alții care deprind de însuși aplicații. Ceea ce am să încerc mai jos e să analizez atitudinea a două din aplicațiile Microsoft: servere WEB și SQL față de HotPlug-ul de CPU. Încep totuși cu o introducere in HotAdd/HotPlug-ul din VMware.

Particularități tehnologie VMware HotAdd/HotPlug

  • funcționează pentru VM-uri începând cu versiunea 7 VM (ESXi 4.x/Workstation 7.x)
  • ai nevoie de licențe Enterprise sau Enterprise Plus pe hosturile de virtualizare – dacă  licența nu include feature-ul de Hot-Pluggable virtual HW  atunci la reconfigurare vei primi mesajul de eroare: Feature HotPlug is not licensed with this edition ..
  • are sens doar daca folosești un guest OS compatibil cu HotAdd/HotPlug – atât Microsoft Windows (cu excepții) cât și Linux au suport pentru HotAdd RAM și HotPlug CPU.
  • nu e compatibil cu funcționalitatea de Fault Tolerance (FT).
  • online doar într-o direcție: HotAdd/HotPlug nu și Remove (cândva posibil acum depreciat)
  • HotAdd vs HotPlug ? Subiect de semantică, de regulă HotAdd-ul e folosit in context cu RAM-ul pe când HotPlug in raport cu resurse CPU.
  • Implicit deconectat pentru toate VM-urile. Se configurează pe fiecare VM in parte cu settings separat pe CPU și RAM, obligatoriu pe VM deconectat. Implicit deconectat pentru că (1) HotAdd/HotPlug-ul implică un plus de overhead pe VMM-ul VM-ului si (2) in practică prea puține VM-uri au nevoie reconfigurare online, așa că un disabled all e mai dezirabil. Funcția trebuie activată din timp pentru a nu ajunge in situația in care îți dorești un upgrade online pe unul din VM-uri dar care încă nu are funcția activată, astfel încât vei fi nevoit până la urmă să introduci un downtime pentru shutdown-reconfigure VM or ăsta nu e tocmai scenariul pe care ți l-ai dorit.
  • Activarea feature-ulu de CPU HotPlug deconectează topologia vNUMA.

Suport guest OS pentru Hot Add-ul de CPU si RAM ?

Dacă e să vorbim de sisteme de operare Microsoft (server) și Linux atunci pentru ambele există suport, totuși nu fără mici excepții:

  • Windows Server 2008R2 Standard (doar RAM) Enterprise/Datacenter (RAM & CPU)
  • Windows Server 2012R2 Standard/Datacenter (RAM & CPU)
  • Linux pe un kernel 2.6.14 sau superior

Sigur lista putea fi una mai comprehensivă și să includă de exemplu toate versiunile servere Windows începând 2003 cu sau fără SP2/R2, Standard/Enterprise sau Datacenter pe 32 sau 64 de biți dar pentru simplitate m-am limitat doar la câteva OS-uri cele mai implementate azi.

Pentru servere 2003 Windows 2003 lucrurile se complică pentru că acestea folosesc  HAL-uri diferite pentru sisteme uniprocessor (UP) și multiprocessor (SMP). HAL-ul corespunzător se configurează automat la instalarea OS-ului așa că pentru un upgrade de la un vCPU pe mai multe (de altfel și invers) va fi nevoie și de reconfigurat HAL-ul (din Device Manager – Computer – ACPI Uniprocessor – Update Driver .. se alege ACPI multiprocesor ș.a.m.d). Din curiozitate verificați articolul: Modifying the Hardware Abstraction Layer (HAL) for a Windows virtual machine (1003978). Sistemele de operare Microsoft începând cu servere 2008 / Windows Vista au un HAL comun pentru UP și SMP așa că ne scutește de nevoia de a reconfigura HAL-ul. Un HAL potrivit e important pentru că dacă e greșit atunci inevitabil vor fi probleme de performanță (CPU pe guest OS liber cu core pe host-ul fizic încărcat la maxim): High CPU utilization of inactive Windows virtual machines (1077).

Cum se configurează Hot Add / Hot Plug ?

Din settings-ul VM-ului (Virtual Machine Properties – Options – Advanced – Memory/CPU Hot Plug) se activează funcțiile de Memory HotAdd  și CPU HotPlug (mai jos screen pe vSphere client). Se configurează pe VM-ul deconectat. Btw, opțiunea de Memory/CPU Hotplug lipsește la VM-urile configurate pentru Guest OS-uri incompatibile cu HotAdd/HotPlug.

how_practicaly_hot_add_can_be_activate_hotadd

Din acest moment VM-ul poate fi reconfigurat cu resurse RAM si CPU in plus chiar si după ce mașina virtuală este pornită. De remarcat warrning-ul de loc evident sub dropbox-ul cu numărul de procesoare – o atenționare in plus pentru a verifica configurația OS-ului la configurația hardware-ului (multiprocessor HAL pentru SMP or uniprocessor HAL pu UP):

how_practicaly_hot_add_can_be_cpu_add_warrning

Resursele noi de CPU și RAM sunt interpretate de către guest OS ca și dispozitive PnP care se auto-configurează și devine disponibile imediat. Prezența resurselor poate fi verificată simplu din (1) System Properties, (2) Device Manager sau (3) Task Manager:

how_practicaly_hot_add_can_be_confirm_hotadd

Dacă la momentul upgrade-ului aplicația Task Manager este deja deschisă, un dialog ne va propune reîncărcarea aplicației pentru a reflecta corect resursele adăugate (doar pentru vCPU hot plug, pentru hot add de vRAM se actualizează automat):

how_practicaly_hot_add_can_be_restart_task_manager

Verificare Hot Plug de vCPU pe aplicații single și multi-thread

Pentru început vom încerca câteva teste de HotPlug pe un server VM cu un workload generat sintetic. Sarcina pe server o vom simula cu un tool Sysinternals: CPUSTRESS:EXE, distribuit gratuit și care poate fi descărcat de aici. Ce este bine la CPUSTRESS e că cu acesta putem genera un workload pe mai multe thread-uri paralele, cu fiecare thread configurabil ca prioritate (in process queue) și intensitate a sarcinii (consumă o fracțiune din timpul CPU-ului sau il saturează la maxim). Subiectul muli-thread-ului e foarte important in contextul HotPlug-ului pentru dacă e HotPlug atunci sigur vorbim de mai multe vCPU-uri ori mai multe vCPU-uri pot fi consumate doar de aplicații multi-thread. Aplicațiile single-thread (majoritatea din ele) nu au cum să consume mai mult decât puterea unui singur CPU, asta e, ține de caracterul sarcinii din aceste aplicații – sarcini ce nu pot fi împărțite pe task-uri paralele. Din asta rezultă si una din recomandările de design a VM-urilor: numărul de vCPU-uri intr-un VM trebuie configurat reieșind din ce aplicații rulează pe acesta, pentru aplicații single-thread se vor configura VM-uri cu un singur vCPU, mai multe vCPU-uri nu vor aduce performanță în plus ci doar overhead pe hypervizor.

Așadar, să realizăm câteva teste cu CPUSTRESS și HOT PLUG in regim single și multi-thread. Efectul îl vom urmări în Task Manager. Btw, din TM putem urmări numărul de thread-uri asociate cu o aplicație sau process, pentru asta adăugam coloana Threads in lista Processes (View-Select Columns ..). In screen-ul de mai jos este ilustrat CPUSTRESS cu 3x thread-uri (app-ul propriu zis) + 2x thread-uri (sintetic) și Task Manager cu coloana Threads inclusă.

how_practicaly_hot_add_can_be_CPUSTRESS

Pentru început să încercăm pe un VM pre-configurat cu un singur vCPU să adăugăm prin Hot Plug încă un vCPU în timp ce CPUSTREES rulează un thread de sarcina sintetic (cu activity setat pe maximum). Se observă că adăugarea unui vCPU nou nu-l face încă disponibil pentru thread-ul de aplicație, core-ul inițial rămâne încărcat iar cel nou fără sarcină. Interesant e că dacă repornești aplicația se implică de acum și al doilea vCPU totuși nu în același timp așa că in sumă tot capacitatea unui vCPU va fi absorbită (50% din ambele vCPU-uri). E și de așteptat pentru o aplicație single-thread care nu poate consuma mai mult decât capacitatea unui singure vCPU.

how_practicaly_hot_add_can_be_CPUSTRESS_singlethread

Să încercăm acum același test pentru CPUSTRESS setat cu 2x thread-uri in paralel (ambele cu activity pe maximum). Același rezultat se observă, noul vCPU (HotPluged) disponibil in sistem nu este încă disponibil pentru workload-ul aplicației, unica soluție pentru a ajunge la el e repornirea aplicației. După repornire deja se observă ambele core-uri implicate. Prin contrast cu testul precedent multithreading-ul saturează ambele core-uri la maxim.

how_practicaly_hot_add_can_be_CPUSTRESS_multithread

Suport HotPlug de CPU pentru aplicații pe IIS Web

Să încercăm acum să repetăm scenariile de mai sus pentru o aplicație pe serverul IIS. Pentru test vom folosi o aplicație WEB programată cu un loop infint pentru a simula o sarcină CPU pe procesul IIS-ului. De menționat că aplicația WEB e una single-thread – pentru multithreading e nevoie de cod in plus :). Efectul multi-thread il vom simula prin deschiderea in paralel a mai multor instanțe de aplicație (un tab in browser cu pagina aplicației). Codul sursă e cel din screen-ul de mai jos, loop-ul este pornit printr-un buton.

how_practicaly_hot_add_can_IISCPUHOG_code

Testele le vom realiza pe o configurație default de IIS 7 (IIS/ASP.NET/.NET4/no-afinity) pe un site separat (CPUHOG) rulat într-un Application Pool izolat. Din Task Manager vom urmări sarcina pe vCPU-uri. Intr-un IIS un application pool este asociat cu un process w3wp.exe in OS – anume pe acesta se observă workload-ul din TM. Repornirea aplicației o vom face cu IISRESET din linia de comandă, de menționat că kill la procesul w3wp.exe din task manager s-au recycle pe Application Pool din IIS Manager nu are efectul presupus (mai multe mai jos).

Așadar să mergem pe următoarele două scenarii:

  • VM pornit cu un singur vCPU upgradat cu HotPlug la două vCPU-uri in timp ce pe IIS rulează o instanța a aplicației CPUHOG. Repornim worker process cu IISRESET.
  • VM pornit cu un singur vCPU upgradat cu HotPlug la două vCPU-uri în timp ce pe IIS rulează două instanțe a aplicației CPUHOG. Repornim worker process cu IISRESET.

Se observă un rezultat similar ca și in testele de mai sus cu workload sintetic și anume:

  • IIS-ul ignoră orice vCPU nou in sistem. Atât pentru single-thread cât și multi-thread doar un singur core rămâne saturat, pe când cel nou e in așteptare.
  • Pentru implicarea noului vCPU e nevoie de repornirea IIS-ului. După repornirea IIS-ului single-thread-ul va fi distribuit de către scheduler-ul OS de CPU pe ambele core-uri dar niciodată in paralel așa că capacitatea sumară rămâne la puterea unui core. Multi-thread-ul așa și cum și era de așteptat va satura ambele vCPU-uri din sistem.

Chiar dacă testul arată contrariul, totuși trebuie de menționat ca IIS-ul știe de fapt să reacționează la apariția unui nou vCPU și anume prin recycling-ul automat la process-ul w3wp.exe care face ca ISS-ul să conștientizarea noul vCPU. De ce nu mers in cazul testelor de mai sus, e pentru că IIS-ul folosește metoda overlapped recycle prin care noul w3wp.exe este pornit in paralel cu cel vechi, care va prelua treptat sarcinile noi din aplicație iar cele vechi rămânând a fi deservite de vechiul w3wp.exe până vor fi încheiate. Or aplicația folosită de noi e una fără sfârșit și deci va fi asociată la infinit de w3wp.exe-ul inițial fără a trece pe procesul w3wp.exe nou (cel care știe deja de vCPU-ul in plus) – de aici si rezultat-ul cu lipsa de interes pentru noul vCPU.

Suport HotPlug de CPU pentru Microsoft SQL Server

Microsoft SQL Server are suport pentru funcția de CPU HotPlug. Următoarele cerințe trebuie satisfăcute pentru hot plug-ul de CPU intr-un server SQL:

  • Hardware și x64 SO cu suport pentru HotPlug CPU (evident)
  • Server Microsoft SQL de la 2008 in sus (Hot Add RAM prezent de la 2005)
  • Server Microsoft SQL ediție Enterprise
  • Serverul SQL nu poate fi configurat pentru soft NUMA.

Spre deosebire de IIS serverul SQL evită intenționat să implice resursele noi de CPU. Pentru a folosi CPU-urile noi pe instanța SQL va trebui de rulat procedura de RECONFIGURE server. In plus dacă e folosit un affinity mask: affinity64 (>32 CPU) acesta va trebui modificat și el.

Până a trece pe teste, va fi util să analizăm un pic subiectului de thread and task architecture în serverul SQL:

  • aplicațiile Windows sunt planificate (alocare time slot) pe CPU de către scheduler-ul încorporat in kernel-ul sistemului de operare. Aplicațiile/procesle ce au nevoie de CPU formează o coadă către acesta, cu o ordine bazată pe priorități (preemptive scheduling), mai mult SO-ul poate oricând decupla forțat un process de la CPU în favoarea altui process mai prioritar.
  • abordarea descrisă funcționează pentru majoritatea aplicațiilor (inclusiv și cele 2x descrise mai sus) nu și pentru serverul SQL. Asta pentru că tratarea thread-urilor din interiorul SQL-ului cu aceeași algoritmi ca și restul proceselor ar fi ineficientă pentru că ar duce la o mulțime de comutări intre contexte datorată realocărilor de CPU. Reieșind din asta pe serverul SQL sa implementat propriul scheduler de CPU numit SOS Scheduler și care introduce un algoritm cooperativ (în loc să fie decuplate forțat thread-urile sunt lăsate să se cedeze voluntar CPU-ul).
  • in SOS Scheduler fiecare core fizic sau procesor logic are asociat un așa numit scheduler – responsabil de planificarea accesului la CPU pentru thread-urile SQL. Fiecare CPU are asociat scheduler (numit scheduler SQL) destinat thread-urilor utilizator (interogări SQL) și niciunul sau câteva Scheduler-e administrative: ​(1) mai multe Scheduler-e pentru Resource Monitor  – supervisor peste Scheduler-e SQL, ce garantează că acestea nu vor monopoliza resursele CPU ș.a.(2) un Scheduler pentru DAC (Dedicated Administrator Connection) – pentru a te putea conecta in caz că Scheduler-ele SQL sunt blocate.
  • Lista de Scheduler-e poate fi obținută din DMV-ul: sys.dm_os_scheduler.
  • Un Scheduler se poate afla în mai multe stări printre care: (1) VISIBLE ONLINE (DAC) – scheduler DAC (2) VISIBLE ONLINE – scheduler standard SQL (3) HIDEN ONLINE – scheduler Resource Monitor (4) HOT_ADDED – creat ca răspuns la un nou CPU (HotPluged) in sistem. Screen-ul de mai jos prezinta DMV-ul cu Scheduler-e SOS pentru un sistem de CPU Quad Core.

Schema de mai jos încearcă să ilustreze ce sa scris despre Scheduler-e si sarcini pe SQL:

how_practicaly_hot_add_can_be_SQLOS_architecture

Acum că ne-am familiarizat cu mecanismele de threading și task management pe un server SQL să încercăm câteva teste pe viu. Vom merge pe scenariul cu un VM pornit cu un singur vCPU upgradat cu HotPlug la două vCPU-uri in timp ce pe instanța de SQL se execută un script-ul pentru simularea de sarcină pe CPU. Vom verifica impactului adus de noul vCPU până și după executarea procedurii RECONFIGURE pe serverul SQL. Pentru exercițiu vom folosi un VM cu OS: Windows Server 2012R2 Standard și o instanță Microsoft SQL Server 2012 x64 Enterprise.

In mare parte testele pe SQL sunt inspirate din How to hot-add a vCPU to a virtual SQL Server, tot de aci vom scoate script-ul pentru generarea de sarcină CPU intensive pe o instanță SQL:

how_practicaly_hot_add_can_be_T-SQL_for_CPUHOG

Așadar, după ce porni, scriptul pentru generare de sarcină pe CPU, merge pe următorii pași:

  • urmărim in Task Manager Usage-ul pe singurul vCPU – consumat la 100%
  • verificam Processor Affinity pe instanța SQL (Server Properties – Processor) -> grayed out pentru ca avem un singur CPU și nici o modificare nu e permisă.
  • verificam scheduler-ii SQL cu SELECT * FROM sys.dm_os_schedulers -> avem un singur scheduler pentru thread-urile rulate pe instanța SQL (screen mai jos, Schedulers.A)
  • adăugăm un vCPU nou la VM (VM-ul pre-configurat pentru HotAdd/HotPlug)
  • urmărim în Task Manager sarcina pe CPU-uri – serverul SQL rămâne să consume un singur vCPU (screen mai jos, CPU.B). Obținem același rezultat și dacă pornim mai multe instanțe de script in paralel – in concluzie, serverul SQL nu ia in calcul noul vCPU.
  • verificăm scheduler-ii SQL -> nimic nou (screen mai jos, Schedulers.B)
  • pentru reconfigurare server executăm procedura RECONFIGURE -> nu merge din prima, pentru că: The affinity mask specified does not match the CPU mask on this system … Ca soluție pe server in affinity mask se trece pe manual după care se bifează singurul vCPU. După RECONFIGURE se setează affinity mask iarăși pe automat.
  • verificam Scheduler-ii SQL -> observăm un scheduler nou asociat cu noul vCPU și care figurează cu statut: VISIBLE ONLINE HOT_ADDED. (screen mai jos, Schedulers.C)
  • repornim script-ul pentru generare sarcina pe CPU (cu mai multe instanțe in paralel)
  • in Task Manager verificam Usage-ul pe CPU – acum ambele CPU-uri sunt implicate (screen mai jos, CPU.C)
  • repornim instanța SQL, verificăm Scheduler-ii SQL – Scheduler-ul nou și-a schimbat statutul in VISIBLE ONLINE (screen mai jos, Schedulers.D)

how_practicaly_hot_add_can_be_T-SQL_CPU_usage_x

how_practicaly_hot_add_can_be_T-SQL_SQL_schedulers