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 sila ay naging totoo, na nag-udyok ng isang mahabang pagsisiyasat. May kinalaman ito sa mga SQL server na pinapatakbo namin sa VMware.

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

Sa katunayan, madaling gawing walang pag-asa ang isang production server sa likod ng isang laptop. Patakbuhin ang sumusunod na code (hindi sa tempdb o sa isang database na pinagana ang Delayed Durability):

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, 28 segundo. Ito ay dahil kailangang hintayin ng SQL na pisikal na maisulat ang log ng transaksyon, at napakaikling mga transaksyon ang ginagawa namin dito. Sa halos pagsasalita, nagmaneho kami ng isang malaki at malakas na trak sa trapiko sa lungsod at pinapanood namin ang mga driver ng paghahatid ng pizza sa mga scooter na lumalampas dito—hindi mahalaga ang throughput dito, ang latency lang. At walang network storage, gaano man karaming mga zero sa presyo nito, ang makakatalo sa lokal na SSD sa latency.

(Sa mga komento, lumabas na nagsinungaling ako—naantala ko ang tibay sa parehong lugar. Nang walang naantala na tibay, ganito ang hitsura:
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, nakikitungo kami sa mga walang kuwentang zero ng Riemann zeta function na may maliit na halimbawa. Iba ang halimbawang dinala sa akin ng mga developer. Nakumbinsi akong tama sila at sinimulan kong alisin ang lahat ng mga detalye nito na may kaugnayan sa lohika ng negosyo. Sa ilang mga punto, napagtanto ko na maaari kong itapon ang kanilang code nang buo at isulat ang aking sarili-isa na nagpapakita ng parehong problema-ngunit sa produksyon, ito ay tumatakbo nang 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, ang primality check ay tatagal ng 6-7-8 segundo. Ganito ang nangyari sa serye. mga serverNgunit sa ilang mga server, ang pagsusuri ay tumagal nang 25-40 segundo. Kapansin-pansin, walang mga server kung saan ang pagpapatupad ay tumagal, halimbawa, ng 14 na segundo—ang code ay tumakbo nang napakabilis o napakabagal, ibig sabihin ang problema ay, wika nga, itim at puti.

Anong ginawa ko? Sinuri ko ang mga sukatan ng VMware. Maayos ang lahat doon—maraming mapagkukunan, Oras ng Handa = 0, maayos ang lahat, at sa panahon ng pagsubok, pareho sa mabilis at mabagal na server, CPU = 100 sa isang vCPU. Pinatakbo ko ang pagsubok sa pagkalkula ng Pi—ang mga resulta ay pare-pareho sa lahat ng server. Lalong lumakas ang amoy ng black magic.

Pagkarating ko sa dev farm, nagsimula akong maglaro sa mga server. Napag-alaman na ang vMotion mula sa host hanggang host ay maaaring "gamutin" ang isang server, ngunit maaari rin nitong gawing "mabagal" ang isang "mabilis" na server. Parang iyon lang—may mga host na nagkakaproblema... pero... hindi. Ang isang virtual machine ay mabagal sa host, sabihin nating, A, ngunit mabilis na tumakbo sa host B. Ang isa pang virtual machine, sa kabilang banda, ay mabilis na tumakbo sa A at bumagal sa B! Ang parehong "mabilis" at "mabagal" na mga makina ay madalas na tumatakbo sa parehong host!

Mula sa sandaling iyon, may kakaibang amoy ng asupre sa hangin. Ang problema ay hindi maiugnay sa virtual machine (mga Windows patch, halimbawa)—ito ay na-convert sa "mabilis" sa panahon ng vMotion. Ngunit ang problema ay hindi rin maiugnay sa host—maaaring mayroon itong parehong "mabilis" at "mabagal" na mga makina. Hindi rin ito nauugnay sa pagkarga—nakuha ko ang isang "mabagal" na makina sa host, kung saan wala nang iba pa.

Sa desperasyon, inilunsad ko ang Sysinternals' Process Explorer at tiningnan ang SQL stack. Sa mga mabagal na makina, ang linyang agad na nakatawag ng pansin sa akin ay:

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. Isang programa ang 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 programang ito ay nagpakita ng mas kapansin-pansing paghina: sa "mabilis" na mga makina, nagpakita ito ng 16-18 milyong cycle bawat segundo, habang sa mas mabagal, ito ay 1.5 milyon o kahit 700,000. Iyan ay 10-20x na pagkakaiba (!!!). Ito ay isang maliit na tagumpay: hindi bababa sa walang panganib na makaalis sa pagitan ng suporta ng Microsoft at VMware, kasama nila ang pagpasa ng pera.

Pagkatapos ay natigil ang pag-unlad—bakasyon, mahahalagang bagay, virus hysteria, at isang matinding pagtaas sa workload. Madalas kong banggitin ang mahiwagang problema sa aking mga kasamahan, ngunit kung minsan ay tila hindi sila naniniwala sa akin—ang pag-aangkin na ang VMware ay nagpapabagal sa code ng 10-20 beses ay masyadong mapangahas.

Sinubukan kong malaman kung ano ang nagpapabagal sa aking sarili. Kung minsan, naisip kong makakahanap ako ng solusyon—ang pagpapagana at pag-disable ng Hot Plugs, pagpapalit ng laki ng memorya, o ang bilang ng mga processor na kadalasang ginagawang "mabilis" ang makina. Pero hindi forever. Ang naging totoo ay ang kailangan mo lang gawin ay lumabas at i-tap ang gulong—iyon ay, baguhin ito. 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!

  • Ito ay karaniwang hindi isang problema. Gayunpaman, kapag lumipat mula sa katutubong host patungo sa isang host na may ibang frequency, dapat ayusin ng VMware ang resulta ng GetTimePrecise.
  • Ito ay karaniwang hindi isang malaking deal maliban kung mayroon kang isang application na humihiling ng eksaktong oras milyon-milyong beses bawat segundo, tulad ng SQL Server.
  • Ngunit hindi ito isang malaking pakikitungo, dahil hindi ito palaging ginagawa ng SQL Server (tingnan ang Konklusyon)

Ngunit may mga kaso kapag ang rake na ito ay tumama nang husto. At oo, sa pamamagitan ng pagtapik sa gulong (pagbabago ng isang bagay sa mga setting ng VM), pinilit ko ang VMware na 'muling kalkulahin' ang pagsasaayos, at ang kasalukuyang dalas ng 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 ang 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 magdagdag ng isang parameter

monitor_control.virtual_rdtsc = MALI

Konklusyon

Marahil ay nagtataka ka: bakit kailangang tawagan ng SQL ang GetTimePrecise nang madalas?

Wala akong source code ng SQL Server, ngunit idinidikta ito ng lohika. Ang SQL ay halos tulad ng isang operating system na may cooperative concurrency, kung saan ang bawat thread ay dapat magbunga paminsan-minsan. At saan ang pinakamagandang lugar para gawin ito? Kung saan may natural na paghihintay—isang lock o IO. Okay, ngunit paano kung nagpapatakbo kami ng mga computational loops? Pagkatapos ang halata at halos tanging lugar ay nasa interpreter (ito ay hindi talaga isang interpreter), pagkatapos isagawa ang susunod na pahayag.

Ang SQL Server ay hindi karaniwang ginagamit para sa dalisay na pagkalkula, at hindi iyon problema. Gayunpaman, ang mga loop na kinasasangkutan ng mga pansamantalang talahanayan (na agad na naka-cache) ay binabago ang code sa isang pagkakasunud-sunod ng napakabilis na naisakatuparan na mga pahayag.

Siyanga pala, kung ibalot mo ang isang function sa NATIVELY COMPILED, hihinto ito sa pagtatanong, at tataas ng sampung beses ang bilis nito. Ngunit ano ang tungkol sa cooperative multitasking? Para sa natively compiled code, kinailangan kong paganahin ang PREEMPTIVE MULTITASKING sa SQL.

Pinagmulan: www.habr.com

Bumili ng maaasahang pagho-host para sa mga site na may proteksyon ng DDoS, mga server ng VPS VDS 🔥 Bumili ng maaasahang website hosting na may proteksyon ng DDoS, VPS VDS servers | ProHoster