Jah, minu vana sĂŒlearvuti on mitmeid kordi vĂ”imsam kui teie tootmisteenus

Just such complaints I heard from our developers. The most interesting thing is that it turned out to be true, leading to a lengthy investigation. We will talk about SQL servers running on VMware.

Jah, minu vana sĂŒlearvuti on mitmeid kordi vĂ”imsam kui teie tootmisteenus

In fact, it is easy to make the production server hopelessly lag behind the laptop. Execute (not on tempdb and not on the database with Delayed Durability) the code:

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

On my desktop, it runs in 5 seconds, while on the production server — 28 seconds. This is because SQL has to wait for the physical completion of writing to the transaction log, and we are making very short transactions here. Roughly speaking, we have driven a big powerful truck into city traffic, and we see how pizza delivery guys on scooters easily overtake it — here throughput doesn't matter, only latency does. And no network storage, no matter how many zeros are in its price, can win on latency against a local SSD.

(it turned out in the comments that I lied — I have delayed durability captured in both places. Without delayed durability, it results in:
Desktop — 39 seconds, 15K tr/sec, 0.065ms /io roundtrip
PROD — 360 seconds, 1600 tr/sec, 0.6ms
I should have noticed that it was way too fast)

However, in this case, we are dealing with trivial zeros of the Riemann zeta function with a trivial example. In the example brought to me by the developers, it was different. I made sure that they were right and began to clear the example of all their specifics related to business logic. At some point, I realized that I could completely discard their code and write my own — which demonstrates the same problem — it runs 3-4 times slower in production:

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

If everything is fine with you, then checking the primality of a number will take 6-7-8 seconds. It was like that in a number of cases serverid. But in some cases, the check took 25-40 seconds. Interestingly, there were no servers where the execution took, say, 14 seconds — the code either ran very fast or very slowly, so the problem was, let's say, black and white.

Mida ma tegin? Vaatasin VMware statistikat. KĂ”ik oli hĂ€sti – ressursse oli rohkem kui piisavalt, Ready time = 0, kĂ”ike jagus, testimise ajal oli nii kiiretel kui ka aeglastel serveritel CPU=100 ĂŒhel vCPU-l. VĂ”tsin testi π arvestamiseks – test nĂ€itas samu tulemusi igasugustes serverites. Kujunes vĂ€lja, et asi muutub mustaks maagiseks.

DEV farmast vĂ€lja pÀÀsedes hakkasin serveritega katsetama. Selgus, et vMotion hostilt hostile vĂ”ib "ravida" serverit, kuid samas vĂ”ib ka "kiire" serveri muuta "aeglaseks". Tundub, et siin on probleem — mĂ”ned hostid on probleemsed... aga... ei. MĂ”ni virtuaalmasin takerdus hostil, ĂŒtleme, A, kuid töötas kiiresti hostil B. Teine virtuaalmasin seevastu töötas kiiresti A-l ja takerdas B-l! Hostil tihti töötasid nii "kiired" kui ka "aeglased" masinad!

Sellest hetkest Ă”hus hakati selgesti tunnetama vÀÀvlilĂ”hna. Probleem ei saanud olla seotud ĂŒhegi virtuaalmasinaga (nĂ€iteks Windowsi plaastritega) — ta muutus "kiireks" vMotioni kĂ€igus. Kuid probleem ei saanud olla ka hostiga seotud — see vĂ”iks hĂ”lmata nagu "kiireid", nii ka "aeglasi" masinaid. Samuti ei olnud see seotud koormusega — mul Ă”nnestus saada "aeglane" masin hostil, kus ei olnud mitte midagi muud.

Meeleheite sunnil kÀivitasin Sysinternals'i Process Explorer'i ja vaatasin SQL steki. Aeglastel masinatel tÔmbas 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

 vahele jÀetud
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 demonstreeris veelgi suuremat aeglustumist — "kiiretel" masinatel nĂ€itab see 16-18 miljonit tsĂŒklit sekundis, samas kui aeglastel — poolteist miljonit vĂ”i isegi 700 tuhat. Erinevus on seega 10-20 korda (!!!). See oli juba vĂ€ike vĂ”it: igal juhul ei olnud ohtu jÀÀda Microsofti ja VMware toe vahele, et nad ĂŒksteise sĂŒĂŒd ĂŒle kandsid.

Edasi liikumine peatus — puhkus, olulised asjad, viirusine hĂŒsteeria ja koormuse jĂ€rsk suurenemine. Ma mainisin sageli maagilist probleemi kolleegidele, kuid mĂ”nikord tundus, et nad ei usu mind — liiga koletuks oli vĂ€lja öelda, et VMware aeglustab koodi 10-20 korda.

Ma ĂŒritasin ise vĂ€lja selgitada, mis siis aeglustab. MĂ”nikord tundus, et leidsin lahenduse — Hot plugide sisse ja vĂ€lja lĂŒlitamine, mĂ€lu mahu muutmine vĂ”i protsessorite arvu muutmine muudavad masina sageli "kiireks". Kuid mitte igavesti. KĂŒll aga selgus tĂ”e kohta — et piisab, kui vĂ€lja minna ja ratast koputada — st muuta (mĂ”elgem kĂ”rgesse ametisse olevatele inimestele), siis on see halb virtuaalmasina parameetrit

LÔpuks leidsid mu Ameerika kolleegid Àkki pÔhjuse.

Jah, minu vana sĂŒlearvuti on mitmeid kordi vĂ”imsam kui teie tootmisteenus

Hostid erinevad sageduse poolest!

  • Reeglina pole see hirmus. Kuid: kui kolida ‘kodusest’ hostist ‘teise’ sagedusega hosti, peab VMware kohandama GetTimePrecise tulemusi.
  • Reeglina pole see hirmus, kui ei osutu olevat rakendust, mis kĂŒsib tĂ€pset aega miljoneid kordi sekundis, nagu SQL server.
  • Kuid ka see ei ole hirmus, sest SQL server ei tee seda kaugel alati (vt KokkuvĂ”te)

Kuid on juhtumeid, kus need takistused löövad valusalt. Ja tÔepoolest, ratast koputades (muutes VM-i seadeid) panin ma VMware 'uuesti arvutama' konfigureerimise, ja praeguse hosti sagedus muutus 'koduseks' sageduseks.

Lahendus

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

Kui keelad TSC virtualiseerimise, siis TSC lugemine virtuaalmasinast tagastab fĂŒĂŒsilise masina TSC vÀÀrtuse, ja TSC kirjutamine virtuaalmasinast ei avalda mĂ”ju. Virtuaalmasina teisaldamine teisele hostile, seisundist taastamine vĂ”i snapshotile tagasipöördumine pĂ”hjustab TSC jĂ€rsku hĂŒpet. MĂ”ned kĂŒlalisoperatsioonisĂŒsteemid ei kĂ€ivitu vĂ”i nĂ€itavad muid ajatsemise 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Ă€rksa parandatud. Funktsiooni on samuti soovitatud kasutada, kui tehakse mÔÔtmisi, mis vajavad virtuaalmasinas tĂ€pset reaalaja allikat.

LĂŒhiĂŒlevaates tuleks lisada parameeter

monitor_control.virtual_rdtsc = FALSE

KokkuvÔte

Te tĂ”enĂ€oliselt kĂŒsid, miks SQL-i tuleb kutsuda GetTimePrecise nii sageli?

Mul ei ole SQL serveri lĂ€htekoodide, kuid loogika ĂŒtleb jĂ€rgmist. SQL on peaaegu operatsioonisĂŒsteem kooperatiivse konkurentsiga, kus iga teema peab aeg-ajalt "loovutama". Ja kus oleks parem seda teha? Seal, kus on loomulik ooteaeg — lukustus vĂ”i I/O. HĂ€sti, aga mis siis, kui me keerame arvutustsĂŒkleid? Siis on ilmselge ja peaaegu ainus koht — tĂ”lgendis (see ei ole pĂ€ris tĂ”lgendi), pĂ€rast jĂ€rgmise kĂ€su tĂ€itmist.

Reeglina ei kasutata SQL serverit puhta arvutustöö jaoks ja see ei ole probleem. Kuid tsĂŒklid, millega töötatakse igasuguste ajutiste tabelitega (mis kohe pĂŒsivalt vahemĂ€lus), muudavad koodi vĂ€ga kiiresti tĂ€idetavate kĂ€su jĂ€rjestuseks.

Muide, kui funktsioon mĂ€hkida NATIVELY COMPILED, siis lĂ”petab see aja pĂ€rimise ja selle kiirus suureneb kĂŒmme korda. Aga kuidas on kooperatiivse mitmeĂŒlesandelisusega? Noh, just seetĂ”ttu tuli SQL-i luua NATIVE COMPILED koodi jaoks PREEMPTIVE MULTITASKING.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster