Да, мој стари лаптоп је неколико пута моћнији од вашег производног сервера

Управо су то жалбе које сам чуо од наших програмера. Најинтересантније је да се то показало као тачно, што је довело до дуге истраге. Говорићемо о СКЛ серверима који раде на ВМваре-у.

Да, мој стари лаптоп је неколико пута моћнији од вашег производног сервера

У ствари, лако је осигурати да производни сервер безнадежно стоји иза лаптопа. Извршите (не на темпдб и не у бази података са омогућеном одложеном издржљивошћу) код:

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 секунди. Зато што СКЛ мора да сачека физички крај уноса у евиденцију трансакција, а ми овде радимо веома кратке трансакције. Грубо говорећи, убацили смо велики, снажан камион у градски саобраћај, и гледали како га дрско престижу достављачи пице на скутерима - овде није важна пропусност, важна је само латенција. И ниједно мрежно складиште, без обзира на то колико нула има у његовој цени, не може победити локални ССД у смислу кашњења.

(у коментарима се испоставило да сам лагао - имао сам одложену издржљивост на оба места. Без одложене издржљивости испада:
Десктоп - 39 секунди, 15К тр/сец, 0.065мс/ио повратно
ПРОД - 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 секунди – код је радио или веома брзо или веома споро, односно проблем је био, рецимо, црно-бели.

Шта сам урадио? Коришћене ВМваре метрике. Тамо је све било у реду - ресурса је било на претек, Време спремности = 0, било је довољно свега, током теста и на брзим и на спорим серверима ЦПУ = 100 на једном вЦПУ-у. Урадио сам тест да израчунам број Пи - тест је показао исте резултате на било ком серверу. Мирис црне магије постајао је све јачи и јачи.

Када сам стигао до ДЕВ фарме, почео сам да се играм са серверима. Испоставило се да вМотион од хоста до хоста може да „излечи” сервер, али такође може да претвори „брзи” сервер у „спор”. Чини се да је то то - неки домаћини имају проблем... али... не. Нека виртуелна машина је била спора на хосту, рецимо А, али је брзо радила на хосту Б. А друга виртуелна машина је, напротив, радила брзо на А и успоравала на Б! И „брзе“ и „споре“ машине су се често вртеле на хосту!

Од тог тренутка у ваздуху се осећао изразит мирис сумпора. На крају крајева, проблем се не може приписати виртуелној машини (на пример, закрпе за Виндовс) - на крају крајева, он се претворио у „брзо“ са вМотион-ом. Али проблем се такође не може приписати хосту - на крају крајева, могао би да има и „брзе“ и „споре“ машине. Такође, ово није било повезано са оптерећењем - успео сам да набавим „спору“ машину на хосту, где осим ње није било ничега.

Из очаја, покренуо сам Процесс Екплорер из Сисинтерналс-а и погледао СКЛ стек. На спорим машинама линија ми је одмах упала у очи:

нтоскрнл.еке!КеСинцхронизеЕкецутион+0к5бф6
нтоскрнл.еке!КеВаитФорМултиплеОбјецтс+0к109д
нтоскрнл.еке!КеВаитФорМултиплеОбјецтс+0кб3ф
нтоскрнл.еке!КеВаитФорСинглеОбјецт+0к377
нтоскрнл.еке!КеКуериСистемТимеПрецисе+0к881 < — !!!
нтоскрнл.еке!ОбДереференцеОбјецтДеферДелете+0к28а
нтоскрнл.еке!КеСинцхронизеЕкецутион+0к2де2
склланг.длл!ЦДиагТхреадСафе::ПклвлРеплаце+0к1а20
... прескочио
склдк.длл!СистемТхреад::МакеМиниСОСТхреад+0ка54
КЕРНЕЛ32.ДЛЛ!БасеТхреадИнитТхунк+0к14
нтдлл.длл!РтлУсерТхреадСтарт+0к21

Ово је већ било нешто. Програм је написан:

    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 пута (!!!). Ово је већ била мала победа: у сваком случају, није било претње да се заглави између подршке Мицрософт-а и ВМваре-а да би окренули стрелице једни на друге.

Тада је напредак стао - одмори, важне ствари, вирусна хистерија и нагло повећање оптерећења. Често сам помињао магични проблем својим колегама, али понекад се чинило да ми ни не верују увек - изјава да ВМваре успорава код 10-20 пута била је превише монструозна.

Покушао сам да откријем шта ме успорава. Понекад ми се чинило да сам пронашао решење - укључивање и искључивање Хот плуг-ова, промена количине меморије или броја процесора често претварају машину у „брзу“. Али не заувек. Али оно што се показало тачним јесте да је довољно изаћи и покуцати на точак – односно променити се било који параметар виртуелне машине

Коначно, моје америчке колеге су изненада пронашле основни узрок.

Да, мој стари лаптоп је неколико пута моћнији од вашег производног сервера

Домаћини су се разликовали по учесталости!

  • По правилу, ово није велика ствар. Али: када прелазите са 'природног' хоста на хост са 'другачијом' фреквенцијом, ВМваре мора да прилагоди резултат ГетТимеПрецисе.
  • По правилу, то није проблем, осим ако не постоји апликација која захтева тачно време милионе пута у секунди, као што је СКЛ сервер.
  • Али ово није страшно, пошто СКЛ сервер то не ради увек (погледајте Закључак)

Али постоје случајеви када ова грабуља снажно удари. Па ипак, да, тапкањем на точкић (променом нечега у подешавањима ВМ-а) натерао сам ВМваре да 'поново израчуна' конфигурацију, а фреквенција тренутног хоста је постала 'природна' фреквенција машине.

одлука

ввв.вмваре.цом/филес/пдф/тецхпапер/Тимекеепинг-Ин-ВиртуалМацхинес.пдф

Када онемогућите виртуелизацију ТСЦ-а, читање ТСЦ-а из виртуелне машине враћа ТСЦ вредност физичке машине, а писање ТСЦ-а из виртуелне машине нема ефекта. Миграција виртуелне машине на други хост, њено враћање из суспендованог стања или враћање на снимак доводи до тога да ТСЦ скаче непрекидно. Неки оперативни системи за госте не успевају да се покрену или показују друге проблеме са мерењем времена када је ТСЦ виртуелизација онемогућена. У прошлости се ова функција понекад препоручивала за побољшање перформанси апликација које често читају ТСЦ, али перформансе виртуелног ТСЦ-а су значајно побољшане у тренутним производима. Ова функција је такође препоручена за употребу приликом извођења мерења која захтевају прецизан извор реалног времена у виртуелној машини.

Укратко, потребно је да додате параметар

монитор_цонтрол.виртуал_рдтсц = ФАЛСЕ

Закључак

Вероватно имате питање: зашто СКЛ тако често позива ГетТимеПрецисе?

Немам изворни код СКЛ сервера, али логика каже ово. СКЛ је скоро оперативни систем са кооперативном конкурентношћу, где свака нит мора с времена на време „попустити“. Где је најбоље то урадити? Где постоји природно чекање - закључавање или ИО. У реду, али шта ако вртимо рачунске петље? Тада је очигледно и скоро једино место у тумачу (ово заправо није тумач), након извршења следеће изјаве.

Генерално, СКЛ сервер се не користи за чисто рачунарство и то није проблем. Али петље које раде са свим врстама привремених табела (које се одмах кеширају) претварају код у низ врло брзо извршених изјава.

Иначе, ако умотате функцију у НАТИВЕЛИ ЦОМПИЛЕД, онда она престаје да тражи време, а брзина јој се повећава за 10 пута Шта је са кооперативним мултитаскингом? Али за изворно преведен код морали смо да урадимо ПРЕВЕНТИВНО МУЛТИТАСКИНГ у СКЛ-у.

Извор: ввв.хабр.цом

Додај коментар