Այո, իմ հին նոութբուքը մի քանի անգամ ավելի հզոր է, քան ձեր արտադրական սերվերը:

Սրանք այն պնդումներն են, որոնք ես լսել եմ մեր ծրագրավորողներից: Ամենահետաքրքիրն այն է, որ պարզվեց, որ դա ճիշտ է, ինչը երկարատև հետաքննության տեղիք տվեց։ Մենք կխոսենք SQL սերվերների մասին, որոնք աշխատում են VMware-ով։

Այո, իմ հին նոութբուքը մի քանի անգամ ավելի հզոր է, քան ձեր արտադրական սերվերը:

Իրականում, նոութբուքի հետևում արտադրական սերվերը անհուսալիորեն ստանալը հեշտ է: Գործարկեք (ոչ tempdb-ում և ոչ տվյալների բազայում, որի հետաձգված երկարակեցությունը միացված է) կոդը.

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

Իմ աշխատասեղանի վրա այն տևում է 5 վայրկյան, իսկ արտադրության սերվերում՝ 28 վայրկյան: Քանի որ SQL-ը պետք է սպասի գործարքների մատյանում գրելու ֆիզիկական ավարտին, և մենք այստեղ շատ կարճ գործարքներ ենք կատարում: Կոպիտ ասած, մենք մեծ հզոր բեռնատարով մեքենա ենք վարել քաղաքային երթևեկության մեջ, և մենք հետևում ենք, թե ինչպես են սկուտերներով պիցցա առաքողները հայտնիորեն շրջանցում այն. այստեղ թողունակությունը կարևոր չէ, կարևոր է միայն ուշացումը: Եվ ոչ մի ցանցային պահեստ, անկախ նրանից, թե որքան զրո կա դրա գնի մեջ, չի կարողանա գերազանցել տեղական SSD-ին ուշացման առումով:

(մեկնաբանություններում պարզվեց, որ ես ստել եմ - երկու տեղն էլ հետաձգել էի ամրությունը։ Առանց ուշացած դիմացկունության ստացվում է.
Աշխատասեղան – 39 վայրկյան, 15K տրր/վրկ, 0.065ms/io հետադարձ ճանապարհ
PROD - 360 վայրկյան, 1600 տրր/վրկ, 0.6 մս
Ես պետք է նկատեի, որ դա շատ արագ է)

Սակայն այս դեպքում մենք գործ ունենք Ռիմանի զետա ֆունկցիայի տրիվիալ զրոների հետ՝ չնչին օրինակով։ Այն օրինակում, որը մշակողները բերեցին ինձ, դա այլ էր. Ես համոզվեցի, որ նրանք ճիշտ են, և սկսեցի օրինակից մաքրել բիզնես տրամաբանության հետ կապված իրենց բոլոր առանձնահատկությունները։ Ինչ-որ պահի ես հասկացա, որ կարող եմ ամբողջովին դեն նետել նրանց ծածկագիրը և գրել իմ սեփականը, ինչը ցույց է տալիս նույն խնդիրը, արտադրության մեջ այն աշխատում է 3-4 անգամ ավելի դանդաղ.

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

Եթե ​​ձեզ մոտ ամեն ինչ կարգին է, ապա թվի պարզության ստուգումը կտևի 6-7-8 վայրկյան: Սա տեղի է ունեցել մի շարք սերվերների վրա: Բայց որոշների դեպքում ստուգումը տևեց 25-40 վայրկյան: Հետաքրքիրն այն է, որ չկային սերվերներ, որտեղ կատարումը տևեր, ասենք, 14 վայրկյան՝ կոդը կամ շատ արագ էր աշխատում, կամ շատ դանդաղ, այսինքն՝ խնդիրը, ասենք, սև ու սպիտակն էր։

Ի՞նչ եմ ես արել: Մտածեք VMware չափումների մեջ: Այնտեղ ամեն ինչ լավ էր. շատ ռեսուրսներ կային, պատրաստի ժամանակ = 0, ամեն ինչ բավական էր, թեստի ժամանակ թե՛ արագ, թե՛ դանդաղ սերվերների վրա CPU = 100 մեկ vCPU-ի վրա: Ես փորձարկեցի Pi-ի քանակը հաշվարկելու համար - թեստը ցույց տվեց նույն արդյունքները ցանկացած սերվերի վրա: Սև մոգության հոտը գնալով ուժեղանում էր:

Դուրս գալով DEV ֆերմայում, ես սկսեցի խաղալ սերվերների հետ: Պարզվեց, որ vMotion-ը հոսթից հոսթ կարող է «բուժել» սերվերը, բայց կարող է նաև «արագ» սերվերը վերածել «դանդաղ» սերվերի։ Թվում է, թե սա է, որոշ հաղորդավարներ խնդիր ունեն ... բայց ... ոչ: Որոշ վիրտուալ մեքենա դանդաղեցրեց հոսթի արագությունը, ասենք, A-ում, բայց արագ աշխատեց հոսթի B-ի վրա: Իսկ մյուս վիրտուալ մեքենան, ընդհակառակը, արագ աշխատեց A-ի վրա և դանդաղեցրեց արագությունը B-ի վրա: Թե՛ «արագ» և թե՛ «դանդաղ» մեքենաները հաճախ պտտվում էին տանտիրոջ վրա։

Այդ պահից օդում ծծմբի հստակ հոտ կար։ Ի վերջո, խնդիրը չէր կարող վերագրվել որևէ վիրտուալ մեքենայի (օրինակ, պատուհանների կարկատաններ) - ի վերջո, այն վերածվեց «արագի» vMotion-ի հետ: Բայց խնդիրը նույնպես չէր կարելի վերագրել հյուրընկալողին. ի վերջո, այն կարող էր ունենալ և՛ «արագ», և՛ «դանդաղ» մեքենաներ: Դա նույնպես կապված չէր ծանրաբեռնվածության հետ. ես կարողացա «դանդաղ» մեքենա ստանալ հյուրընկալողի վրա, որտեղ դրանից բացի ընդհանրապես ոչինչ չկար:

Հուսահատությունից ես գործարկեցի Sysinternals-ի Process Explorer-ը և նայեցի SQL փաթեթին: Դանդաղ մեքենաների վրա գիծն անմիջապես գրավեց իմ աչքը.

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
… բաց թողնվեց
sqldk.dll!SystemThread::MakeMiniSOSThread+0xa54
KERNEL32.DLL!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

Դա արդեն ինչ-որ բան էր։ Ծրագիրը գրված էր.

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

Այս ծրագիրը ցույց տվեց ավելի ընդգծված դանդաղում. «արագ» մեքենաների վրա այն ցույց է տալիս վայրկյանում 16-18 միլիոն ցիկլ, մինչդեռ դանդաղների վրա՝ մեկուկես միլիոն, կամ նույնիսկ 700 հազար: Այսինքն՝ տարբերությունը 10-20 անգամ է (!!!): Սա արդեն փոքր հաղթանակ էր. ամեն դեպքում Microsoft-ի և VMware-ի աջակցության միջև խրվելու վտանգ չկար, որպեսզի նրանք սլաքները փոխեին միմյանց վրա։

Հետո առաջընթացը դադարեց՝ արձակուրդ, կարևոր բաներ, վիրուսային հիստերիա և ծանրաբեռնվածության կտրուկ աճ։ Ես հաճախ նշում էի կախարդական խնդիրը գործընկերներին, բայց երբեմն թվում էր, որ նրանք նույնիսկ միշտ չէին հավատում ինձ. այն հայտարարությունը, որ VMware-ը դանդաղեցրել է կոդը 10-20 անգամ, չափազանց հրեշավոր էր:

Ես ինքս փորձեցի պեղել, թե ինչն է դա դանդաղեցնում: Երբեմն ինձ թվում էր, թե ես լուծում եմ գտել. Hot plug-ները միացնելն ու անջատելը, հիշողության ծավալը կամ պրոցեսորների քանակը փոխելը հաճախ սարքը դարձնում էին «արագ»: Բայց ոչ ընդմիշտ: Բայց այն, ինչ ճշմարիտ է պարզվել, այն է, որ բավական է դուրս գալ և ղեկը թակել, այսինքն՝ փոխել. որեւէ վիրտուալ մեքենայի պարամետր

Վերջապես, իմ ամերիկացի գործընկերները հանկարծ գտան հիմնական պատճառը:

Այո, իմ հին նոութբուքը մի քանի անգամ ավելի հզոր է, քան ձեր արտադրական սերվերը:

Հաղորդավարները տարբերվում էին հաճախականությամբ:

  • Որպես կանոն, սա սարսափելի չէ։ Բայց երբ «բնական» հոսթից տեղափոխվում է «տարբեր» հաճախականությամբ հոսթ, VMware-ը պետք է կարգավորի GetTimePrecise արդյունքը:
  • Որպես կանոն, դա խնդիր չէ, եթե չկա ծրագիր, որը վայրկյանում միլիոնավոր անգամներ է պահանջում ճշգրիտ ժամանակը, ինչպես SQL սերվերը։
  • Բայց սա նույնպես սարսափելի չէ, քանի որ SQL սերվերը միշտ չէ, որ դա անում է (տես Եզրակացություն)

Բայց լինում են դեպքեր, երբ այս փոցխը ցավում է։ Եվ այո, անիվի վրա թակելով (VM-ի կարգավորումներում ինչ-որ բան փոխելով) ես ստիպեցի VMware-ին «վերահաշվարկել» կոնֆիգուրացիան, և ընթացիկ հոսթի հաճախականությունը դարձավ մեքենայի «հայրենի» հաճախականությունը:

որոշում

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

Երբ անջատում եք TSC-ի վիրտուալացումը, TSC-ը վիրտուալ մեքենայից կարդալը վերադարձնում է ֆիզիկական մեքենայի TSC արժեքը, և վիրտուալ մեքենայի ներսից TSC գրելը ոչ մի ազդեցություն չունի: Վիրտուալ մեքենան այլ հոսթ տեղափոխելը, այն կասեցված վիճակից վերականգնելը կամ լուսանկարին վերադառնալը հանգեցնում է նրան, որ TSC-ն անընդհատ ցատկում է: Որոշ հյուր օպերացիոն համակարգեր չեն կարողանում բեռնել կամ ցուցադրում են ժամանակաչափման այլ խնդիրներ, երբ TSC վիրտուալացումն անջատված է: Նախկինում այս հատկությունը երբեմն առաջարկվել է բարելավելու այն հավելվածների աշխատանքը, որոնք հաճախակի կարդում են TSC, սակայն վիրտուալ TSC-ի կատարումը էապես բարելավվել է ընթացիկ արտադրանքներում: Հատկանիշը նաև առաջարկվել է օգտագործել վիրտուալ մեքենայում իրական ժամանակի ճշգրիտ աղբյուր պահանջող չափումներ կատարելիս:

Մի խոսքով, դուք պետք է ավելացնեք պարամետրը

monitor_control.virtual_rdtsc = FALSE

Ամփոփում

Դուք հավանաբար հարց ունեք. ինչու՞ է SQL-ն այդքան հաճախ զանգում GetTimePrecise-ին:

Ես չունեմ SQL սերվերի աղբյուրներ, բայց տրամաբանությունն ասում է սա. SQL-ը գրեթե կոոպերատիվ համաժամանակյա օպերացիոն համակարգ է, որտեղ յուրաքանչյուր շարանը պետք է ժամանակ առ ժամանակ «զիջի»: Որտեղ է դա անելու լավագույն վայրը: Որտեղ կա բնական ակնկալիք - կողպեք կամ IO: Լավ, բայց ի՞նչ, եթե մենք պտտում ենք հաշվողական ցիկլեր: Այնուհետև ակնհայտ և գրեթե միակ տեղը թարգմանիչն է (սա այնքան էլ թարգմանիչ չէ), հաջորդ օպերատորի կատարումից հետո:

Որպես կանոն, SQL սերվերը չի օգտագործվում մաքուր հաշվարկների համար, և դա խնդիր չէ: Բայց բոլոր տեսակի ժամանակավոր աղյուսակների հետ աշխատանքի ցիկլերը (որոնք անմիջապես պահվում են քեշում) կոդը վերածում են շատ արագ կատարվող հայտարարությունների հաջորդականության:

Ի դեպ, եթե ֆունկցիան փաթաթված է NATIVELY COMPILED-ով, ապա այն դադարում է ժամանակ պահանջել, և դրա արագությունը մեծանում է 10 անգամ: Բայց ինչ վերաբերում է կոոպերատիվ բազմախնդրությանը: Բայց բնիկ կերպով կազմված կոդի համար ես պետք է կատարեի PREEMPTIVE MULTITASKING SQL-ում:

Source: www.habr.com

Добавить комментарий