Иә, менің ескі ноутбукім сіздің өндірістік серверіңізден бірнеше есе күшті.

Бұл біздің әзірлеушілерден естіген шағымдар. Ең қызығы, бұл рас болып шығып, ұзақ тергеуге негіз болды. Біз VMware жүйесінде жұмыс істейтін SQL серверлері туралы айтатын боламыз.

Иә, менің ескі ноутбукім сіздің өндірістік серверіңізден бірнеше есе күшті.

Шын мәнінде, өндірістік серверді ноутбуктың артында үмітсіз алу оңай. Кодты іске қосыңыз (temdb емес және кешіктірілген төзімділік қосылған дерекқорда емес):

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.065 мс/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, барлығы жеткілікті болды, сынақ кезінде жылдам және баяу серверлерде бір vCPU-де CPU = 100. Мен Pi санын есептеу үшін сынақтан өттім - сынақ кез келген серверлерде бірдей нәтижелерді көрсетті. Қара магияның иісі барған сайын күшейе түсті.

DEV фермасына шыққаннан кейін мен серверлермен ойнай бастадым. vMotion хосттан хостқа серверді «емдей алады», бірақ ол «жылдам» серверді «баяу» серверге айналдыра алады. Бұл солай сияқты - кейбір хосттарда мәселе бар ... бірақ ... жоқ. Кейбір виртуалды машина хостта баяулады, айталық, А, бірақ В хостында жылдам жұмыс істеді. Ал басқа виртуалды машина, керісінше, А-да жылдам жұмыс істеді және В-де баяулады! «Жылдам» және «баяу» көліктер жиі үй иесіне айналады!

Осы сәттен бастап ауада күкірттің айқын иісі сезілді. Ақыр соңында, мәселені кез келген виртуалды машинаға жатқызуға болмайды (мысалы, терезе патчтары) - бұл vMotion көмегімен «жылдам» болды. Бірақ проблеманы хостқа жатқызуға болмайды - ақыр соңында оның «жылдам» және «баяу» машиналар болуы мүмкін. Бұл сонымен қатар жүктемеге байланысты емес - мен хостқа «баяу» машинаны ала алдым, онда одан басқа ештеңе жоқ.

Шарасыздықтан мен Sysinternals' Process Explorer бағдарламасын іске қосып, SQL стекіне қарадым. Баяу машиналарда сызық бірден көзіме түсті:

ntoskrnl.exe!KeSynchronizeExecution+0x5bf6
ntoskrnl.exe!Бірнеше нысанды күтіңіз+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 есе баяулатты деген мәлімдеме тым қорқынышты болды.

Мен оны не бәсеңдететінін өзім қазып алуға тырыстым. Кейде маған шешім тапқандай көрінетінмін - ыстық штепсельдерді қосу және өшіру, жад көлемін немесе процессорлар санын өзгерту машинаны жиі «жылдамға» айналдырды. Бірақ мәңгі емес. Бірақ шындық болып шыққаны, сыртқа шығып, дөңгелекті қағу жеткілікті, яғни өзгерту кез келген виртуалды машина параметрі

Ақырында, американдық әріптестерім кенеттен түпкі себебін тапты.

Иә, менің ескі ноутбукім сіздің өндірістік серверіңізден бірнеше есе күшті.

Хосттар жиілігі бойынша әр түрлі болды!

  • Әдетте, бұл қорқынышты емес. Бірақ: «жергілікті» хосттан «басқа» жиіліктегі хостқа көшкенде, 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 = ЖАЛҒАН

қорытынды

Сізде сұрақ туындауы мүмкін: SQL неге GetTimePrecise деп жиі шақырады?

Менде SQL серверінің көздері жоқ, бірақ логика мұны айтады. SQL дерлік бірлескен параллельді операциялық жүйе болып табылады, мұнда әрбір ағын мезгіл-мезгіл «жол беруі» керек. Мұны істеу үшін ең жақсы орын қай жерде? Табиғи күту бар жерде - құлыптау немесе IO. Жарайды, бірақ егер біз есептеу циклдерін айналдырсақ ше? Содан кейін анық және дерлік жалғыз орын келесі операторды орындағаннан кейін аудармашыда болады (бұл аудармашы емес).

Әдетте, SQL сервері таза есептеулер үшін пайдаланылмайды және бұл проблема емес. Бірақ уақытша кестелердің барлық түрлерімен жұмыс істейтін циклдар (олар бірден кэштеледі) кодты өте жылдам орындалатын мәлімдемелер тізбегіне айналдырады.

Айтпақшы, егер функция NATIVELY COMPILED ішіне оралған болса, онда ол уақытты сұрауды тоқтатады және оның жылдамдығы 10 есе артады.Бірақ кооперативтік көп тапсырма туралы не деуге болады? Бірақ түпнұсқалық түрде құрастырылған код үшін SQL-де ПРЕКТИВТІК КӨП ТАПСЫРМА жасау керек болды.

Ақпарат көзі: www.habr.com

пікір қалдыру