Jā, mans vecais klēpjdators ir vairākas reizes jaudÄ«gāks par jÅ«su ražoÅ”anas serveri

TieÅ”i Ŕādas sÅ«dzÄ«bas es dzirdēju no mÅ«su izstrādātājiem. Interesantākais ir tas, ka tā izrādÄ«jās patiesÄ«ba, kas izraisÄ«ja ilgu izmeklÄ“Å”anu. Mēs runāsim par SQL serveriem, kas darbojas VMware.

Jā, mans vecais klēpjdators ir vairākas reizes jaudÄ«gāks par jÅ«su ražoÅ”anas serveri

PatiesÄ«bā ir viegli nodroÅ”ināt, ka ražoÅ”anas serveris bezcerÄ«gi atrodas aiz klēpjdatora. Izpildiet kodu (nevis tempdb un datu bāzē, kurā ir iespējota kavētā izturÄ«ba) kodu:

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

Manā darbvirsmā tas aizņem 5 sekundes, bet ražoÅ”anas serverÄ« - 28 sekundes. Tā kā SQL ir jāgaida darÄ«jumu žurnāla ieraksta fiziskā beigas, un mēs Å”eit veicam ļoti Ä«sus darÄ«jumus. Aptuveni sakot, mēs iebraucām pilsētas satiksmē ar lielu, jaudÄ«gu kravas automaŔīnu un skatÄ«jāmies, kā to braÅ”i apdzina picu piegādātāji ar motorolleriem - caurlaidspēja Å”eit nav svarÄ«ga, svarÄ«gs ir tikai latentums. Un neviena tÄ«kla krātuve, neatkarÄ«gi no tā, cik nulles ir tās cenā, nevar pārspēt vietējo SSD latentuma ziņā.

(komentāros izrādījās, ka meloju - abās vietās man bija aizkavējusies izturība. Bez aizkavētās izturības izrādās:
Galddators ā€” 39 sekundes, 15 0.065 tr/s, XNUMX ms/io turp un atpakaļ
PROD ā€” 360 sekundes, 1600 tr/s, 0.6 ms
Man vajadzēja ievērot, ka tas bija pārāk ātri)

Tomēr Å”ajā gadÄ«jumā mums ir darÄ«Å”ana ar triviālām RÄ«maņa zeta funkcijas nullēm ar triviālu piemēru. Piemērā, ko man atnesa izstrādātāji, tas bija savādāk. Es biju pārliecināts, ka viņiem ir taisnÄ«ba, un sāku izņemt no piemēra visu viņu specifiku, kas saistÄ«ta ar biznesa loÄ£iku. Kādā brÄ«dÄ« es sapratu, ka varu pilnÄ«bā izmest viņu kodu un uzrakstÄ«t savu - kas parāda to paÅ”u problēmu - ražoÅ”anā tas darbojas 3-4 reizes lēnāk:

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

Ja viss ir kārtÄ«bā, skaitļa pirmatnÄ«bas pārbaude prasÄ«s 6-7-8 sekundes. Tas notika vairākos serveros. Bet dažiem pārbaude aizņēma 25ā€“40 sekundes. Interesanti, ka nebija serveru, kur izpilde aizņemtu, teiksim, 14 sekundes ā€“ kods darbojās vai nu ļoti ātri, vai ļoti lēni, proti, problēma bija, teiksim, melnbalta.

Ko es esmu izdarÄ«jis? Izmantotā VMware metrika. Tur viss bija kārtÄ«bā - bija resursu pārbagātÄ«ba, Ready time = 0, visa kā pietika, testa laikā gan uz ātrajiem, gan lēnajiem serveriem CPU = 100 uz viena vCPU. Es veicu testu, lai aprēķinātu skaitli Pi - tests parādÄ«ja tādus paÅ”us rezultātus jebkurā serverÄ«. Melnās maÄ£ijas smarža kļuva arvien spēcÄ«gāka.

Kad nokļuvu DEV fermā, sāku spēlēt ar serveriem. IzrādÄ«jās, ka vMotion no resursdatora uz resursdatoru var ā€œizārstētā€ serveri, bet tas var arÄ« pārvērst ā€œÄtroā€ serveri par ā€œlēnuā€. Å Ä·iet, ka tā ir - dažiem saimniekiem ir problēma... bet... nē. Dažas virtuālās maŔīnas darbojās lēni resursdatorā, piemēram, A, bet darbojās ātri resursdatorā B. Un cita virtuālā maŔīna, gluži pretēji, ātri darbojās uz A un palēnināja B! Uz saimnieka bieži griezās gan ā€œÄtrāsā€, gan ā€œlēnāsā€ maŔīnas!

KopÅ” tā brīža gaisā bija jÅ«tama izteikta sēra smaka. Galu galā problēmu nevarēja saistÄ«t ar virtuālo maŔīnu (piemēram, Windows ielāpus) - galu galā tā kļuva par ā€œÄtruā€, izmantojot vMotion. Bet problēmu arÄ« nevarēja saistÄ«t ar saimniekdatoru - galu galā tam varētu bÅ«t gan ā€œÄtrasā€, gan ā€œlēnasā€ maŔīnas. ArÄ« tas nebija saistÄ«ts ar slodzi - man izdevās uz resursdatora dabÅ«t ā€œlēnuā€ maŔīnu, kurā bez tā nebija nekā.

Aiz izmisuma es palaižu Process Explorer no Sysinternals un paskatÄ«jos uz SQL steku. Lēnās maŔīnās lÄ«nija uzreiz iekrita acÄ«s:

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

Tas jau bija kaut kas. Programma tika uzrakstīta:

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

Å Ä« programma demonstrēja vēl izteiktāku palēninājumu - uz ā€œÄtrāmā€ maŔīnām tā rāda 16-18 miljonus ciklu sekundē, savukārt uz lēnām maŔīnām uzrāda pusotru miljonu vai pat 700 tÅ«kstoÅ”us. Tas ir, atŔķirÄ«ba ir 10-20 reizes (!!!). Å Ä« jau bija maza uzvara: jebkurā gadÄ«jumā nebija nekādu draudu iesprÅ«st starp Microsoft un VMware atbalstu, lai tie grieztu viens pret otru bultas.

Tad progress apstājās ā€“ atvaļinājumi, svarÄ«gas lietas, vÄ«rusu histērija un straujÅ” darba slodzes pieaugums. Bieži pieminēju maÄ£isko problēmu saviem kolēģiem, taču brīžiem Ŕķita, ka viņi pat ne vienmēr man tic - apgalvojums, ka VMware palēnina kodu 10-20 reizes, bija pārāk zvērÄ«gs.

Es mēģināju pats izrakt to, kas mani bremzē. Brīžiem Ŕķita, ka esmu atradis risinājumu - Hot plugs ieslēgÅ”ana un izslēgÅ”ana, atmiņas apjoma vai procesoru skaita maiņa bieži vien padarÄ«ja maŔīnu par ā€œÄtroā€. Bet ne uz visiem laikiem. Taču patiesÄ«ba izrādÄ«jās, ka pietiek iziet ārā un pieklauvēt pie stÅ«res ā€“ tas ir, pārģērbties jebkurÅ” virtuālās maŔīnas parametrs

Visbeidzot, mani amerikāņu kolēģi pēkŔņi atrada galveno cēloni.

Jā, mans vecais klēpjdators ir vairākas reizes jaudÄ«gāks par jÅ«su ražoÅ”anas serveri

Saimnieki atŔķīrās pēc biežuma!

  • Kā likums, tas nav nekas liels. Bet: pārejot no ā€œvietējāā€ resursdatora uz resursdatoru ar ā€œatŔķirÄ«guā€ frekvenci, VMware ir jāpielāgo GetTimePrecise rezultāts.
  • Parasti tā nav problēma, ja vien nav lietojumprogrammas, kas pieprasa precÄ«zu laiku miljoniem reižu sekundē, piemēram, SQL serveris.
  • Bet tas nav biedējoÅ”i, jo SQL serveris ne vienmēr to dara (skatiet Secinājumu)

Bet ir gadÄ«jumi, kad Å”is grābeklis sit smagi. Un tomēr, jā, pieskaroties ritenim (kaut ko mainot VM iestatÄ«jumos), es piespiedu VMware ā€œpārrēķinātā€ konfigurāciju, un paÅ”reizējā resursdatora frekvence kļuva par maŔīnas ā€œdzimtoā€ frekvenci.

Å Ä·Ä«dums

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

Atspējojot TSC virtualizāciju, nolasot TSC no virtuālās maŔīnas, tiek atgriezta fiziskās maŔīnas TSC vērtÄ«ba, un TSC rakstÄ«Å”anai no virtuālās maŔīnas nav nekādas ietekmes. Migrējot virtuālo maŔīnu uz citu resursdatoru, atsākot to no apturēta stāvokļa vai atgriežoties uz momentuzņēmumu, TSC pārlec nepārtraukti. Dažām viesu operētājsistēmām neizdodas sāknēties vai rodas citas hronometrāžas problēmas, kad TSC virtualizācija ir atspējota. Agrāk Ŕī funkcija dažkārt tika ieteikta, lai uzlabotu to lietojumprogrammu veiktspēju, kuras bieži lasa TSC, taču paÅ”reizējos produktos virtuālā TSC veiktspēja ir bÅ«tiski uzlabota. Funkciju ieteicams izmantot arÄ«, veicot mērÄ«jumus, kuriem nepiecieÅ”ams precÄ«zs reāllaika avots virtuālajā maŔīnā.

ÄŖsāk sakot, jums jāpievieno parametrs

monitor_control.virtual_rdtsc = FALSE

Secinājums

Jums droÅ”i vien ir jautājums: kāpēc SQL tik bieži izsauc GetTimePrecise?

Man nav SQL servera pirmkoda, bet loÄ£ika to saka. SQL ir gandrÄ«z operētājsistēma ar kooperatÄ«vu vienlaicÄ«gumu, kur katram pavedienam ik pa laikam ir ā€œjāpiekāpjasā€. Kur ir vislabākā vieta, kur to izdarÄ«t? Kur ir dabiska gaidÄ«Å”ana - slēdzene vai IO. Labi, bet ja mēs griežam skaitļoÅ”anas cilpas? Tad acÄ«mredzamā un gandrÄ«z vienÄ«gā vieta ir tulkā (tas Ä«sti nav tulks), pēc nākamā paziņojuma izpildÄ«Å”anas.

Parasti SQL serveri neizmanto tÄ«rai skaitļoÅ”anas naglām, un tā nav problēma. Bet cilpas, kas strādā ar visādām pagaidu tabulām (kas tiek nekavējoties saglabātas keÅ”atmiņā), pārvērÅ” kodu ļoti ātri izpildāmu paziņojumu secÄ«bā.

Starp citu, ja funkciju iesaiņo NATIVELY COMPILED, tad tā pārstāj prasÄ«t laiku, un tās ātrums palielinās 10 reizes.. Kā ar kooperatÄ«vo daudzuzdevumu veikÅ”anu? Bet sākotnēji kompilēta koda gadÄ«jumā mums bija jāveic PREEMPTIVE MULTITASKING SQL.

Avots: www.habr.com

Pievieno komentāru