Jah, minu vana sĂŒlearvuti on mitu korda vĂ”imsam kui teie tootmisserver.

Selliseid vÀiteid kuulsin meie arendajatelt. KÔige huvitavam on see, et see osutus tÔeks, alustades pikaajalist uurimist. Jutt kÀib SQL serveritest, mis jooksutavad meie VMware'is.

Jah, minu vana sĂŒlearvuti on mitu korda vĂ”imsam kui teie tootmisserver.

SeetĂ”ttu on kerge saavutada, et tootmisserver jÀÀks sĂŒlearvutile lootusetult alla. KĂ€ivitage (mitte tempdb-s ja mitte andmebaasis, kus on aktiveeritud Delayed Durability) jĂ€rgnev kood:

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

Minu töölaual vĂ”tab see aega 5 sekundit, tootmisserveris – 28 sekundit. Sest SQL peab ootama tehingulogis kirjutamise fĂŒĂŒsilise lĂ”petamise pĂ€rast, ja me teeme siin vĂ€ga lĂŒhikesi tehinguid. Ütleme nii, et me surusime suure vĂ”imsa kaubiku linna liiklusesse, ja vaatame, kuidas pizza kullerid oma mootorratastel meid kergelt mööda sĂ”idavad — siin ei loe lĂ€bivus, vaid ainult latentsus. Ükski vĂ”rgu mĂ€luseade, kui palju nulli ka ei oleks selle hinnas, ei suuda saavutada madalamat latentsust kohaliku SSD ees.

(kommentaarides selgus, et ma valetasime — mul on mĂ”lemas kohas viibinud delayed durability. Ilma delayed durability'ta on tulemused:
Töölaua puhul — 39 sekundit, 15K tr/sec, 0,065 ms /io ĂŒmmargune reisi aeg.
PROD — 360 sekundit, 1600 tr/sec, 0,6 ms
Pidin tÀhele panna, et see on liiga kiire)

Siinkohal on meil tegemist Riemanni funktsiooni triviaalsete nullidega triviaalse nĂ€itega. NĂ€ites, mille mulle arendajad tĂ”id, oli midagi muud. Ma veendusin, et nad on Ă”iged, ja hakkasin nĂ€itest eemaldama nende Ă€ri loogikaga seotud spetsiifikat. Mingil hetkel sain aru, et vĂ”in tĂ€ielikult visata nende koodi Ă€ra ja kirjutada oma — mis demonstreerib sama probleemi — productionis töötab see 3–4 korda aeglasemalt:

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 -- kontrolli paarituid numbreid kuni ruudust
  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

Kui teil on kĂ”ik hĂ€sti, siis arvutatakse arvu primitiivsuse kontroll 6–7–8 sekundi jooksul. Nii oli mitmel puhul. serverite. Kuid mĂ”nikord vĂ”ttis kontroll 25–40 sekundit. Mis on huvitav, ei olnud servereid, kus tĂ€itmine oleks kestnud nĂ€iteks 14 sekundit — kood töötas kas vĂ€ga kiiresti vĂ”i vĂ€ga aeglaselt, ehkki probleem oli, ĂŒtleme nii, must-valge.

Mida ma tegin? Vaatasin VMware'i mÔÔdikuid. KĂ”ik oli korras — ressurssi oli ĂŒle, Ready time = 0, kĂ”ike jagus, testimise ajal olid nii kiiretel kui ka aeglastel serveritel CPU=100 ĂŒhel vCPU-l. Tehtud test Pi arvestamiseks — test nĂ€itas samasid tulemusi igas serveris. Must maa muutus jĂ€rjest selgemaks.

DEV farmist vĂ€lja pÀÀsedes hakkasin serveritega katsetama. Selgus, et vMotion hostilt hostile vĂ”ib serverit 'ravida', aga vĂ”ib ka vastupidi, 'kiire' server muuta 'aeglaseks'. Tundub, et probleem on olemas — mĂ”nel hostil on probleem... aga... ei. Üks virtuaalmasin pidurdas hostis, ĂŒtleme, A, aga töötas kiiresti hostis B. Teine virtuaalmasin vastupidi, töötas kiiresti A-s ja pidurdas B-s! Hostis liiklesid tihti nii 'kiired' kui ka 'aeglased' masinad!

Sellest hetkest alates oli Ă”hus selgelt vÀÀvli lĂ”hna. Probleemi ei saanud seostada virtuaalmasinaga (nĂ€iteks Windowsi uuendustega) — see muutus ju vMotionil "kiireks". Kuid probleem ei saanud olla seotud ka hostiga — sellel vĂ”is olla nii "kiireid" kui "aeglaseid" masinaid. Samuti ei olnud see koormusega seotud — mul Ă”nnestus saada "aeglane" masin hostil, kus peale selle ei olnud ĂŒldse midagi.

HÀda tÔttu kÀivitasin Sysinternalsi Process Exploreri ja vaatasin SQL-i stacki. Aeglaste masinate puhul jÀi mulle kohe silma rida:

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

 vahelejÀtetud
sqldk.dll!SystemThread::MakeMiniSOSThread+0xa54
KERNEL32.DLL!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

See oli juba midagi. Programm oli kirjutatud:

    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  0)
                {
                    Console.WriteLine("{0}", counter);
                }
            }
        }
    }

See programm demonstreerib veelgi tugevamat aeglust — "kiiretel" masinatel nĂ€itab see 16-18 miljonit tsĂŒklit sekundis, samas kui aeglastel — ĂŒhe ja poole miljoni vĂ”i isegi 700 000. See tĂ€hendab, et vahe on 10-20 korda (!!!). See oli juba vĂ€ike vĂ”it: igal juhul ei olnud ohtu takerduda Microsofti ja VMware toe vahele, et nad suunaksid ĂŒksteisele sĂŒĂŒdistusi.

Edasi liikumine peatus — puhkus, tĂ€htsad asjad, viirushaigus ja koormuse jĂ€rsk tĂ”us. Olen tihti maininud kolleegidele maagilist probleemi, kuid vahel tundus, et nad ei usu mind alati — liiga uskumatud olid vĂ€ited, et VMware aeglustab koodi 10-20 korda.

PĂŒĂŒdsin ise vĂ€lja uurida, mis takistab. Vahel tundus, et leidsin lahenduse — kuumplugide sisse ja vĂ€lja lĂŒlitamine, muutmine mĂ€lu mahtu vĂ”i protsessorite arvu tihti muutis masina "kiireks". Kuid mitte igavesti. Siiski selgus, et piisab, kui lihtsalt vĂ€lja minna ja ratast koputada — st muuta igaĂŒhe virtuaalmasina parameetrit

LÔpuks leidsid mu Ameerika kolleegid root cause'i.

Jah, minu vana sĂŒlearvuti on mitu korda vĂ”imsam kui teie tootmisserver.

Hostid erinevad sageduse poolest!

  • Reeglina pole see hirmus. Kuid: ĂŒleminekul ‘oma’ hostilt ‘teise’ sagedusega hostile peab VMware korrigeerima GetTimePrecise'i tulemusi.
  • Reeglina pole see hirmus, kui ei satu rakendust, mis kĂŒsib tĂ€pset aega miljon korda sekundis, nagu SQL server.
  • Aga isegi see pole hirmus, kuna SQL server ei tee seda sugugi alati (vt KokkuvĂ”te)

Aga on juhtumeid, kui need lĂ”ksud tĂ”eliselt haiget teevad. Jah, kui koputasin ratastele (vahetades midagi VM seadetest), sundisin ma VMware 'ĂŒlekalkuleerima' konfiguratsiooni ja aktiivse hosti sagedus muutus 'originaalseks' sageduseks masina jaoks.

Lahendus

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

Kui te keelate TSC virtualiseerimise, tagastab TSC lugemine virtuaalmasinast fĂŒĂŒsilise masina TSC vÀÀrtuse ning TSC kirjutamine virtuaalmasinast ei pĂ”hjusta mingit mĂ”ju. Virtuaalmasina teisaldamine teisele hostile, selle jĂ€rsu seiskamise taastamine vĂ”i hetkeseisule tagasipöördumine pĂ”hjustab TSC rikkumist. MĂ”ned kĂŒlalisoperatsioonisĂŒsteemid ei kĂ€ivitu vĂ”i nĂ€itavad muid ajahoidmise probleeme, kui TSC virtualiseerimine on keelatud. Minevikus on seda funktsiooni mĂ”nikord soovitatud rakenduste jĂ”udluse parandamiseks, mis loevad TSC-d sageli, kuid virtuaalse TSC jĂ”udlust on praegustes toodetes mĂ€rkimisvÀÀrselt parandatud. Funktsiooni on soovitatud kasutada ka mÔÔtmiste tegemisel, mis vajavad virtuaalmasinas tĂ€pset reaalaega allikat.

LĂŒhidalt öeldes, tuleb lisada parameeter

monitor_control.virtual_rdtsc = FALSE

KokkuvÔte

Te kindlasti kĂŒsite: miks SQL kutsub GetTimePrecise nii sageli?

Mul ei ole SQL serveri lĂ€htekoodid, kuid loogika ĂŒtleb jĂ€rgmist. SQL on peaaegu operatsioonisĂŒsteem kooperatiivse konkurentsiga, kus iga lĂ”ime peab aeg-ajalt "loomulikult" ootama. Aga kus oleks parem seda teha? Seal, kus on loomulik ooteaeg — lukud vĂ”i IO. HĂ€sti, aga mis siis, kui me keerame arvutuslikke tsĂŒkleid? Siis on ilmne ja peaaegu ainus koht — tĂ”lgendajas (see ei ole pĂ€ris tĂ”lgendaja), pĂ€rast jĂ€rgmise kĂ€su tĂ€itmist.

Reeglina ei kasutata SQL serverit puhaste arvutuste tegemiseks, ning see ei ole probleem. Kuid tsĂŒklid ajutiste tabelitega (mis kohe vahemĂ€lustesse salvestatakse) muudavad koodi vĂ€ga kiiresti tĂ€idetavate kĂ€skude jĂ€rjestuseks.

Muide, kui funktsiooni ĂŒmbritseda NATIVELY COMPILED, siis see lĂ”petab ajakĂŒsimise, ja selle kiirus suureneb kĂŒmme korda. Aga kuidas on kooperatiivse multitaskinguga? Noh, just natively compiled koodi jaoks tuli SQL-s teha PREEMPTIVE MULTITASKING.

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster