ใช่ แล็ปท็อปเครื่องเก่าของฉันมีประสิทธิภาพมากกว่าเซิร์ฟเวอร์ที่ใช้งานจริงหลายเท่า

นี่คือคำกล่าวอ้างที่ฉันได้ยินจากนักพัฒนาซอฟต์แวร์ของเรา สิ่งที่น่าสนใจที่สุดคือเรื่องนี้กลายเป็นจริง ทำให้เกิดการสืบสวนที่ยืดเยื้อ เราจะพูดถึงเซิร์ฟเวอร์ SQL ที่ทำงานบน VMware

ใช่ แล็ปท็อปเครื่องเก่าของฉันมีประสิทธิภาพมากกว่าเซิร์ฟเวอร์ที่ใช้งานจริงหลายเท่า

อันที่จริง การรับเซิร์ฟเวอร์ที่ใช้งานจริงโดยไม่ทันตั้งตัวแล็ปท็อปนั้นเป็นเรื่องง่าย เรียกใช้ (ไม่ใช่ใน tempdb และไม่ได้อยู่ในฐานข้อมูลที่เปิดใช้งาน Delayed Durability) รหัส:

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/วินาที 0.065ms /io ไปกลับ
PROD - 360 วินาที 1600 tr/วินาที 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! รถทั้ง "เร็ว" และ "ช้า" มักจะหมุนเข้าหาเจ้าบ้าน!

ตั้งแต่นั้นเป็นต้นมา มีกลิ่นกำมะถันที่เด่นชัดในอากาศ ท้ายที่สุดแล้วปัญหาไม่สามารถระบุได้ว่ามาจากเครื่องเสมือนใด ๆ (เช่นโปรแกรมแก้ไข windows) - ท้ายที่สุดมันกลายเป็นเครื่องที่ "เร็ว" ด้วย vMotion แต่ปัญหาไม่สามารถนำมาประกอบกับโฮสต์ได้ - ท้ายที่สุดอาจมีทั้งเครื่องที่ "เร็ว" และ "ช้า" มันยังไม่เกี่ยวข้องกับการโหลด - ฉันจัดการเพื่อให้ได้เครื่องที่ "ช้า" บนโฮสต์ซึ่งไม่มีอะไรเลยนอกจากนั้น

ด้วยความสิ้นหวัง ฉันเรียกใช้ Process Explorer ของ 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::MakeMiniSOSTthread+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 เท่า (!!!) นี่เป็นชัยชนะเล็ก ๆ น้อย ๆ อยู่แล้ว ไม่ว่าในกรณีใด ไม่มีการติดขัดระหว่างฝ่ายสนับสนุนของ Microsoft และ VMware เพื่อให้พวกเขาสลับลูกศรกัน

จากนั้นความคืบหน้าก็หยุดลง - วันหยุด สิ่งสำคัญ ฮิสทีเรียจากไวรัส และภาระงานที่เพิ่มขึ้นอย่างรวดเร็ว ฉันมักจะพูดถึงปัญหามหัศจรรย์กับเพื่อนร่วมงาน แต่บางครั้งดูเหมือนว่าพวกเขาจะไม่เชื่อฉันด้วยซ้ำ คำพูดที่ว่า VMware ทำให้โค้ดช้าลง 10-20 เท่านั้นเป็นสิ่งที่น่ากลัวเกินไป

ฉันพยายามค้นหาตัวเองว่าอะไรที่ทำให้ช้าลง บางครั้งฉันคิดว่าฉันพบวิธีแก้ปัญหาแล้ว - การเปิดและปิด Hot plugs การเปลี่ยนจำนวนหน่วยความจำหรือจำนวนโปรเซสเซอร์มักทำให้เครื่องกลายเป็น "เครื่องเร็ว" แต่ไม่ตลอดไป แต่สิ่งที่กลายเป็นความจริงก็คือการออกไปเคาะล้อก็เพียงพอแล้วนั่นคือการเปลี่ยนแปลง ใด พารามิเตอร์เครื่องเสมือน

ในที่สุดเพื่อนร่วมงานชาวอเมริกันของฉันก็พบสาเหตุที่แท้จริง

ใช่ แล็ปท็อปเครื่องเก่าของฉันมีประสิทธิภาพมากกว่าเซิร์ฟเวอร์ที่ใช้งานจริงหลายเท่า

เจ้าภาพความถี่ต่างกัน!

  • ตามกฎแล้วมันไม่น่ากลัว แต่: เมื่อย้ายจากโฮสต์ 'ดั้งเดิม' ไปยังโฮสต์ที่มีความถี่ 'ต่างกัน' VMware จะต้องปรับผลลัพธ์ GetTimePrecise
  • ตามกฎแล้ว นี่ไม่ใช่ปัญหา เว้นแต่จะมีแอปพลิเคชันที่ร้องขอเวลาที่แน่นอนหลายล้านครั้งต่อวินาที เช่น SQL Server
  • แต่ก็ไม่น่ากลัวเช่นกันเนื่องจากเซิร์ฟเวอร์ 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 Server จะไม่ใช้สำหรับการประมวลผลแบบ Pure Computing และนี่ไม่ใช่ปัญหา แต่การหมุนเวียนด้วยการทำงานกับตารางชั่วคราวทุกประเภท (ซึ่งจะถูกแคชทันที) ทำให้โค้ดกลายเป็นลำดับของคำสั่งที่ดำเนินการอย่างรวดเร็ว

อย่างไรก็ตาม หากฟังก์ชันถูกรวมไว้ใน NATIVELY COMPILED มันจะหยุดร้องขอเวลาและความเร็วของมันจะเพิ่มขึ้น 10 เท่า แต่การทำงานหลายอย่างแบบร่วมมือกันล่ะ แต่สำหรับโค้ดที่คอมไพล์แล้ว ฉันต้องทำ PREEMPTIVE MULTITASKING ใน SQL

ที่มา: will.com

เพิ่มความคิดเห็น