Ya, laptop lama saya beberapa kali lebih bertenaga daripada server produksi Anda.

Ini adalah klaim yang saya dengar dari pengembang kami. Hal yang paling menarik adalah ternyata hal tersebut benar sehingga menimbulkan penyelidikan yang panjang. Kami akan berbicara tentang server SQL yang berjalan di VMware.

Ya, laptop lama saya beberapa kali lebih bertenaga daripada server produksi Anda.

Sebenarnya, mendapatkan server produksi tanpa harapan di belakang laptop itu mudah. Jalankan (bukan di tempdb dan bukan di database dengan Delayed Durability diaktifkan) kode:

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

Dibutuhkan 5 detik di desktop saya dan 28 detik di server produksi. Karena SQL harus menunggu akhir penulisan fisik ke log transaksi, dan kami melakukan transaksi yang sangat singkat di sini. Secara kasar, kami mengendarai truk besar yang bertenaga ke lalu lintas kota, dan kami menyaksikan bagaimana pengantar pizza dengan skuter terkenal menyalipnya - throughput tidak penting di sini, hanya latensi yang penting. Dan tidak ada satu pun penyimpanan jaringan, tidak peduli berapa banyak nol harganya, akan mampu mengungguli SSD lokal dalam hal latensi.

(di kolom komentar ternyata saya bohong - saya mengalami delay durabilitas di kedua tempat tersebut. Tanpa delay durabilitas ternyata:
Desktop - 39 detik, 15K tr/dtk, 0.065 md/io bolak-balik
PROD - 360 detik, 1600 tr/dtk, 0.6 md
Saya seharusnya memperhatikan bahwa itu terlalu cepat)

Namun, dalam kasus ini kita berurusan dengan nol sepele dari fungsi zeta Riemann dengan contoh sepele. Dalam contoh yang diberikan pengembang kepada saya, itu berbeda. Saya yakin bahwa mereka benar, dan mulai membersihkan semua kekhususan mereka yang terkait dengan logika bisnis dari contoh. Pada titik tertentu, saya menyadari bahwa saya dapat sepenuhnya membuang kode mereka, dan menulis kode saya sendiri - yang menunjukkan masalah yang sama - dalam produksi berjalan 3-4 kali lebih lambat:

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

Jika semuanya baik-baik saja dengan Anda, maka memeriksa kesederhanaan angka akan memakan waktu 6-7-8 detik. Ini telah terjadi di sejumlah server. Tetapi pada beberapa pemeriksaan membutuhkan waktu 25-40 detik. Menariknya, tidak ada server yang eksekusinya memakan waktu, katakanlah, 14 detik - kodenya bekerja sangat cepat atau sangat lambat, yaitu, masalahnya, katakanlah, hitam dan putih.

Apa yang telah kulakukan? Masuk ke metrik VMware. Semuanya baik-baik saja di sana - ada banyak sumber daya, Waktu siap = 0, semuanya cukup, selama pengujian pada server cepat dan lambat CPU = 100 pada satu vCPU. Saya mengikuti tes untuk menghitung jumlah Pi - tes menunjukkan hasil yang sama di server mana pun. Bau ilmu hitam semakin kuat dan kuat.

Setelah keluar dari pertanian DEV, saya mulai bermain dengan server. Ternyata vMotion dari host ke host dapat "menyembuhkan" server, tetapi juga dapat mengubah server "cepat" menjadi "lambat". Sepertinya ini dia - beberapa host memiliki masalah ... tapi ... tidak. Beberapa mesin virtual melambat di host, katakanlah, A, tetapi bekerja dengan cepat di host B. Dan mesin virtual lainnya, sebaliknya, bekerja cepat di A dan melambat di B! Mobil "cepat" dan "lambat" sering berputar di depan!

Sejak saat itu, tercium bau belerang yang khas di udara. Lagi pula, masalahnya tidak dapat dikaitkan dengan mesin virtual apa pun (tambalan windows, misalnya) - lagipula, itu berubah menjadi mesin "cepat" dengan vMotion. Tetapi masalahnya juga tidak dapat dikaitkan dengan host - lagipula, itu bisa memiliki mesin "cepat" dan "lambat". Itu juga tidak terkait dengan beban - saya berhasil mendapatkan mesin "lambat" di host, di mana tidak ada apa-apa selain itu.

Karena putus asa, saya menjalankan Process Explorer Sysinternals dan melihat tumpukan SQL. Pada mesin yang lambat, garis itu langsung menarik perhatian saya:

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

Itu sudah menjadi sesuatu. Program itu ditulis:

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

Program ini menunjukkan pelambatan yang lebih nyata - pada mesin "cepat", ini menunjukkan 16-18 juta siklus per detik, sedangkan pada yang lambat - satu setengah juta, atau bahkan 700 ribu. Artinya, selisihnya 10-20 kali lipat (!!!). Ini sudah merupakan kemenangan kecil: bagaimanapun juga, tidak ada ancaman terjebak antara dukungan Microsoft dan VMware sehingga mereka akan saling bertukar panah.

Kemudian kemajuan terhenti - liburan, hal-hal penting, histeria viral, dan peningkatan tajam dalam beban kerja. Saya sering menyebutkan masalah magis kepada rekan kerja, tetapi kadang-kadang tampaknya mereka bahkan tidak selalu mempercayai saya - pernyataan bahwa VMware memperlambat kode sebanyak 10-20 kali terlalu mengerikan.

Saya mencoba menggali sendiri apa yang memperlambatnya. Kadang-kadang bagi saya sepertinya saya telah menemukan solusi - menyalakan dan mematikan colokan Panas, mengubah jumlah memori atau jumlah prosesor sering mengubah mesin menjadi "cepat". Tapi tidak selamanya. Tapi yang ternyata benar adalah cukup keluar dan mengetuk kemudi - yaitu, berubah apa saja parameter mesin virtual

Akhirnya, rekan Amerika saya tiba-tiba menemukan akar penyebabnya.

Ya, laptop lama saya beberapa kali lebih bertenaga daripada server produksi Anda.

Host berbeda dalam frekuensi!

  • Biasanya, ini tidak menakutkan. Namun: saat berpindah dari host 'asli' ke host dengan frekuensi 'berbeda', VMware harus menyesuaikan hasil GetTimePrecise.
  • Sebagai aturan, ini bukan masalah, kecuali ada aplikasi yang meminta waktu yang tepat jutaan kali per detik, seperti SQL server.
  • Tapi ini juga tidak menakutkan, karena SQL server tidak selalu melakukan ini (lihat Kesimpulan)

Tetapi ada kalanya penggaruk ini sakit. Dan ya, dengan mengetuk roda (dengan mengubah sesuatu di pengaturan VM), saya memaksa VMware untuk 'menghitung ulang' konfigurasi, dan frekuensi host saat ini menjadi frekuensi 'asli' dari mesin.

keputusan

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

Saat Anda menonaktifkan virtualisasi TSC, membaca TSC dari dalam mesin virtual mengembalikan nilai TSC mesin fisik, dan menulis TSC dari dalam mesin virtual tidak berpengaruh. Memindahkan mesin virtual ke host lain, melanjutkannya dari status ditangguhkan, atau mengembalikan ke snapshot menyebabkan TSC melompat secara terputus-putus. Beberapa sistem operasi tamu gagal melakukan booting, atau menunjukkan masalah ketepatan waktu lainnya, saat virtualisasi TSC dinonaktifkan. Sebelumnya, fitur ini terkadang direkomendasikan untuk meningkatkan performa aplikasi yang sering membaca TSC, tetapi kinerja TSC virtual telah ditingkatkan secara substansial dalam produk saat ini. Fitur ini juga telah direkomendasikan untuk digunakan saat melakukan pengukuran yang memerlukan sumber waktu nyata yang akurat di mesin virtual.

Singkatnya, Anda perlu menambahkan parameter

monitor_control.virtual_rdtsc = SALAH

Kesimpulan

Anda mungkin memiliki pertanyaan: mengapa SQL sering memanggil GetTimePrecise?

Saya tidak memiliki sumber server SQL, tetapi logikanya mengatakan ini. SQL hampir merupakan sistem operasi dengan konkurensi kooperatif, di mana setiap utas harus "memberi jalan" dari waktu ke waktu. Di mana tempat terbaik untuk melakukannya? Di mana ada ekspektasi alami - kunci atau IO. Oke, tapi bagaimana jika kita memutar siklus komputasi? Kemudian tempat yang jelas dan hampir satu-satunya adalah di juru bahasa (ini bukan juru bahasa), setelah eksekusi operator berikutnya.

Biasanya, server SQL tidak digunakan untuk komputasi murni dan ini bukan masalah. Tetapi siklus dengan bekerja dengan semua jenis tabel sementara (yang langsung di-cache) mengubah kode menjadi urutan pernyataan yang dieksekusi dengan sangat cepat.

Omong-omong, jika fungsi dibungkus dengan NATIVELY COMPILED, maka ia berhenti meminta waktu, dan kecepatannya meningkat 10 kali lipat.Tapi bagaimana dengan multitasking kooperatif? Tetapi untuk kode yang dikompilasi secara asli, saya harus melakukan PREEMPTIVE MULTITASKING dalam SQL.

Sumber: www.habr.com

Tambah komentar