Evet, eski dizüstü bilgisayarım sizin üretim sunucunuzdan birkaç kat daha güçlü.

Geliştiricilerimizden duyduğum iddialar bunlar. En ilginç olanı ise bunun doğru çıkması uzun bir soruşturmaya yol açtı. VMware üzerinde çalışan SQL sunucularından bahsedeceğiz.

Evet, eski dizüstü bilgisayarım sizin üretim sunucunuzdan birkaç kat daha güçlü.

Aslında, üretim sunucusunu umutsuzca dizüstü bilgisayarın arkasına almak kolaydır. Şu kodu çalıştırın (tempdb'de ve Gecikmeli Dayanıklılığın etkin olduğu bir veritabanında değil):

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

Masaüstümde 5 saniye ve üretim sunucusunda 28 saniye sürüyor. Çünkü SQL, işlem günlüğüne yazmanın fiziksel olarak bitmesini beklemek zorunda ve burada çok kısa işlemler yapıyoruz. Kabaca konuşursak, büyük ve güçlü bir kamyonu şehir trafiğine sürdük ve scooter kullanan pizza dağıtımcılarının onu nasıl meşhur bir şekilde geride bıraktığını izliyoruz - burada verimlilik önemli değil, yalnızca gecikme önemlidir. Ve fiyatında kaç tane sıfır olursa olsun, tek bir ağ depolaması gecikme açısından yerel bir SSD'den daha iyi performans gösteremez.

(yorumlarda yalan söylediğim ortaya çıktı - her iki yerde de dayanıklılığı geciktirdim. Dayanıklılığı geciktirmeden şu çıkıyor:
Masaüstü - 39 saniye, 15K tr/sn, 0.065ms /io gidiş dönüş
PROD - 360 saniye, 1600 tr/sn, 0.6 ms
Çok hızlı olduğunu fark etmeliydim)

Bununla birlikte, bu durumda önemsiz bir örnekle Riemann zeta fonksiyonunun önemsiz sıfırlarıyla uğraşıyoruz. Geliştiricilerin bana getirdiği örnekte durum farklıydı. Haklı olduklarına ikna oldum ve iş mantığıyla ilgili tüm ayrıntılarını örnekten temizlemeye başladım. Bir noktada, kodlarını tamamen atabileceğimi ve kendi kodumu yazabileceğimi fark ettim - ki bu aynı sorunu gösteriyor - üretimde 3-4 kat daha yavaş çalışıyor:

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

Sizin için her şey yolundaysa, bir sayının basitliğini kontrol etmek 6-7-8 saniye sürecektir. Bu, birkaç sunucuda oldu. Ancak bazılarında kontrol 25-40 saniye sürdü. İlginç bir şekilde, yürütmenin örneğin 14 saniye sürebileceği hiçbir sunucu yoktu - kod ya çok hızlı ya da çok yavaş çalıştı, yani sorun, diyelim ki siyah beyazdı.

Ne yaptım? VMware ölçümlerine girdim. Orada her şey yolundaydı - çok sayıda kaynak vardı, Hazır olma süresi = 0, hem hızlı hem de yavaş sunucularda test sırasında her şey yeterliydi CPU = bir vCPU'da 100. Pi sayısını hesaplamak için bir test yaptım - test tüm sunucularda aynı sonuçları gösterdi. Kara büyü kokusu gittikçe güçlendi.

DEV çiftliğine çıktıktan sonra sunucularla oynamaya başladım. Ana bilgisayardan ana bilgisayara vMotion'ın bir sunucuyu "iyileştirebileceği", ancak aynı zamanda "hızlı" bir sunucuyu "yavaş" bir sunucuya dönüştürebileceği ortaya çıktı. Görünüşe göre bu - bazı ev sahiplerinin bir sorunu var ... ama ... hayır. Bazı sanal makineler, örneğin A ana bilgisayarında yavaşladı, ancak B ana bilgisayarında hızlı çalıştı. Ve diğer sanal makine, aksine, A'da hızlı çalıştı ve B'de yavaşladı! Hem "hızlı" hem de "yavaş" arabalar genellikle ana bilgisayarda dönüyordu!

O andan itibaren havada belirgin bir kükürt kokusu vardı. Ne de olsa sorun herhangi bir sanal makineye (örneğin Windows yamaları) atfedilemezdi - sonuçta vMotion ile "hızlı" bir makineye dönüştü. Ancak sorun, ana bilgisayara da atfedilemez - sonuçta hem "hızlı" hem de "yavaş" makinelere sahip olabilir. Ayrıca, yükle ilgili değildi - Ana bilgisayarda, onun dışında hiçbir şeyin olmadığı "yavaş" bir makine almayı başardım.

Çaresizlikten Sysinternals'ın İşlem Gezgini'ni çalıştırdım ve SQL yığınına baktım. Yavaş makinelerde, satır hemen gözüme çarptı:

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
… atlandı
sqldk.dll!SystemThread::MakeMiniSOSTthread+0xa54
KERNEL32.DLL! BaseThreadInitThunk + 0x14
ntdll.dll! RtlUserThreadStart + 0x21

Zaten bir şeydi. Program yazıldı:

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

Bu program daha da belirgin bir yavaşlama gösterdi - "hızlı" makinelerde saniyede 16-18 milyon döngü gösterirken, yavaş makinelerde - bir buçuk milyon, hatta 700 bin. Yani fark 10-20 kattır (!!!). Bu zaten küçük bir zaferdi: Her halükarda, Microsoft ve VMware desteği arasında sıkışıp kalma tehdidi yoktu, böylece okları birbirlerine çevireceklerdi.

Sonra ilerleme durdu - tatil, önemli şeyler, viral histeri ve iş yükünde keskin bir artış. Sık sık meslektaşlarıma büyülü sorundan bahsettim, ancak bazen bana her zaman inanmıyor gibiydiler - VMware'in kodu 10-20 kat yavaşlattığı ifadesi çok canavarcaydı.

Onu neyin yavaşlattığını kendim bulmaya çalıştım. Bazen bana bir çözüm bulmuşum gibi geldi - Çalışır durumda fişleri açıp kapatmak, bellek miktarını veya işlemci sayısını değiştirmek genellikle makineyi "hızlı" hale getirdi. Ama sonsuza kadar değil. Ama doğru olduğu ortaya çıktı ki, dışarı çıkıp direksiyona vurmak - yani değişmek için yeterli. herhangi sanal makine parametresi

Sonunda, Amerikalı meslektaşlarım aniden bir kök neden buldular.

Evet, eski dizüstü bilgisayarım sizin üretim sunucunuzdan birkaç kat daha güçlü.

Ana bilgisayarların sıklığı farklıydı!

  • Kural olarak, bu korkutucu değil. Ancak: "yerel" bir ana bilgisayardan "farklı" bir frekansa sahip bir ana bilgisayara geçerken, VMware GetTimePrecise sonucunu ayarlamalıdır.
  • Kural olarak, SQL sunucusu gibi saniyede milyonlarca kez tam zamanı isteyen bir uygulama olmadığı sürece bu bir sorun değildir.
  • Ancak bu da korkutucu değil çünkü SQL sunucusu bunu her zaman yapmıyor (Sonuca bakın)

Ancak bu tırmığın acıttığı durumlar vardır. Ve evet, direksiyona vurarak (VM ayarlarında bir şeyi değiştirerek), VMware'i yapılandırmayı 'yeniden hesaplamaya' zorladım ve mevcut ana bilgisayarın frekansı, makinenin 'yerel' frekansı oldu.

karar

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

TSC'nin sanallaştırılmasını devre dışı bıraktığınızda, TSC'yi sanal makinenin içinden okumak, fiziksel makinenin TSC değerini döndürür ve TSC'yi sanal makinenin içinden yazmanın hiçbir etkisi olmaz. Sanal makineyi başka bir ana bilgisayara geçirmek, askıya alma durumundan devam ettirmek veya bir anlık görüntüye geri döndürmek, TSC'nin kesintili bir şekilde atlamasına neden olur. Bazı konuk işletim sistemleri, TSC sanallaştırması devre dışı bırakıldığında önyükleme yapamaz veya başka zaman tutma sorunları sergiler. Geçmişte, bu özellik bazen TSC'yi sık sık okuyan uygulamaların performansını artırmak için önerildi., ancak sanal TSC'nin performansı mevcut ürünlerde önemli ölçüde iyileştirildi. Bu özelliğin, sanal makinede kesin bir gerçek zamanlı kaynak gerektiren ölçümler gerçekleştirirken kullanılması da tavsiye edilmiştir.

Kısacası, parametreyi eklemeniz gerekir.

monitor_control.virtual_rdtsc = YANLIŞ

Sonuç

Muhtemelen bir sorunuz var: SQL neden GetTimePrecise'i bu kadar sık ​​çağırsın?

SQL sunucu kaynaklarına sahip değilim, ancak mantık bunu söylüyor. SQL, neredeyse işbirlikçi eşzamanlılığa sahip bir işletim sistemidir ve her iş parçacığının zaman zaman "yol vermesi" gerekir. Bunu yapmak için en iyi yer neresidir? Doğal bir beklentinin olduğu yerde - kilitleme veya IO. Tamam, ama ya hesaplama döngülerini döndürüyorsak? O zaman bariz ve neredeyse tek yer, bir sonraki operatörün yürütülmesinden sonra tercümandadır (bu tam olarak bir tercüman değildir).

Kural olarak, SQL sunucusu saf bilgi işlem için kullanılmaz ve bu bir sorun değildir. Ancak (hemen önbelleğe alınan) her türlü geçici tabloyla çalışan döngüler, kodu çok hızlı yürütülen ifadeler dizisine dönüştürür.

Bu arada, işlev NATIVELY COMPILED'e sarılırsa, zaman istemeyi bırakır ve hızı 10 kat artar.Peki ya işbirlikçi çoklu görev? Ancak yerel olarak derlenmiş kod için SQL'de PREEMPTIVE MULTITASKING yapmak zorunda kaldım.

Kaynak: habr.com

Yorum ekle