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

Ini adalah klaim yang saya dengar dari pengembang kami. Yang paling menarik adalah bahwa ini ternyata benar, sehingga menimbulkan penyelidikan yang panjang. Ini akan tentang SQL server, yang berputar di VMware kami.



Sebenarnya, untuk memastikan bahwa server produksi tanpa harapan di belakang laptop itu mudah. Jalankan (bukan pada tempdb dan bukan pada pangkalan 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

Di desktop saya, ini berjalan selama 5 detik, dan pada server produksi - 28 detik. Karena SQL harus menunggu akhir fisik entri log transaksi, dan di sini kita melakukan transaksi yang sangat singkat. Secara kasar, kami mengendarai truk besar yang kuat ke lalu lintas kota, dan kami mengamati bagaimana truk itu terkenal dikalahkan oleh pengantar pizza dengan skuter - throughput tidak penting di sini, hanya latensi yang penting. Dan bukan penyimpanan jaringan tunggal, tidak peduli berapa banyak nol harganya, akan dapat memenangkan latensi terhadap SSD lokal.

(dalam komentar ternyata saya berbohong - saya telah menunda daya tahan di kedua tempat. Tanpa daya tahan yang tertunda ternyata:
Desktop - 39 detik, 15K tr / detik, bolak-balik 0,065ms / io
PROD PROD - 360 detik, 1600 tr / detik, 0,6 ms
saya seharusnya memperhatikan terlalu cepat)


Namun, dalam kasus ini, kita berhadapan dengan nol sepele dari fungsi zeta Riemann dengan contoh sepele. Dalam contoh yang pengembang bawa saya, ada yang lain. Saya menjadi yakin bahwa mereka benar, dan mulai membersihkan dari contoh semua spesifik mereka yang berkaitan dengan logika bisnis. Pada titik tertentu, saya menyadari bahwa saya benar-benar dapat membuang kode mereka, dan menulis sendiri - yang menunjukkan masalah yang sama - berjalan 3-4 kali lebih lambat pada produksi:

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 verifikasi kesederhanaan nomor akan dilakukan 6-7-8 detik. Jadi itu di sejumlah server. Tetapi pada beberapa, cek butuh 25-40 detik. Menariknya, tidak ada server tempat eksekusi akan memakan waktu, katakanlah, 14 detik - kodenya bekerja sangat cepat atau sangat lambat, artinya, masalahnya adalah, katakanlah, hitam dan putih.

Apa yang telah kulakukan? Berguna dalam 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. Itu berbau ilmu hitam semakin banyak.

Setelah keluar di peternakan DEV, saya mulai bermain sebagai server. Ternyata vMotion dari host ke host dapat "menyembuhkan" server, tetapi bisa dan sebaliknya, mengubah server "cepat" menjadi yang "lambat". Sepertinya ini - beberapa host punya masalah ... tapi ... tidak. Beberapa mesin virtual memperlambat host, misalnya, A tetapi bekerja dengan cepat pada host B. Dan mesin virtual lainnya, sebaliknya, bekerja dengan cepat pada A dan melambat pada B! Mobil-mobil "cepat" dan "lambat" sering berputar pada tuan rumah!

Sejak saat itu, udaranya jelas berbau belerang. Bagaimanapun, masalahnya tidak dapat dikaitkan dengan mesin virtual (windows patch, misalnya) - karena itu berubah menjadi "cepat" dengan vMotion. Tetapi masalahnya juga tidak dapat dikaitkan dengan tuan rumah - karena bisa memiliki mesin "cepat" dan "lambat". Itu juga tidak terhubung dengan beban - saya berhasil mendapatkan mesin "lambat" pada host, di mana tidak ada sama sekali selain itu.

Karena putus asa, saya meluncurkan Process Explorer dari Sysinternals dan melihat tumpukan SQL. Pada mesin yang lambat, saluran langsung menarik perhatian saya:

ntoskrnl.exe! KeSynchronizeExecution + 0x5bf6
ntoskrnl.exe! KeWaitForMultipleObjects + 0x109d
ntoskrnl.exe! KeWaitForMultipleObjects + 0xb3f
ntosKrnx 0!
ntoskrnl.exe! KeQuerySystemTimePrecise + 0x881 <- !!!
ntoskrnl.exe! ObDereferenceObjectDeferDelete + 0x28a
ntoskrnl.exe! KeSynchronizeExecution + 0x2de2
sqllang.dll! CDiagThreadSafe :: PxlvlReplace + 0x1a20
... melewatkan
sqldk.dll! SystemThread :: MakeMiniSOSThread + 0xa54
Kernel32.dll! BaseThreadInitThunk + 0x14
ntdll.dll! RtlUserThreadStart + 0x21


Sudah sesuatu. Program ini 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 perlambatan yang lebih cerah - pada mesin "cepat" ia menunjukkan 16-18 juta siklus per detik, sedangkan pada yang lambat itu satu setengah juta, atau bahkan 700 ribu. Artinya, perbedaannya adalah 10-20 kali (!!!). Ini sudah merupakan kemenangan kecil: dalam hal apa pun, tidak ada ancaman macet antara dukungan Microsoft dan VMware sehingga mereka akan mentransfer panah satu sama lain.

Selanjutnya, kemajuan berhenti - liburan, hal-hal penting, histeria virus dan peningkatan tajam dalam beban. Saya sering menyebutkan masalah ajaib kepada kolega saya, tetapi kadang-kadang tampaknya mereka tidak selalu mempercayai saya - pernyataan bahwa VMware memperlambat kode 10-20 kali terlalu mengerikan.

Saya mencoba menggali sendiri apa yang melambat. Kadang-kadang menurut saya saya menemukan solusi - menghidupkan dan mematikan colokan panas, mengubah ukuran memori atau jumlah prosesor sering mengubah mesin menjadi "cepat". Tapi tidak selamanya. Tetapi yang ternyata benar adalah bahwa itu cukup untuk keluar dan mengetuk roda - yaitu, mengubah parameter apa pun dari mesin virtual

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



Host berbeda dalam frekuensinya!
  • Ini biasanya tidak menakutkan. Tetapi: ketika pindah dari host 'asli' ke host dengan frekuensi 'berbeda', VMware harus menyesuaikan hasil GetTimePrecise.
  • Sebagai aturan, ini tidak menakutkan, kecuali ada aplikasi yang meminta waktu yang tepat jutaan kali per detik, seperti server SQL.
  • Tapi ini tidak menakutkan, karena SQL server tidak selalu melakukan ini (lihat Kesimpulannya)

Tetapi ada beberapa kasus ketika rake ini memukul dengan menyakitkan. Namun, ya, dengan mengetuk roda (mengubah sesuatu di pengaturan VM) Saya memaksa VMware untuk 'menceritakan kembali' konfigurasi, dan frekuensi host saat ini menjadi frekuensi 'asli' dari mesin.

Keputusan


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

When you disable virtualization of the TSC, reading the TSC from within the virtual machine returns the physical machine’s TSC value, and writing the TSC from within the virtual machine has no effect. Migrating the virtual machine to another host, resuming it from suspended state, or reverting to a snapshot causes the TSC to jump discontinuously. Some guest operating systems fail to boot, or exhibit other timekeeping problems, when TSC virtualization is disabled. In the past, this feature has sometimes been recommended to improve performance of applications that read the TSC frequently, but performance of the virtual TSC has been improved substantially in current products. The feature has also been recommended for use when performing measurements that require a precise source of real time in the virtual machine.

Singkatnya, tambahkan parameter

monitor_control.virtual_rdtsc = FALSE

Kesimpulan


Anda mungkin memiliki pertanyaan: untuk apa panggilan SQL GetTimePrecise begitu sering?

Saya tidak memiliki sumber server SQL, tetapi logika mengatakan ini. SQL hampir merupakan OS dengan konkurensi kerja sama, di mana setiap utas harus memberi jalan dari waktu ke waktu. Di mana lebih baik melakukannya? Di mana ada harapan alami - kunci atau IO. Nah, bagaimana jika kita memutar siklus komputasi? Kemudian yang jelas dan hampir satu-satunya tempat adalah di penerjemah (ini bukan penerjemah), setelah eksekusi operator berikutnya.

Sebagai aturan, SQL server tidak digunakan untuk memaku perhitungan bersih dan ini bukan masalah. Tetapi siklus dengan bekerja dengan semua jenis tablet sementara (yang segera di-cache) mengubah kode menjadi urutan pernyataan yang sangat cepat dieksekusi.

Ngomong-ngomong, jika Anda membungkus fungsi di NATIVELY COMPILED, maka itu berhenti meminta waktu, dan kecepatannya meningkat dengan faktor 10. Tapi bagaimana dengan kerja sama multitasking? Tetapi untuk kode yang dikompilasi secara asli, saya harus melakukan PREEMPTIVE MULTITASKING dalam SQL.

All Articles