Iè, u mo vechju laptop hè parechje volte più putente cà u vostru servitore di produzzione.

Quessi sò esattamente e lagnanze chì aghju intesu da i nostri sviluppatori. A cosa più interessante hè chì questu hè statu veru, chì dà nascita à una longa investigazione. Parleremu di i servitori SQL chì funzionanu nantu à VMware.

Iè, u mo vechju laptop hè parechje volte più putente cà u vostru servitore di produzzione.

In realtà, hè faciule d'assicurà chì u servitore di produzzione hè senza speranza daretu à u laptop. Eseguite (micca nantu à tempdb è micca in una basa di dati cù a Durabilità Ritardata attivata) u codice:

set nocount on
create table _t (v varchar(100))
declare @n int=300000
while @n>0 begin 
  insert into _t select 'What a slowpoke!'
  delete from _t
  set @n=@n-1
  end
GO
drop table _t

In u mo scrittore, ci vole 5 seconde, è nantu à u servitore di pruduzzione dura 28 seconde. Perchè SQL deve aspittà a fine fisica di l'entrata di u logu di transazzione, è facemu transazzione assai brevi quì. In modu approssimativu, avemu guidatu un camion grande è putente in u trafficu di a cità, è fighjulemu cum'ellu era superatu da e persone di consegna di pizza in scooter - u throughput ùn hè micca impurtante quì, solu a latenza hè impurtante. E nisun almacenamentu di rete, ùn importa quanti zeri ci sò in u so prezzu, pò batte u SSD locale in termini di latenza.

(in i cumenti hè risultatu chì aghju mentitu - aghju avutu a durabilità ritardata in i dui lochi. Senza durabilità ritardata risulta:
Desktop - 39 seconde, 15K tr/sec, 0.065 ms/io andata e ritorno
PROD - 360 seconde, 1600 tr/sec, 0.6 ms
Aghju avutu nutatu chì era troppu veloce)

In ogni casu, in questu casu, avemu trattatu di zeri triviali di a funzione zeta di Riemann cù un esempiu trivial. In l'esempiu chì i sviluppatori m'hà purtatu, era diversu. Eru cunvinta ch'elli avianu ragiò, è cuminciaru à caccià da l'esempiu tutti i so specifichi ligati à a logica cummerciale. À un certu puntu, aghju realizatu chì puderia scaccià cumplettamente u so codice è scrive u mo propiu - chì mostra u stessu prublema - in a pruduzzione corre 3-4 volte più lenta:

create function dbo.isPrime (@n bigint)
returns int
as
  begin
  if @n = 1 return 0
  if @n = 2 return 1
  if @n = 3 return 1
  if @n % 2 = 0 return 0
  declare @sq int
  set @sq = sqrt(@n)+1 -- check odds up to sqrt
  declare @dv int = 1
  while @dv < @sq 
    begin
	set @dv=@dv+2
	if @n % @dv = 0 return 0
	end
  return 1
  end
GO
declare @dt datetime set @dt=getdate()
select dbo.isPrime(1000000000000037)
select datediff(ms,@dt,getdate()) as ms
GO

Sè tuttu hè bè, tandu cuntrollà a primalità di un numeru vi piglià 6-7-8 seconde. Questu hè accadutu nantu à una quantità di servitori. Ma in certi, u cuntrollu hà pigliatu 25-40 seconde. Curiosamente, ùn ci era micca servitori induve l'esekzione durava, per dì, 14 seconde - u codice hà travagliatu o assai rapidamente o assai lentamente, vale à dì, u prublema era, dicemu, biancu è biancu.

Chì aghju fattu ? Aduprate metriche VMware. Tuttu era bè quì - ci era una bundanza di risorse, Ready time = 0, ci era abbastanza di tuttu, durante a prova nantu à i servitori veloci è lenti CPU = 100 in una vCPU. Aghju fattu una prova per calculà u numeru Pi - a prova hà mostratu i stessi risultati in ogni servitore. L'odore di a magia negra hè diventatu più forte è più forte.

Una volta ghjuntu à a splutazioni DEV, aghju cuminciatu à ghjucà cù i servitori. Hè risultatu chì vMotion da l'ospite à l'ospitu pò "cura" un servitore, ma pò ancu trasfurmà un servitore "veloce" in un "lentu". Sembra chì questu hè questu - certi ospiti anu un prublema ... ma ... nò. Qualchese macchina virtuale era lenta nantu à l'ospite, dì A, ma hà travagliatu rapidamente nantu à l'ospite B. È un'altra macchina virtuale, à u cuntrariu, hà travagliatu rapidamente in A è rallentò in B! E macchine "rapide" è "lenti" giravanu spessu nantu à l'ospite!

Da quellu mumentu, ci era un odore distintu di sulphur in l'aria. Dopu tuttu, u prublema ùn pò micca esse attribuita à a macchina virtuale (patch Windows, per esempiu) - dopu tuttu, hè diventatu "rapidu" cù vMotion. Ma u prublema ùn pò ancu esse attribuita à l'ospitu - dopu à tuttu, puderia avè tramindui machini "veloci" è "lenti". Inoltre, questu ùn era micca ligatu à a carica - aghju riesciutu à ottene una macchina "lenta" nantu à l'ospite, induve ùn ci era nunda in tuttu fora di questu.

Per disperazione, aghju lanciatu Process Explorer da Sysinternals è fighjulà a pila SQL. Nant'à e macchine lente, a linea hà subitu attiratu u mo sguardu:

ntoskrnl.exe!KeSynchronizeExecution+0x5bf6
ntoskrnl.exe!KeWaitForMultipleObjects+0x109d
ntoskrnl.exe!KeWaitForMultipleObjects+0xb3f
ntoskrnl.exe!KeWaitForSingleObject+0x377
ntoskrnl.exe!KeQuerySystemTimePrecise+0x881 < — !!!
ntoskrnl.exe! ObDereferenceObjectDeferDelete+0x28a
ntoskrnl.exe!KeSynchronizeExecution+0x2de2
sqllang.dll!CDiagThreadSafe::PxlvlReplace+0x1a20
... saltatu
sqldk.dll!SystemThread::MakeMiniSOSThread+0xa54
KERNEL32.DLL!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

Questu era digià qualcosa. U prugramma hè statu scrittu:

    class Program
    {
        [DllImport("kernel32.dll")]
        static extern void GetSystemTimePreciseAsFileTime(out FILE_TIME lpSystemTimeAsFileTime);

        [StructLayout(LayoutKind.Sequential)]
        struct FILE_TIME
        {
            public int ftTimeLow;
            public int ftTimeHigh;
        }

        static void Main(string[] args)
        {
            for (int i = 0; i < 16; i++)
            {
                int counter = 0;

                var stopwatch = Stopwatch.StartNew();

                while (stopwatch.ElapsedMilliseconds < 1000)
                {
                    GetSystemTimePreciseAsFileTime(out var fileTime);
                    counter++;
                }

                if (i > 0)
                {
                    Console.WriteLine("{0}", counter);
                }
            }
        }
    }

Stu prugramma hà dimustratu un rallentamentu ancu più pronunciatu - nantu à e macchine "veloce" mostra 16-18 milioni di cicli per seconda, mentre chì in macchine lente mostra un milione è mezu, o ancu 700 mila. Questu hè, a diferenza hè 10-20 volte (!!!). Questa era dighjà una piccula vittoria: in ogni casu, ùn ci era micca minaccia d'appiccicà trà u supportu Microsoft è VMware per ch'elli turnanu frecce l'un l'altru.

Allora u prugressu si firmò - vacanze, affari impurtanti, isteria virali è un forte aumentu di a carica di travagliu. Spessu menzionatu u prublema magicu à i mo culleghi, ma à volte pareva ch'elli ùn anu micca sempre cridutu - a dichjarazione chì VMware rallenta u codice da 10-20 volte era troppu monstruosa.

Aghju pruvatu à scavà per mè stessu ciò chì mi rallentava. A volte mi paria chì aghju trovu una suluzione - turning Hot plugs on and off, cambiendu a quantità di memoria o u numeru di prucessori spessu turnava a macchina in una "veloce". Ma micca per sempre. Ma ciò chì hè diventatu veru hè chì hè abbastanza per esce è chjappà à a rota - vale à dì, cambià qualchissia paràmetru di a macchina virtuale

Infine, i mo culleghi americani di colpu truvaru a causa radicali.

Iè, u mo vechju laptop hè parechje volte più putente cà u vostru servitore di produzzione.

L'ospiti sò diffirenti in frequenza!

  • Comu regula, questu ùn hè micca un grande affare. Ma: quandu si move da un host "nativu" à un host cù una frequenza "different", VMware deve aghjustà u risultatu GetTimePrecise.
  • Comu regula, questu ùn hè micca un prublema, salvu chì ùn ci hè una applicazione chì dumanda l'ora esatta milioni di volte per seconda, cum'è u servitore SQL.
  • Ma questu ùn hè micca scantu, postu chì u servitore SQL ùn face micca sempre questu (vede Conclusione)

Ma ci sò casi quandu stu rake colpi dura. Eppuru, sì, toccu nantu à a rota (cambiendu qualcosa in i paràmetri di VM) aghju furzatu à VMware à "ricalculà" a cunfigurazione, è a freccia di l'ospite attuale hè diventata a frequenza "nativa" di a macchina.

dicisioni

www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf

Quandu disattiveghjanu a virtualizazione di u TSC, leghje u TSC da a macchina virtuale torna u valore TSC di a macchina fisica, è scrive u TSC da a macchina virtuale ùn hà micca effettu. Migrazione di a macchina virtuale à un altru òspite, ripiglià da u statu sospesu, o vultà à una snapshot face chì u TSC salta discontinuamente. Certi sistemi operativi di l'ospiti fallenu à boot, o presentanu altri prublemi di timekeeping, quandu a virtualizazione TSC hè disattivata. In u passatu, sta funzione hè stata à volte cunsigliata per migliurà u rendiment di l'applicazioni chì leghjenu u TSC spessu, ma u rendiment di u TSC virtuale hè statu migliuratu sustancialmente in i prudutti attuali. A funzione hè stata ancu cunsigliata per l'usu quandu eseguisce misure chì necessitanu una fonte precisa di tempu reale in a macchina virtuale.

In corta, avete bisognu di aghjunghje u paràmetru

monitor_control.virtual_rdtsc = FALSE

cunchiusioni

Probabilmente avete una quistione: perchè SQL chjama GetTimePrecise cusì spessu?

Ùn aghju micca u codice fonte di u servitore SQL, ma a logica dice questu. SQL hè quasi un sistema operatore cù cuncurrenza cooperativa, induve ogni filu deve "cede" da u tempu à u tempu. Induve hè u megliu postu per fà questu? Induve ci hè una aspetta naturale - serratura o IO. D'accordu, ma chì succede s'è no spinning loops di calculu? Allora u locu evidenti è quasi solu hè in l'interprete (questu ùn hè micca veramente un interprete), dopu à eseguisce a prossima dichjarazione.

In generale, u servitore SQL ùn hè micca utilizatu per l'inchiodatura di l'informatica pura è questu ùn hè micca un prublema. Ma i loops chì travaglianu cù ogni tipu di tavule tempuranee (chì sò immediatamente in cache) trasformanu u codice in una sequenza di dichjarazioni eseguite assai rapidamente.

A propositu, s'è vo imbulighjate a funzione in NATIVELY COMPILED, allora si ferma di dumandà u tempu, è a so vitezza aumenta da 10 volte. Ma per u codice compilatu nativu avemu avutu à fà PREEMPTIVE MULTITASKING in SQL.

Source: www.habr.com

Add a comment