Oo, ang aking lumang laptop ay ilang beses na mas malakas kaysa sa iyong production server

Ito mismo ang mga reklamo na narinig ko mula sa aming mga developer. Ang pinaka-kagiliw-giliw na bagay ay na ito ay naging totoo, na nagdulot ng mahabang pagsisiyasat. Pag-uusapan natin ang tungkol sa mga SQL server na tumatakbo sa VMware.

Oo, ang aking lumang laptop ay ilang beses na mas malakas kaysa sa iyong production server

Sa totoo lang, madaling matiyak na ang production server ay walang pag-asa sa likod ng laptop. Ipatupad (hindi sa tempdb at hindi sa isang database na pinagana ang Delayed Durability) ang 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

Sa aking desktop ito ay tumatagal ng 5 segundo, at sa production server ay tumatagal ng 28 segundo. Dahil dapat hintayin ng SQL ang pisikal na pagtatapos ng entry log ng transaksyon, at napakaikling transaksyon ang ginagawa namin dito. Sa madaling salita, nagmaneho kami ng isang malaki at malakas na trak sa trapiko ng lungsod, at napanood namin kung paano ito naabutan ng mga taong naghahatid ng pizza sa mga scooter - hindi mahalaga ang throughput dito, ang latency lang ang mahalaga. At walang network storage, gaano man karaming mga zero ang mayroon sa presyo nito, ay maaaring matalo ang lokal na SSD sa mga tuntunin ng latency.

(sa mga komento ay lumabas na nagsinungaling ako - naantala ko ang tibay sa parehong mga lugar. Nang walang naantala na tibay, lumalabas:
Desktop - 39 segundo, 15K tr/sec, 0.065ms/io roundtrip
PROD - 360 segundo, 1600 tr/sec, 0.6ms
Dapat kong napansin na ito ay masyadong mabilis)

Gayunpaman, sa kasong ito kami ay nakikitungo sa mga walang kuwentang zero ng Riemann zeta function na may isang maliit na halimbawa. Sa halimbawang dinala sa akin ng mga developer, iba ito. Ako ay kumbinsido na sila ay tama, at nagsimulang alisin mula sa halimbawa ang lahat ng kanilang mga detalye na nauugnay sa lohika ng negosyo. Sa isang punto napagtanto ko na maaari kong ganap na itapon ang kanilang code at isulat ang sarili ko - na nagpapakita ng parehong problema - sa produksyon ay tumatakbo ito ng 3-4 beses na mas mabagal:

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

Kung maayos ang lahat, aabutin ng 6-7-8 segundo ang pagsuri sa primality ng isang numero. Nangyari ito sa ilang mga server. Ngunit sa ilan, ang tseke ay tumagal ng 25-40 segundo. Kapansin-pansin, walang mga server kung saan tatagal ang pagpapatupad, halimbawa, 14 na segundo - ang code ay gumana nang napakabilis o napakabagal, iyon ay, ang problema ay, sabihin nating, itim at puti.

Ang aking nagawa? Ginamit na mga sukatan ng VMware. Ang lahat ay maayos doon - mayroong isang kasaganaan ng mga mapagkukunan, Handa na oras = 0, mayroong sapat na lahat, sa panahon ng pagsubok sa parehong mabilis at mabagal na mga server CPU = 100 sa isang vCPU. Kumuha ako ng pagsubok upang kalkulahin ang numero ng Pi - ang pagsubok ay nagpakita ng parehong mga resulta sa anumang server. Lalong lumakas ang amoy ng black magic.

Nang makarating ako sa bukid ng DEV, nagsimula akong maglaro sa mga server. Napag-alaman na ang vMotion mula sa host hanggang sa host ay maaaring "gamutin" ang isang server, ngunit maaari rin nitong gawing "mabagal" ang isang "mabilis" na server. Parang ito na - may problema ang ilang host... pero... hindi. Ang ilang virtual machine ay mabagal sa host, sabihin nating A, ngunit mabilis na gumana sa host B. At isa pang virtual machine, sa kabaligtaran, ay gumana nang mabilis sa A at bumagal sa B! Ang parehong "mabilis" at "mabagal" na mga makina ay madalas na umiikot sa host!

Mula sa sandaling iyon, may kakaibang amoy ng asupre sa hangin. Pagkatapos ng lahat, ang problema ay hindi maiugnay sa virtual machine (mga window patch, halimbawa) - pagkatapos ng lahat, ito ay naging "mabilis" sa vMotion. Ngunit ang problema ay hindi rin maiugnay sa host - pagkatapos ng lahat, maaari itong magkaroon ng parehong "mabilis" at "mabagal" na mga makina. Gayundin, hindi ito nauugnay sa pag-load - Nakuha ko ang isang "mabagal" na makina sa host, kung saan walang anuman maliban dito.

Dahil sa desperasyon, inilunsad ko ang Process Explorer mula sa Sysinternals at tiningnan ang SQL stack. Sa mga mabagal na makina ay agad na nahagip ng aking mata ang linya:

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
... nilaktawan
sqldk.dll!SystemThread::MakeMiniSOSThread+0xa54
KERNEL32.DLL!BaseThreadInitThunk+0x14
ntdll.dll! RtlUserThreadStart + 0x21

Ito ay dati nang bagay. Ang programa ay isinulat:

    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);
                }
            }
        }
    }

Ang program na ito ay nagpakita ng isang mas malinaw na paghina - sa "mabilis" na mga makina ay nagpapakita ito ng 16-18 milyong mga cycle bawat segundo, habang sa mga mabagal na makina ito ay nagpapakita ng isa at kalahating milyon, o kahit na 700 libo. Iyon ay, ang pagkakaiba ay 10-20 beses (!!!). Ito ay isa nang maliit na tagumpay: sa anumang kaso, walang banta na makaalis sa pagitan ng suporta ng Microsoft at VMware upang sila ay mag-arrow sa isa't isa.

Pagkatapos ay tumigil ang pag-unlad - mga bakasyon, mahahalagang bagay, viral hysteria at isang matalim na pagtaas sa workload. Madalas kong banggitin ang magic problem sa aking mga kasamahan, ngunit minsan ay tila hindi sila palaging naniniwala sa akin - ang pahayag na pinabagal ng VMware ang code nang 10-20 beses ay napakapangit.

Sinubukan kong hukayin ang sarili ko kung ano ang nagpapabagal sa akin. Minsan, tila sa akin ay nakahanap ako ng solusyon - ang pag-on at pag-off ng Hot plugs, pagpapalit ng dami ng memorya o ang bilang ng mga processor ay madalas na ginagawang "mabilis" ang makina. Pero hindi forever. Ngunit ang naging totoo ay sapat na ang lumabas at kumatok sa manibela - iyon ay, pagbabago anumang parameter ng virtual machine

Sa wakas, ang aking mga kasamahan sa Amerika ay biglang natagpuan ang ugat.

Oo, ang aking lumang laptop ay ilang beses na mas malakas kaysa sa iyong production server

Ang mga host ay naiiba sa dalas!

  • Bilang isang tuntunin, ito ay hindi isang malaking pakikitungo. Ngunit: kapag lumipat mula sa isang 'katutubong' host patungo sa isang host na may 'iba't ibang dalas, dapat ayusin ng VMware ang resulta ng GetTimePrecise.
  • Bilang panuntunan, hindi ito problema, maliban kung mayroong application na humihiling ng eksaktong oras milyun-milyong beses bawat segundo, tulad ng SQL server.
  • Ngunit hindi ito nakakatakot, dahil hindi ito palaging ginagawa ng SQL server (tingnan ang Konklusyon)

Ngunit may mga kaso kapag ang rake na ito ay tumama nang husto. Gayunpaman, oo, sa pamamagitan ng pag-tap sa gulong (sa pamamagitan ng pagbabago ng isang bagay sa mga setting ng VM) pinilit ko ang VMware na 'muling kalkulahin' ang pagsasaayos, at ang dalas ng kasalukuyang host ay naging 'katutubong' dalas ng makina.

desisyon

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

Kapag hindi mo pinagana ang virtualization ng TSC, ang pagbabasa ng TSC mula sa loob ng virtual machine ay nagbabalik ng TSC value ng pisikal na makina, at ang pagsulat ng TSC mula sa loob ng virtual machine ay walang epekto. Ang paglipat ng virtual machine sa isa pang host, ang pagpapatuloy nito mula sa suspendido na estado, o pagbabalik sa isang snapshot ay nagiging sanhi ng TSC na tumalon nang walang tigil. Ang ilang mga guest operating system ay nabigo sa pag-boot, o nagpapakita ng iba pang mga problema sa timekeeping, kapag ang TSC virtualization ay hindi pinagana. Noong nakaraan, ang tampok na ito ay minsan ay inirerekomenda upang mapabuti ang pagganap ng mga application na madalas basahin ang TSC, ngunit ang pagganap ng virtual na TSC ay lubos na napabuti sa mga kasalukuyang produkto. Inirerekomenda din ang feature na gamitin kapag nagsasagawa ng mga sukat na nangangailangan ng tumpak na pinagmulan ng real time sa virtual machine.

Sa madaling salita, kailangan mong idagdag ang parameter

monitor_control.virtual_rdtsc = MALI

Konklusyon

Marahil ay may tanong ka: bakit madalas na tinatawag ng SQL ang GetTimePrecise?

Wala akong source code ng SQL server, ngunit sinasabi ito ng lohika. Ang SQL ay halos isang operating system na may cooperative concurrency, kung saan ang bawat thread ay dapat "magbigay" paminsan-minsan. Saan ang pinakamagandang lugar para gawin ito? Kung saan mayroong natural na paghihintay - lock o IO. Okay, ngunit paano kung kami ay umiikot sa mga computational loop? Pagkatapos ang halata at halos tanging lugar ay nasa interpreter (ito ay hindi talaga isang interpreter), pagkatapos isagawa ang susunod na pahayag.

Sa pangkalahatan, ang SQL server ay hindi ginagamit para sa purong computing nailing at hindi ito isang problema. Ngunit ang mga loop na gumagana sa lahat ng uri ng mga pansamantalang talahanayan (na agad na naka-cache) ay ginagawang isang pagkakasunud-sunod ng napakabilis na naisagawang mga pahayag.

Siyanga pala, kung ibalot mo ang function sa NATIVELY COMPILED, hihinto ito sa paghingi ng oras, at tataas ang bilis nito ng 10 beses. Paano naman ang multitasking ng kooperatiba? Ngunit para sa natively compiled code kailangan naming gawin ang PREEMPTIVE MULTITASKING sa SQL.

Pinagmulan: www.habr.com

Magdagdag ng komento