Kyllä, vanha kannettavani on useita kertoja tehokkaampi kuin tuotantopalvelimesi.

Juuri näitä valituksia kuulin kehittäjiltämme. Mielenkiintoisinta on, että tämä osoittautui todeksi ja aiheutti pitkän tutkimuksen. Puhumme SQL-palvelimista, jotka toimivat VMwarella.

Kyllä, vanha kannettavani on useita kertoja tehokkaampi kuin tuotantopalvelimesi.

Itse asiassa on helppo varmistaa, että tuotantopalvelin on toivottomasti kannettavan tietokoneen takana. Suorita (ei tempdb:ssä eikä tietokannassa, jossa on viivästetty kestävyys käytössä) koodi:

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

Työpöydälläni se kestää 5 sekuntia ja tuotantopalvelimella 28 sekuntia. Koska SQL:n on odotettava tapahtumalokimerkinnän fyysistä loppua, ja teemme täällä erittäin lyhyitä tapahtumia. Karkeasti sanottuna ajoimme ison, tehokkaan kuorma-auton kaupunkiliikenteeseen ja katselimme, kuinka skoottereiden pizzanjakelijat ohittivat sen räjähdysmäisesti - läpijuoksulla ei ole tässä merkitystä, vain latenssilla on merkitystä. Eikä mikään verkkotallennustila, vaikka sen hinnassa olisi kuinka monta nollaa, voi lyödä paikallista SSD-levyä latenssissa.

(kommenteissa kävi ilmi, että valehtelin - minulla oli viivästynyt kestävyys molemmissa paikoissa. Ilman viivästynyttä kestävyyttä selviää:
Pöytäkone – 39 sekuntia, 15 0.065 tr/s, XNUMX ms/io edestakainen matka
PROD - 360 sekuntia, 1600 tr/s, 0.6 ms
Minun olisi pitänyt huomata, että se oli liian nopea)

Tässä tapauksessa on kuitenkin kyseessä Riemannin zeta-funktion triviaaliset nollit triviaalin esimerkin avulla. Esimerkissä, jonka kehittäjät toivat minulle, se oli erilainen. Olin vakuuttunut siitä, että he olivat oikeassa, ja aloin poistaa esimerkistä kaikkia heidän liiketoimintalogiikkaan liittyviä yksityiskohtiaan. Jossain vaiheessa tajusin, että voisin heittää heidän koodinsa kokonaan pois ja kirjoittaa oman - mikä osoittaa saman ongelman - tuotannossa se toimii 3-4 kertaa hitaammin:

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

Jos kaikki on kunnossa, numeron ensisijaisuuden tarkistaminen kestää 6-7-8 sekuntia. Tämä tapahtui useilla palvelimilla. Mutta joillain tarkistus kesti 25-40 sekuntia. Mielenkiintoista kyllä, ei ollut palvelimia, joiden suorittaminen kestäisi vaikkapa 14 sekuntia - koodi toimi joko hyvin nopeasti tai hyvin hitaasti, eli ongelma oli vaikkapa mustavalkoinen.

Mitä olen tehnyt? Käytetyt VMware-mittarit. Siellä kaikki oli hyvin - resursseja oli runsaasti, Valmistusaika = 0, kaikkea riitti, testin aikana sekä nopeilla että hitailla palvelimilla CPU = 100 yhdellä vCPU:lla. Tein testin Pi-luvun laskemiseksi - testi osoitti samat tulokset millä tahansa palvelimella. Mustan magian tuoksu vahvistui ja vahvistui.

Kun pääsin DEV-farmille, aloin pelaamaan palvelimilla. Kävi ilmi, että vMotion isännästä isäntään voi "parantaa" palvelimen, mutta se voi myös muuttaa "nopean" palvelimen "hidasteeksi". Näyttää siltä, ​​että tämä on - joillakin isännillä on ongelma... mutta... ei. Jotkut virtuaalikoneet olivat hitaita isännässä, esimerkiksi A, mutta toimivat nopeasti isännässä B. Ja toinen virtuaalikone päinvastoin toimi nopeasti A:lla ja hidastui B:llä! Sekä "nopeat" että "hitaat" koneet pyörivät usein isännässä!

Siitä hetkestä lähtien ilmassa oli selkeä rikin haju. Loppujen lopuksi ongelmaa ei voitu johtua virtuaalikoneesta (esimerkiksi Windows-korjaukset) - loppujen lopuksi se muuttui "nopeaksi" vMotionilla. Mutta ongelmaa ei myöskään voitu johtua isännästä - sillä voi loppujen lopuksi olla sekä "nopeita" että "hitaita" koneita. Tämä ei myöskään liittynyt kuormaan - onnistuin saamaan "hitaan" koneen isäntään, jossa ei ollut mitään sen lisäksi.

Epätoivosta käynnistin Process Explorerin Sysinternalsista ja katsoin SQL-pinoa. Hitaissa koneissa rivi pisti heti silmään:

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

Tämä oli jo jotain. Ohjelma kirjoitettiin:

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

Tämä ohjelma osoitti vielä selvempää hidastumista - "nopeilla" koneilla se näyttää 16-18 miljoonaa sykliä sekunnissa, kun taas hitaissa koneissa se näyttää puolitoista miljoonaa tai jopa 700 tuhatta. Eli ero on 10-20 kertaa (!!!). Tämä oli jo pieni voitto: joka tapauksessa ei ollut uhkaa juuttua Microsoftin ja VMwaren tuen väliin, jotta ne kääntäisivät nuolia toisiaan vastaan.

Sitten kehitys pysähtyi - lomat, tärkeät asiat, virushysteria ja jyrkkä työmäärän kasvu. Mainitsin usein taikaongelmasta kollegoilleni, mutta välillä näytti siltä, ​​että he eivät edes aina uskoneet minua - väite, että VMware hidastaa koodia 10-20 kertaa, oli liian hirveä.

Yritin kaivaa itsestäni esiin, mikä hidasti minua. Välillä minusta tuntui, että olin löytänyt ratkaisun - Hot plugin kytkeminen päälle ja pois, muistin määrän tai prosessorien lukumäärän muuttaminen teki koneesta usein "nopean". Mutta ei ikuisesti. Mutta mikä osoittautui todeksi, on se, että riittää mennä ulos ja koputtaa pyörään - eli vaihtaa kaikki virtuaalikoneen parametri

Lopulta amerikkalaiset kollegani löysivät yhtäkkiä perimmäisen syyn.

Kyllä, vanha kannettavani on useita kertoja tehokkaampi kuin tuotantopalvelimesi.

Isännät erosivat taajuudesta!

  • Yleensä tämä ei ole iso juttu. Mutta: siirryttäessä "alkuperäisestä" isännästä "eri"taajuudella olevaan isäntään, VMwaren on säädettävä GetTimePrecise-tulosta.
  • Pääsääntöisesti tämä ei ole ongelma, ellei ole olemassa sovellusta, joka pyytää tarkkaa aikaa miljoonia kertoja sekunnissa, kuten SQL-palvelin.
  • Mutta tämä ei ole pelottavaa, koska SQL-palvelin ei aina tee tätä (katso johtopäätös)

Mutta on tapauksia, joissa tämä harava osuu kovaa. Ja kuitenkin, kyllä, napauttamalla pyörää (muutamalla jotain VM-asetuksissa) pakotin VMwaren "laskemaan uudelleen" kokoonpanon, ja nykyisen isännän taajuudesta tuli koneen "natiivi" taajuus.

päätös

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

Kun poistat TSC:n virtualisoinnin käytöstä, TSC:n lukeminen virtuaalikoneen sisältä palauttaa fyysisen koneen TSC-arvon, eikä TSC:n kirjoittaminen virtuaalikoneen sisältä vaikuta. Virtuaalikoneen siirtäminen toiseen isäntään, sen palauttaminen keskeytetystä tilasta tai tilannekuvaan palauttaminen saa TSC:n hyppäämään epäjatkuvasti. Jotkut vieraskäyttöjärjestelmät eivät käynnisty tai niissä on muita ajanotto-ongelmia, kun TSC-virtualisointi on poistettu käytöstä. Aiemmin tätä ominaisuutta on joskus suositeltu parantamaan sovellusten suorituskykyä, jotka lukevat usein TSC:tä, mutta virtuaalisen TSC:n suorituskykyä on parannettu huomattavasti nykyisissä tuotteissa. Ominaisuutta on myös suositeltu käytettäväksi suoritettaessa mittauksia, jotka vaativat tarkan reaaliaikalähteen virtuaalikoneessa.

Lyhyesti sanottuna sinun on lisättävä parametri

monitor_control.virtual_rdtsc = EPÄTOSI

Johtopäätös

Sinulla on luultavasti kysymys: miksi SQL kutsuu GetTimePrecisea niin usein?

Minulla ei ole SQL-palvelimen lähdekoodia, mutta logiikka sanoo tämän. SQL on melkein käyttöjärjestelmä, jossa on yhteistoiminnallinen samanaikaisuus, jossa jokaisen säikeen täytyy ajoittain "antaa periksi". Missä on paras paikka tehdä tämä? Missä on luonnollinen odotus - lukko tai IO. Okei, mutta entä jos pyöritämme laskennallisia silmukoita? Sitten ilmeinen ja melkein ainoa paikka on tulkissa (tämä ei todellakaan ole tulkki), seuraavan lauseen suorittamisen jälkeen.

Yleensä SQL-palvelinta ei käytetä puhtaaseen laskentaan, eikä tämä ole ongelma. Mutta silmukat, jotka toimivat kaikenlaisten väliaikaisten taulukoiden kanssa (jotka ovat välittömästi välimuistissa), muuttavat koodin erittäin nopeasti suoritettavien lauseiden sarjaksi.

Muuten, jos funktio kääritään muotoon NATIVELY COMILED, se lakkaa pyytämästä aikaa ja sen nopeus kasvaa 10-kertaiseksi. Entä yhteistoiminnallinen moniajo? Mutta natiivisti käännettyä koodia varten meidän piti tehdä ENNAKKOINEN MULTITASKING SQL:ssä.

Lähde: will.com

Lisää kommentti