Ja, myn âlde laptop is ferskate kearen machtiger dan jo produksjetsjinner

Dit binne krekt de klachten dy't ik hearde fan ús ûntwikkelders. It meast nijsgjirrige is dat dit wier bliek te wêzen, wat oanlieding ta in lang ûndersyk. Wy sille prate oer SQL-tsjinners dy't rinne op VMware.

Ja, myn âlde laptop is ferskate kearen machtiger dan jo produksjetsjinner

Eins is it maklik om te soargjen dat de produksjetsjinner hopeleas efter de laptop is. Utfiere (net op tempdb en net op in database mei fertrage duorsumens ynskeakele) de koade:

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

Op myn buroblêd duorret it 5 sekonden, en op 'e produksjetsjinner duorret it 28 sekonden. Om't SQL moat wachtsje op it fysike ein fan 'e transaksje log yngong, en wy dogge hiel koarte transaksjes hjir. Rûchwei sprutsen, rieden wy in grutte, krêftige frachtwein yn it stedsferkear, en seagen hoe't it ynfallend waard ynhelle troch pizzabezorgers op scooters - trochstreaming is hjir net wichtich, allinich latency is wichtich. En gjin netwurk opslach, nettsjinsteande hoefolle nullen der binne yn syn priis, kin ferslaan de lokale SSD yn termen fan latency.

(yn de opmerkings die bliken dat ik leagens - ik hie op beide plakken fertrage duorsumens. Sûnder fertrage duorsumens docht bliken:
Buroblêd - 39 sekonden, 15K tr/sek, 0.065ms /io roundtrip
PROD - 360 sekonden, 1600 tr/sek, 0.6ms
Ik hie opfallen dat it te fluch wie)

Yn dit gefal hawwe wy lykwols te meitsjen mei triviale nullen fan 'e Riemann-zetafunksje mei in triviale foarbyld. Yn it foarbyld dat de ûntwikkelders my brochten, wie it oars. Ik wie derfan oertsjûge dat se gelyk hiene, en begûn te ferwiderjen út it foarbyld al harren specifics yn ferbân mei saaklike logika. Op in stuit realisearre ik dat ik har koade folslein koe smite en myn eigen skriuwe - wat itselde probleem toant - yn produksje rint it 3-4 kear 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 goed is, dan sil it kontrolearjen fan 'e primaliteit fan in nûmer 6-7-8 sekonden nimme. Dit barde op in oantal servers. Mar op guon naam de kontrôle 25-40 sekonden. Ynteressant wiene d'r gjin tsjinners wêr't de útfiering bygelyks 14 sekonden soe nimme - de koade wurke of heul fluch of heul stadich, dat is, it probleem wie, lit ús sizze, swart en wyt.

Wat ik dien haw? Brûkte VMware-metriken. Alles wie goed dêr - der wie in oerfloed fan middels, Ready tiid = 0, der wie genôch fan alles, tidens de test op sawol flugge en trage tsjinners CPU = 100 op ien vCPU. Ik naam in test om it getal Pi te berekkenjen - de test liet deselde resultaten sjen op elke server. De rook fan swarte magy waard sterker en sterker.

Sadree't ik kaam by de DEV pleats, Ik begûn boartsjen mei de tsjinners. It die bliken dat vMotion fan host nei host in tsjinner kin "geneze", mar it kin ek in "snelle" tsjinner yn in "stadich" feroarje. It liket derop dat dit it is - guon hosts hawwe in probleem ... mar ... nee. Guon firtuele masine wie stadich op host, sizze A, mar wurke fluch op host B. En in oare firtuele masine, krekt oarsom, wurke fluch op A en fertrage op B! Sawol "snelle" en "stadige" masines wiene faak spinnen op de host!

Fan dat momint ôf wie der in dúdlike rook fan swevel yn 'e loft. Ommers, it probleem koe net wurde taskreaun oan 'e firtuele masine (Windows-patches, bygelyks) - ommers, it feroare yn "fluch" mei vMotion. Mar it probleem koe ek net oan 'e host wurde taskreaun - it koe ommers sawol "snelle" as "stadige" masines hawwe. Ek dit wie net relatearre oan de lading - ik koe in "stadige" masine op 'e host krije, wêr't d'r neat oars wie.

Ut wanhoop lansearre ik Process Explorer fan Sysinternals en seach nei de SQL-stapel. Op trage masines foel de line my daliks yn it each:

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

Dit wie al wat. It programma waard skreaun:

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

Dit programma toande in noch mear útsprutsen fertraging - op "snelle" masines toant it 16-18 miljoen syklusen per sekonde, wylst op trage masines toant ien en in heal miljoen, of sels 700 tûzen. Dat is, it ferskil is 10-20 kear (!!!). Dit wie al in lytse oerwinning: d'r wie yn alle gefallen gjin bedriging om fêst te sitten tusken Microsoft en VMware-stipe sadat se pylken op elkoar draaie.

Doe stoppe de foarútgong - fakânsjes, wichtige saken, virale hystery en in skerpe tanimming fan wurkdruk. Ik neamde it magyske probleem faak oan myn kollega's, mar soms like it dat se my net iens altyd leauden - de útspraak dat VMware de koade mei 10-20 kear fertraget wie te meunsterlik.

Ik besocht mysels út te graven wat my fertrage. Soms like it my dat ik in oplossing fûn hie - Hot plugs oan en útsette, de hoemannichte ûnthâld feroarje of it oantal processors feroare de masine faaks yn in "snelle" ien. Mar net foar altyd. Mar wat blykte wier te wêzen is dat it genôch is om út te gean en op it tsjil te klopjen - dat is, feroarje ien firtuele masine parameter

Uteinlik fûnen myn Amerikaanske kollega's ynienen de woartel oarsaak.

Ja, myn âlde laptop is ferskate kearen machtiger dan jo produksjetsjinner

De hosts ferskille yn frekwinsje!

  • As regel, dit is net in grut probleem. Mar: by it ferpleatsen fan in 'native' host nei in host mei in 'oare' frekwinsje, moat VMware it GetTimePrecise-resultaat oanpasse.
  • As regel is dit gjin probleem, útsein as d'r in applikaasje is dy't de krekte tiid miljoenen kearen per sekonde freget, lykas SQL-tsjinner.
  • Mar dit is net eng, om't SQL-tsjinner dit net altyd docht (sjoch konklúzje)

Mar d'r binne gefallen dat dizze rake hurd rekket. En dochs, ja, troch op it tsjil te tikken (troch wat te feroarjen yn 'e VM-ynstellingen) twong ik VMware om de konfiguraasje 'opnij te berekkenjen', en de frekwinsje fan 'e hjoeddeistige host waard de 'native' frekwinsje fan 'e masine.

beslút

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

As jo ​​​​virtualisaasje fan 'e TSC útskeakelje, jout it lêzen fan' e TSC út 'e firtuele masine de TSC-wearde fan' e fysike masine werom, en it skriuwen fan 'e TSC fanút de firtuele masine hat gjin effekt. It migrearjen fan 'e firtuele masine nei in oare host, it werheljen fan' e ophâlden steat, of weromgean nei in momintopname feroarsaket de TSC om diskontinu te springen. Guon bestjoeringssystemen foar gast kinne net opstarte, of eksposearje oare timekeeping-problemen, as TSC-virtualisaasje is útskeakele. Yn it ferline is dizze funksje soms oanrikkemandearre om de prestaasjes te ferbetterjen fan applikaasjes dy't de TSC faak lêze, mar prestaasjes fan 'e firtuele TSC is substansjeel ferbettere yn hjoeddeistige produkten. De funksje is ek oanrikkemandearre foar gebrûk by it útfieren fan mjittingen dy't in krekte boarne fan echte tiid yn 'e firtuele masine fereaskje.

Koartsein moatte jo de parameter tafoegje

monitor_control.virtual_rdtsc = FALSE

konklúzje

Jo hawwe wierskynlik in fraach: wêrom neamt SQL GetTimePrecise sa faak?

Ik haw net de SQL tsjinner boarne koade, mar de logika seit dit. SQL is hast in bestjoeringssysteem mei koöperative concurrency, dêr't elke tried moat "jouwe yn" fan tiid ta tiid. Wêr is it bêste plak om dit te dwaan? Dêr't der in natuerlike wachtsjen - slot of IO. Okee, mar wat as wy komputearjende loops spinne? Dan is it foar de hân lizzende en hast ienige plak yn de tolk (dit is net echt in tolk), nei it útfieren fan de folgjende útspraak.

Yn 't algemien wurdt SQL-tsjinner net brûkt foar suvere komputer-nailing en dit is gjin probleem. Mar loops dy't wurkje mei allerhanne tydlike tabellen (dy't daliks yn 'e cache binne) meitsje de koade yn in folchoarder fan tige fluch útfierde útspraken.

Trouwens, as jo de funksje yn NATIVELY COMPILED ynpakke, dan stopet it om tiid te freegjen, en syn snelheid nimt ta mei 10 kear. Hoe sit it mei koöperative multitasking? Mar foar natuerlik kompilearre koade moasten wy PREEMPTIVE MULTITASKING dwaan yn SQL.

Boarne: www.habr.com

Add a comment