Ja, my ou skootrekenaar is 'n paar keer kragtiger as jou produksiebediener.

Dit is die eise wat ek van ons ontwikkelaars gehoor het. Die interessantste is dat dit waar geblyk het te wees, wat aanleiding gegee het tot 'n lang ondersoek. Ons sal praat oor SQL-bedieners wat op VMware loop.

Ja, my ou skootrekenaar is 'n paar keer kragtiger as jou produksiebediener.

Eintlik is dit maklik om die produksiebediener hopeloos agter die skootrekenaar te kry. Begin (nie op tempdb en nie op 'n databasis met vertraagde duursaamheid geaktiveer nie) die kode:

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

Dit neem 5 sekondes op my lessenaar en 28 sekondes op die produksiebediener. Omdat SQL moet wag vir die fisiese einde van skryf aan die transaksielog, en ons doen baie kort transaksies hier. Rofweg gesproke het ons 'n groot kragtige vragmotor in stadsverkeer ingery, en ons kyk hoe pizzaafleweringsmense op bromponies dit beroemd verbysteek - deurset is nie hier belangrik nie, net latency is belangrik. En nie 'n enkele netwerkberging, maak nie saak hoeveel nulle daar in sy prys is, sal 'n plaaslike SSD in terme van latensie kan oortref nie.

(in die kommentaar het dit geblyk dat ek gelieg het - ek het vertraagde duursaamheid op beide plekke gehad. Sonder vertraagde duursaamheid blyk dit:
Werkskerm - 39 sekondes, 15K tr/sek, 0.065ms /io heen en weer
PROD - 360 sekondes, 1600 tr/sek, 0.6ms
Ek moes opgemerk het dat dit te vinnig is)

In hierdie geval het ons egter te doen met triviale nulle van die Riemann zeta-funksie met 'n triviale voorbeeld. In die voorbeeld wat die ontwikkelaars vir my gebring het, was dit anders. Ek was oortuig dat hulle reg was, en het begin om al hul besonderhede wat verband hou met besigheidslogika uit die voorbeeld skoon te maak. Op 'n stadium het ek besef dat ek hul kode heeltemal kan weggooi en my eie kan skryf - wat dieselfde probleem demonstreer - in produksie loop dit 3-4 keer stadiger:

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

As alles in orde is met jou, sal dit 6-7-8 sekondes neem om na die eenvoud van 'n nommer te kyk. Dit het op 'n aantal bedieners gebeur. Maar op sommige het die tjek 25-40 sekondes geneem. Interessant genoeg was daar geen bedieners waar die uitvoering byvoorbeeld 14 sekondes sou neem nie - die kode het Γ³f baie vinnig Γ³f baie stadig gewerk, dit wil sΓͺ, die probleem was, kom ons sΓͺ, swart en wit.

Wat ek gedoen het? Het by VMware-statistieke ingegaan. Alles was goed daar - daar was baie hulpbronne, gereed tyd = 0, daar was genoeg van alles, tydens die toets beide op vinnige en stadige bedieners CPU = 100 op een vCPU. Ek het 'n toets afgelΓͺ om die aantal Pi te bereken - die toets het dieselfde resultate op enige bedieners gewys. Die reuk van swart magie het sterker en sterker geword.

Nadat ek op die DEV-plaas uitgekom het, het ek met bedieners begin speel. Dit het geblyk dat vMotion van gasheer tot gasheer 'n bediener kan "genees", maar dit kan ook 'n "vinnige" bediener in 'n "stadige" een verander. Dit blyk dat dit dit is - sommige gashere het 'n probleem ... maar ... nee. Die een of ander virtuele masjien het stadiger op gasheer, sΓͺ, A, maar vinnig op gasheer B gewerk. En die ander virtuele masjien, inteendeel, het vinnig op A gewerk en op B vertraag! Beide "vinnige" en "stadige" motors het dikwels op die gasheer gedraai!

Van daardie oomblik af was daar 'n duidelike reuk van swael in die lug. Die probleem kon immers nie aan enige virtuele masjien toegeskryf word nie (byvoorbeeld Windows-pleisters) - dit het immers in 'n "vinnige" een met vMotion verander. Maar die probleem kon ook nie aan die gasheer toegeskryf word nie - dit kan immers beide "vinnige" en "stadige" masjiene hΓͺ. Dit was ook nie verwant aan die vrag nie - ek het daarin geslaag om 'n "stadige" masjien op die gasheer te kry, waar daar niks buiten dit was nie.

Uit desperaatheid het ek Sysinternals se Process Explorer aangevuur en na die SQL-stapel gekyk. Op stadige masjiene het die lyn dadelik my oog gevang:

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

Dit was al iets. Die program is geskryf:

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

Hierdie program het 'n selfs meer uitgesproke verlangsaming getoon - op "vinnige" masjiene toon dit 16-18 miljoen siklusse per sekonde, terwyl op stadige - een en 'n half miljoen, of selfs 700 duisend. Dit wil sΓͺ, die verskil is 10-20 keer (!!!). Dit was reeds 'n klein oorwinning: daar was in elk geval geen gevaar om tussen Microsoft en VMware-ondersteuning vas te raak sodat hulle pyle na mekaar sou oorskakel nie.

Toe het vordering gestop - vakansie, belangrike dinge, virale histerie en 'n skerp toename in werklading. Ek het dikwels die magiese probleem aan kollegas genoem, maar soms het dit gelyk of hulle my nie eers altyd geglo het nie - die stelling dat VMware die kode met 10-20 keer vertraag het, was te monsteragtig.

Ek het self probeer uitgrawe wat dit vertraag. Soms het dit vir my gelyk of ek 'n oplossing gevind het - om die Hot plugs aan en af ​​te skakel, die hoeveelheid geheue of die aantal verwerkers te verander, het die masjien dikwels in 'n "vinnige een" verander. Maar nie vir altyd nie. Maar wat waar blyk te wees, is dat dit genoeg is om uit te gaan en aan die wiel te klop – dit wil sΓͺ om te verander enige virtuele masjien parameter

Uiteindelik het my Amerikaanse kollegas skielik 'n oorsaak gevind.

Ja, my ou skootrekenaar is 'n paar keer kragtiger as jou produksiebediener.

Gashere het verskil in frekwensie!

  • As 'n reΓ«l is dit nie skrikwekkend nie. Maar: wanneer jy van 'n 'inheemse' gasheer na 'n gasheer met 'n 'ander' frekwensie beweeg, moet VMware die GetTimePrecise-resultaat aanpas.
  • As 'n reΓ«l is dit nie 'n probleem nie, tensy daar 'n toepassing is wat die presiese tyd miljoene kere per sekonde versoek, soos SQL-bediener.
  • Maar dit is ook nie skrikwekkend nie, aangesien SQL-bediener dit nie altyd doen nie (sien gevolgtrekking)

Maar daar is gevalle wanneer hierdie hark seermaak. En ja, deur aan die wiel te klop (deur iets in die VM-instellings te verander), het ek VMware gedwing om die konfigurasie te 'herbereken', en die frekwensie van die huidige gasheer het die 'inheemse' frekwensie van die masjien geword.

besluit

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

Wanneer jy virtualisering van die TSC deaktiveer, gee die lees van die TSC van binne die virtuele masjien die fisiese masjien se TSC-waarde terug, en die skryf van die TSC van binne die virtuele masjien het geen effek nie. Om die virtuele masjien na 'n ander gasheer te migreer, dit te hervat vanaf 'n opgeskorte toestand, of terug te keer na 'n momentopname, veroorsaak dat die TSC ononderbroke spring. Sommige gasbedryfstelsels kan nie selflaai nie, of toon ander tydhouprobleme wanneer TSC-virtualisering gedeaktiveer is. In die verlede is hierdie kenmerk soms aanbeveel om werkverrigting te verbeter van toepassings wat die TSC gereeld lees, maar prestasie van die virtuele TSC is aansienlik verbeter in huidige produkte. Die kenmerk is ook aanbeveel vir gebruik wanneer metings uitgevoer word wat 'n presiese bron van intydse tyd in die virtuele masjien vereis.

Kortom, jy moet die parameter byvoeg

monitor_control.virtual_rdtsc = ONWAAR

Gevolgtrekking

Jy het waarskynlik 'n vraag: hoekom sou SQL GetTimePrecise so gereeld bel?

Ek het nie die SQL-bedienerbronne nie, maar die logika sΓͺ dit. SQL is amper 'n bedryfstelsel met samewerkende sameloop, waar elke draad van tyd tot tyd moet "padgee". Waar is die beste plek om dit te doen? Waar daar 'n natuurlike verwagting is - slot of IO. Goed, maar wat as ons rekenaarsiklusse draai? Dan is die ooglopende en amper die enigste plek in die tolk (dit is nie heeltemal 'n tolk nie), na die uitvoering van die volgende operateur.

As 'n reΓ«l word SQL-bediener nie vir suiwer rekenaar gebruik nie en dit is nie 'n probleem nie. Maar siklusse met werk met allerhande tydelike tabelle (wat onmiddellik gekas word) verander die kode in 'n reeks van baie vinnig uitgevoer stellings.

Terloops, as die funksie toegedraai is in NATIVELY COMPILED, dan hou dit op om tyd aan te vra, en sy spoed neem toe met 10 keer Maar wat van samewerkende multitasking? Maar vir inheemse saamgestelde kode, moes ek PREEMPTIVE MULTITASKING in SQL doen.

Bron: will.com

Voeg 'n opmerking