Po, laptopi im më i vjetër është disa herë më i fuqishëm se serveri juaj i prodhimit.

Këto janë pikërisht ankimet që dëgjova nga zhvilluesit tanë. Më e çuditshmja është se kjo u vërtetua të jetë e vërtetë, duke filluar një hetim të gjatë. Bëhet fjalë për serverët SQL, të cilët funksionojnë te ne në VMware.

Po, laptopi im më i vjetër është disa herë më i fuqishëm se serveri juaj i prodhimit.

Në fakt, është shumë e lehtë të bësh që production server të mbetet pa shpresë pas laptopit. Ekzekutoni këtë kod (jo në tempdb dhe jo në një bazë me Delayed Durability të aktivizuar):

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

NĂ« desktopin tim ai ekzekutohet pĂ«r 5 sekonda, ndĂ«rsa nĂ« production server pĂ«r 28 sekonda. Arsyeja Ă«shtĂ« se SQL duhet tĂ« presĂ« pĂ«rfundimin fizik tĂ« shkrimit nĂ« transaction log, ndĂ«rsa kĂ«tu po bĂ«jmĂ« transaksione shumĂ« tĂ« shkurtra. Me pak fjalĂ«, kemi futur njĂ« kamion tĂ« madh e tĂ« fuqishĂ«m nĂ« trafikun e qytetit dhe po shohim si e parakalojnĂ« me lehtĂ«si korrierĂ«t e picave me skuterĂ« — kĂ«tu nuk ka rĂ«ndĂ«si throughput, por vetĂ«m latency. Dhe asnjĂ« network storage, sado zero tĂ« ketĂ« nĂ« çmim, nuk mund ta mposhtĂ« njĂ« SSD lokal pĂ«r nga latency.

(nĂ« komente doli qĂ« kisha gabuar — nĂ« tĂ« dyja rastet mĂ« ishte futur delayed durability. Pa delayed durability del kĂ«shtu:
Desktop — 39 sekonda, 15K tr/sec, 0.065ms /io roundtrip
PROD — 360 sekonda, 1600 tr/sec, 0.6ms
Duhej ta kisha vënë re që ishte tepër shpejt)

MegjithatĂ«, nĂ« kĂ«tĂ« rast kemi tĂ« bĂ«jmĂ« me zero triviale tĂ« funksionit zeta tĂ« Riemann-it dhe me njĂ« shembull trivial. NĂ« shembullin qĂ« mĂ« sollĂ«n zhvilluesit, situata ishte tjetĂ«r. U binda qĂ« kishin tĂ« drejtĂ« dhe nisa tĂ« pastroja nga shembulli tĂ« gjithĂ« specifikĂ«n e tyre tĂ« lidhur me logjikĂ«n e biznesit. NĂ« njĂ« moment kuptova se mund ta hiqja plotĂ«sisht kodin e tyre dhe tĂ« shkruaja timin — i cili demonstron tĂ« njĂ«jtin problem — nĂ« production ai ekzekutohet 3-4 herĂ« mĂ« ngadalĂ«:

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

NĂ«se gjithçka Ă«shtĂ« nĂ« rregull, atĂ«herĂ« kontrolli i thjeshtĂ«sisĂ« sĂ« numrit do tĂ« zgjasĂ« 6-7-8 sekonda. KĂ«shtu ndodhte edhe nĂ« njĂ« sĂ«rĂ« serverĂ«sh. Por nĂ« disa raste kontrolli zgjaste 25-40 sekonda. Interesante Ă«shtĂ« se nuk kishte serverĂ« ku ekzekutimi tĂ« zgjaste, tĂ« themi, 14 sekonda — kodi punonte ose shumĂ« shpejt, ose shumĂ« ngadalĂ«, pra problemi ishte, si tĂ« thuash, bardh e zi.

ÇfarĂ« bĂ«ra? Hyra te metrikat e VMware. Aty gjithçka dukej nĂ« rregull — burimet ishin mĂ« se tĂ« mjaftueshme, Ready time = 0, gjithçka mjaftonte; gjatĂ« testit, si nĂ« serverĂ«t e shpejtĂ« ashtu edhe nĂ« ata tĂ« ngadaltĂ«, CPU=100 nĂ« njĂ« vCPU. Mora testin pĂ«r llogaritjen e numrit Pi — testi jepte tĂ« njĂ«jtat rezultate nĂ« çdo server. GjithnjĂ« e mĂ« shumĂ« dukej si magji e zezĂ«.

Pasi hyra nĂ« fermĂ«n DEV, fillova tĂ« eksperimentoja me serverĂ«t. Doli se vMotion nga njĂ« host nĂ« tjetrin mund ta «shĂ«rojë» serverin, por edhe anasjelltas, ta kthejĂ« njĂ« server «tĂ« shpejtë» nĂ« «tĂ« ngadaltë». U duk sikur ja ku ishte zgjidhja — disa hoste kishin problem
 por
 jo. NjĂ« makinĂ« virtuale ngadalĂ«sohej nĂ« hostin A, pĂ«r shembull, por punonte shpejt nĂ« hostin B. NdĂ«rsa njĂ« tjetĂ«r, pĂ«rkundrazi, punonte shpejt nĂ« A dhe ngadalĂ«sohej nĂ« B! NĂ« tĂ« njĂ«jtin host shpesh ekzekutoheshin si makina «tĂ« shpejta», ashtu edhe «tĂ« ngadalta»!

QĂ« nga ai moment, nĂ« ajĂ«r u ndie qartĂ« era e squfurit. Problemi nuk mund t'i atribuohej as makinĂ«s virtuale (pĂ«r shembull, Windows patches) — sepse me vMotion ajo kthehej nĂ« «tĂ« shpejtë». Por problemi nuk mund t'i atribuohej as hostit — sepse nĂ« tĂ« mund tĂ« kishte njĂ«kohĂ«sisht si makina «tĂ« shpejta», ashtu edhe «tĂ« ngadalta». Po ashtu nuk lidhej me ngarkesĂ«n — arrita tĂ« merrja njĂ« makinĂ« «tĂ« ngadaltë» nĂ« njĂ« host ku, pĂ«rveç saj, nuk kishte fare asgjĂ« tjetĂ«r.

Nga dëshpërimi hapa Process Explorer nga Sysinternals dhe pashë stack-un e SQL. Në makinat e ngadalta më ra menjëherë në sy rreshti:

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

 u anashkalua
sqldk.dll!SystemThread::MakeMiniSOSThread+0xa54
KERNEL32.DLL!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

Kjo tashmë ishte diçka. U shkrua një program:

    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  0)
                {
                    Console.WriteLine("{0}", counter);
                }
            }
        }
    }

Ky program tregoi njĂ« ngadalĂ«sim edhe mĂ« tĂ« theksuar: nĂ« makinat “e shpejta” ai jepte 16-18 milionĂ« cikle nĂ« sekondĂ«, ndĂ«rsa nĂ« tĂ« ngadalta — njĂ« milion e gjysmĂ«, madje edhe 700 mijĂ«. Pra, diferenca arrinte 10-20 herĂ« (!!!). Kjo ishte tashmĂ« njĂ« fitore e vogĂ«l: tĂ« paktĂ«n nuk kishte rrezik tĂ« mbeteshim mes support-it tĂ« Microsoft dhe VMware, duke ia kaluar fajin njĂ«ri-tjetrit.

MĂ« pas progresi u ndal — pushimet, çështjet e rĂ«ndĂ«sishme, histeria virale dhe rritja e menjĂ«hershme e ngarkesĂ«s. Shpesh ua pĂ«rmendja kolegĂ«ve kĂ«tĂ« problem “magjik”, por ndonjĂ«herĂ« mĂ« dukej sikur jo gjithmonĂ« mĂ« besonin — pretendimi se VMware e ngadalĂ«son kodin 10-20 herĂ« dukej tepĂ«r i pabesueshĂ«m.

U pĂ«rpoqa ta zbuloj vetĂ« se çfarĂ« po e ngadalĂ«sonte. HerĂ« pas here mĂ« dukej se e kisha gjetur zgjidhjen — aktivizimi dhe çaktivizimi i Hot plugs, ndryshimi i sasisĂ« sĂ« memories ose i numrit tĂ« procesorĂ«ve shpesh e kthente makinĂ«n nĂ« “tĂ« shpejtĂ«â€. Por jo pĂ«rgjithmonĂ«. Ajo qĂ« doli e vĂ«rtetĂ« ishte kjo: mjaftonte tĂ« dilje e t’i bija rrotĂ«s me shqelm — pra, tĂ« ndryshoje çfarĂ«do parametĂ«r tĂ« makinĂ«s virtuale

Më në fund, kolegët e mi amerikanë e gjetën papritur root cause.

Po, laptopi im më i vjetër është disa herë më i fuqishëm se serveri juaj i prodhimit.

Host-et ndryshonin për nga frekuenca!

  • Zakonisht kjo nuk Ă«shtĂ« problem. Por: kur zhvendoset nga host-i “vendor” nĂ« njĂ« host me “frekuencĂ« tjetĂ«r”, VMware duhet tĂ« korrigjojĂ« rezultatin e GetTimePrecise.
  • Zakonisht kjo nuk Ă«shtĂ« problem, pĂ«rveçse kur haset njĂ« aplikacion qĂ« kĂ«rkon kohĂ« tĂ« saktĂ« miliona herĂ« nĂ« sekondĂ«, si SQL Server.
  • Por as kjo nuk Ă«shtĂ« problem, sepse SQL Server nuk e bĂ«n kĂ«tĂ« gjithmonĂ« (shih PĂ«rfundimin)

Por ka raste kur kjo tĂ« godet fort. Dhe po, duke “i rĂ«nĂ« rrotĂ«s” (duke ndryshuar diçka nĂ« cilĂ«simet e VM), e detyroja VMware ta “rillogarisĂ«â€ konfigurimin dhe frekuenca e host-it aktual bĂ«hej frekuenca “vendore” e makinĂ«s.

Zgjidhja

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

Kur çaktivizon virtualizimin e TSC, leximi i TSC nga brenda makinës virtuale kthen vlerën TSC të makinës fizike, ndërsa shkrimi në TSC nga brenda makinës virtuale nuk ka asnjë efekt. Migrimi i makinës virtuale në një host tjetër, rikthimi i saj nga gjendja e pezulluar ose kthimi në një snapshot bën që TSC të kërcejë në mënyrë jokontinue. Disa sisteme operative guest nuk nisen, ose shfaqin probleme të tjera me matjen e kohës, kur virtualizimi i TSC është i çaktivizuar. Në të kaluarën, kjo veçori është rekomanduar ndonjëherë për të përmirësuar performancën e aplikacioneve që lexojnë shpesh TSC, por performanca e TSC virtual është përmirësuar ndjeshëm në produktet aktuale. Kjo veçori është rekomanduar gjithashtu për përdorim gjatë kryerjes së matjeve që kërkojnë një burim të saktë të kohës reale brenda makinës virtuale.

Shkurt, duhet të shtoni parametrin

monitor_control.virtual_rdtsc = FALSE

Përfundim

Me siguri ju ka lindur pyetja: pse vallë SQL e thërret kaq shpesh GetTimePrecise?

Nuk i kam burimet e SQL Server, por logjika thotĂ« kĂ«tĂ«. SQL Ă«shtĂ« pothuajse si njĂ« sistem operativ me cooperative concurrency, ku çdo thread duhet herĂ« pas here tĂ« "lĂ«shojĂ« radhĂ«n". Dhe ku bĂ«het mĂ« mirĂ« kjo? Atje ku ka pritje natyrale — lock ose I/O. MirĂ«, po nĂ«se po rrotullojmĂ« cikle llogaritĂ«se? AtĂ«herĂ« vendi i dukshĂ«m dhe pothuajse i vetmi Ă«shtĂ« te interpretuesi (nuk Ă«shtĂ« tamam interpretues), pas ekzekutimit tĂ« operatorit tĂ« radhĂ«s.

Zakonisht, SQL Server nuk përdoret për llogaritje të pastra intensive dhe kjo nuk përbën problem. Por ciklet me përdorimin e lloj-lloj tabelave të përkohshme (që menjëherë futen në cache) e kthejnë kodin në një sekuencë operatorësh që ekzekutohen shumë shpejt.

Meqë ra fjala, nëse funksioni mbështillet me NATIVELY COMPILED, ai ndalon së kërkuari kohën dhe shpejtësia e tij rritet rreth 10 herë. Po cooperative multitasking? Pikërisht për kodin natively compiled, SQL-it iu desh të zbatonte PREEMPTIVE MULTITASKING.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster