हो, मेरो पुरानो ल्यापटप तपाईको उत्पादन सर्भर भन्दा धेरै गुणा शक्तिशाली छ।

यी ठीक गुनासोहरू हुन् जुन मैले हाम्रा विकासकर्ताहरूबाट सुनेको छु। सबैभन्दा चाखलाग्दो कुरा यो हो कि यो सत्य साबित भयो, लामो अनुसन्धानलाई जन्म दिदै। हामी VMware मा चल्ने SQL सर्भरहरूको बारेमा कुरा गर्नेछौं।

हो, मेरो पुरानो ल्यापटप तपाईको उत्पादन सर्भर भन्दा धेरै गुणा शक्तिशाली छ।

वास्तवमा, यो सुनिश्चित गर्न सजिलो छ कि उत्पादन सर्भर ल्यापटप पछाडि निराशाजनक छ। कार्यान्वयन गर्नुहोस् (tempdb मा होइन र विलम्बित स्थायित्व सक्षम भएको डाटाबेसमा होइन) कोड:

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 tr/sec, 0.065ms /io roundtrip
PROD - 360 सेकेन्ड, 1600 tr/sec, 0.6ms
मैले याद गरेको हुनुपर्छ कि यो धेरै छिटो थियो)

यद्यपि, यस अवस्थामा हामी एउटा सानो उदाहरणको साथ Riemann zeta प्रकार्यको तुच्छ शून्यसँग व्यवहार गर्दैछौं। विकासकर्ताहरूले मलाई ल्याएको उदाहरणमा, यो फरक थियो। म विश्वस्त भएँ कि तिनीहरू सही थिए, र उदाहरणबाट तिनीहरूका व्यापार तर्कसँग सम्बन्धित सबै विवरणहरू हटाउन थाले। केहि बिन्दुमा मैले महसुस गरें कि म तिनीहरूको कोड पूर्ण रूपमा फाल्न सक्छु र आफ्नै लेख्न सक्छु - जसले समान समस्या देखाउँदछ - उत्पादनमा यो 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, त्यहाँ सबै कुरा पर्याप्त थियो, दुबै छिटो र ढिलो सर्भरहरूमा परीक्षणको क्रममा CPU = 100 एउटा vCPU मा। मैले Pi नम्बर गणना गर्न परीक्षण लिएँ - परीक्षणले कुनै पनि सर्भरमा उही परिणामहरू देखायो। कालो जादूको गन्ध बलियो र बलियो भयो।

एक पटक म DEV फार्ममा पुगेपछि, मैले सर्भरहरूसँग खेल्न थालें। यो बाहिर आयो कि होस्ट देखि होस्ट सम्म vMotion ले सर्भर "उपचार" गर्न सक्छ, तर यसले "छिटो" सर्भरलाई "ढिलो" एकमा पनि बदल्न सक्छ। यो यो हो जस्तो देखिन्छ - केहि होस्टहरूमा समस्या छ... तर... होइन। केही भर्चुअल मेसिन होस्टमा ढिलो थियो, A भन्नुहोस्, तर होस्ट B मा छिटो काम गर्यो। र अर्को भर्चुअल मेसिन, यसको विपरीत, A मा छिटो काम गर्यो र B मा ढिलो भयो! दुबै "छिटो" र "ढिलो" मेसिनहरू प्रायः होस्टमा घुमिरहेका थिए!

त्यस क्षणदेखि, हावामा सल्फरको छुट्टै गन्ध थियो। आखिर, समस्या भर्चुअल मेसिन (उदाहरणका लागि विन्डोज प्याचहरू) मा श्रेय दिन सकिँदैन - आखिर, यो vMotion को साथ "छिटो" मा परिणत भयो। तर समस्या पनि होस्टलाई श्रेय दिन सकिँदैन - सबै पछि, यो दुवै "छिटो" र "ढिलो" मेसिन हुन सक्छ। साथै, यो लोडसँग सम्बन्धित थिएन - मैले होस्टमा "ढिलो" मेसिन प्राप्त गर्न व्यवस्थित गरें, जहाँ यो बाहेक केही पनि थिएन।

निराशाबाट, मैले Sysinternals बाट प्रोसेस एक्सप्लोरर सुरु गरें र SQL स्ट्याक हेरे। ढिलो मेसिनहरूमा लाइनले तुरुन्तै मेरो आँखा समात्यो:

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
... छोडियो
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 पटक (!!!) छ। यो पहिले नै एउटा सानो विजय थियो: कुनै पनि अवस्थामा, माइक्रोसफ्ट र 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 = FALSE

निष्कर्षमा

तपाईसँग सायद एउटा प्रश्न छ: किन SQL ले GetTimePrecise लाई धेरै पटक कल गर्छ?

मसँग SQL सर्भर स्रोत कोड छैन, तर तर्कले यो भन्छ। SQL लगभग एक अपरेटिङ सिस्टम हो जसमा सहकारी संगत हुन्छ, जहाँ प्रत्येक थ्रेडले समय-समयमा "गिभ इन" गर्नुपर्छ। यो गर्न सबैभन्दा राम्रो ठाउँ कहाँ छ? जहाँ प्राकृतिक पर्खाइ छ - लक वा IO। ठीक छ, तर के हुन्छ यदि हामी कम्प्युटेसनल लूपहरू घुमाउँदै छौं? त्यसपछि स्पष्ट र लगभग एक मात्र स्थान दोभाषेमा छ (यो वास्तवमा एक दोभाषे होइन), अर्को कथन कार्यान्वयन पछि।

सामान्यतया, SQL सर्भर शुद्ध कम्प्युटिङ नेलिङको लागि प्रयोग गरिँदैन र यो कुनै समस्या होइन। तर सबै प्रकारका अस्थायी तालिकाहरूसँग काम गर्ने लूपहरूले (जसलाई तुरुन्तै क्यास गरिन्छ) कोडलाई धेरै छिटो कार्यान्वयन गरिएका कथनहरूको अनुक्रममा परिणत गर्दछ।

वैसे, यदि तपाईंले NATIVELY COMPILED मा प्रकार्यलाई र्‍याप गर्नुभयो भने, यसले समयको लागि सोध्न छोड्छ, र यसको गति 10 गुणाले बढ्छ। सहकारी मल्टिटास्किङको बारेमा के हुन्छ? तर नेटिभली कम्पाइल गरिएको कोडको लागि हामीले SQL मा PREEMPTIVE MULTITASKING गर्नु पर्ने थियो।

स्रोत: www.habr.com

एक टिप्पणी थप्न