ซอฟต์แวร์ที่ทำงานได้ดีไม่เหมือนกับซอฟต์แวร์ที่ทำงานได้ดีภายใต้ภาระงาน ฟีเจอร์หนึ่งอาจผ่านการทดสอบฟังก์ชันทั้งหมด ถูกจัดส่งได้อย่างสะอาดตา แต่แล้วกลับล้มเหลวในครั้งแรกที่มีการใช้งานจริงเข้ามา การทดสอบประสิทธิภาพคือระเบียบวินัยที่เชื่อมช่องว่างนั้น: มันวัดว่าระบบทำงานอย่างไรเมื่อมีการใช้งาน ไม่ใช่แค่ว่ามันถูกต้องเมื่อไม่ได้ใช้งาน
คู่มือนี้จะอธิบายว่าการทดสอบประสิทธิภาพคืออะไร ประเภทหลักๆ มีอะไรบ้าง เมตริกที่ใช้นิยามผลลัพธ์ และวิธีการที่มันเข้ากับการกระบวนการทดสอบสมัยใหม่
การทดสอบประสิทธิภาพคืออะไร
การทดสอบประสิทธิภาพจะประเมินความเร็ว ความเสถียร และความสามารถในการปรับขนาดของระบบภายใต้ภาระงานที่กำหนดไว้ มันไม่ได้ถามว่า “ฟีเจอร์นี้ใช้งานได้หรือไม่?” แต่มันถามว่า “มันเร็วแค่ไหน รองรับได้เท่าไหร่ และจะเกิดอะไรขึ้นเมื่อถึงขีดจำกัด?”
ความแตกต่างนั้นสำคัญ การทดสอบฟังก์ชันและการทดสอบประสิทธิภาพตอบคำถามที่แตกต่างกันและจับข้อผิดพลาดที่แตกต่างกันได้ Endpoint สำหรับการเข้าสู่ระบบอาจคืนค่าโทเค็นที่ถูกต้องทุกครั้ง แต่ยังคงใช้เวลาสี่วินาทีในการทำงานภายใต้ภาระงาน การทดสอบฟังก์ชันผ่าน; ผู้ใช้จากไป การทดสอบประสิทธิภาพคือสิ่งที่เปิดเผยปัญหาที่สองนั้น
ผลลัพธ์ของการทดสอบประสิทธิภาพไม่ใช่แค่การผ่านหรือไม่ผ่านง่ายๆ แต่มันคือโปรไฟล์: ที่ภาระงานระดับนี้ ระบบตอบสนองได้เร็วเท่านี้ รักษาปริมาณงานได้เท่านี้ และล้มเหลวในลักษณะนี้เมื่อถูกผลักดันเกินจุดนี้ โปรไฟล์นั้นคือสิ่งที่ช่วยให้ทีมวางแผนกำลังการผลิต กำหนดระดับการบริการที่เป็นจริง และตรวจจับการถดถอยก่อนการเปิดตัว
ประเภทหลักของการทดสอบประสิทธิภาพ
การทดสอบประสิทธิภาพเป็นกลุ่มของประเภทการทดสอบ โดยแต่ละประเภทจะใช้ภาระงานในรูปแบบที่แตกต่างกันเพื่อตอบคำถามที่แตกต่างกัน
การทดสอบ Baseline (Baseline testing) จะรันระบบภายใต้ภาระงานปกติที่คาดไว้และบันทึกผลลัพธ์ Baseline นี้คือข้อมูลอ้างอิงที่การทดสอบในภายหลังทั้งหมดจะใช้เปรียบเทียบ หากไม่มีมัน คุณจะไม่สามารถบอกได้ว่าตัวเลขนั้นดี ไม่ดี หรือแค่แตกต่างกัน
การทดสอบ Load (Load testing) ใช้ปริมาณการใช้งานสูงสุดที่คาดการณ์ไว้และยืนยันว่าระบบสามารถรองรับได้: เวลาตอบสนองยังคงอยู่ในงบประมาณ ข้อผิดพลาดใกล้เคียงศูนย์ มันตรวจสอบว่าระบบสามารถอยู่รอดได้ในวันทำงานที่ยุ่งวุ่นวายปกติ
การทดสอบ Stress (Stress testing) จงใจเกินขีดจำกัด โดยเพิ่มภาระงานจนกว่าระบบจะเสื่อมถอยหรือล้มเหลว เป้าหมายคือการค้นหาจุดแตกหักและสังเกตรูปแบบความล้มเหลว การเสื่อมถอยอย่างสง่างาม (ทำงานช้าลงแต่ยังคงให้บริการได้) เป็นที่ยอมรับได้; การสูญเสียข้อมูลหรือข้อผิดพลาดที่ส่งผลกระทบต่อเนื่องไม่ใช่
การทดสอบ Spike (Spike testing) ใช้การเพิ่มภาระงานอย่างกะทันหันและรวดเร็ว แล้วลดลงอีกครั้ง มันจำลองการขายแฟลชเซล ข่าวสาร และการระเบิดของปริมาณงานอื่นๆ ระบบที่ปรับแต่งมาเพื่อการจราจรที่สม่ำเสมออาจยังคงล้มเหลวเมื่อเกิด Spike เพราะมันไม่สามารถปรับขนาดได้เร็วพอ
การทดสอบ Capacity (Capacity testing) ค้นหาภาระงานสูงสุดที่ระบบสามารถรองรับได้ในขณะที่ยังคงบรรลุเป้าหมาย คำตอบคือตัวเลขที่ชัดเจน ซึ่งใช้โดยตรงสำหรับการวางแผนกำลังการผลิตและเกณฑ์การปรับขนาดอัตโนมัติ
การทดสอบ Soak (Soak testing) หรือที่เรียกว่าการทดสอบความเสถียรหรือความทนทาน จะคงภาระงานระดับปานกลางเป็นระยะเวลานานเพื่อเปิดเผยความล้มเหลวที่เกิดขึ้นช้าๆ: การรั่วไหลของหน่วยความจำ การใช้ทรัพยากรจนหมด การทำงานช้าลงอย่างค่อยเป็นค่อยไป สิ่งเหล่านี้มองไม่เห็นในการรันระยะสั้น และจะปรากฏขึ้นเมื่อผ่านไปหลายชั่วโมงเท่านั้น
ทีมส่วนใหญ่จะดำเนินการทดสอบ Baseline, Load และ Soak เป็นมาตรฐาน และเพิ่มการทดสอบ Stress และ Spike สำหรับระบบที่มีปริมาณการใช้งานสูงหรือไม่สามารถคาดเดาได้
เมตริกที่ใช้นิยามผลลัพธ์
การทดสอบประสิทธิภาพจะมีประโยชน์ก็ต่อเมื่อเมตริกที่คุณอ่านจากมันมีประโยชน์เท่านั้น
เวลาตอบสนอง (Response time) คือระยะเวลาตั้งแต่การร้องขอจนถึงการตอบกลับ ควรอ่านค่านี้เป็นการกระจายเสมอ ค่าเฉลี่ยอาจทำให้เข้าใจผิดได้; ค่าเฉลี่ยที่ดีอาจซ่อนเปอร์เซ็นไทล์ที่ 99 ซึ่งแย่กว่าสิบเท่า ส่วนที่ช้าที่สุดคือสิ่งที่ผู้ใช้จริงสังเกตเห็นและบ่นถึง
ปริมาณงาน (Throughput) คือปริมาณงานที่ทำเสร็จต่อหน่วยเวลา มักจะแสดงเป็นจำนวนคำขอต่อวินาที มันคำนวณจากจำนวนคำขอทั้งหมดหารด้วยระยะเวลาการทดสอบ และแสดงถึงขีดความสามารถที่แท้จริงของระบบ
การทำงานพร้อมกัน (Concurrency) คือจำนวนผู้ใช้หรือการเชื่อมต่อพร้อมกัน ความสามารถของระบบมักจะระบุเป็นระดับการทำงานพร้อมกันที่เวลาตอบสนองเกินเกณฑ์ที่ยอมรับได้
อัตราข้อผิดพลาด (Error rate) คือเปอร์เซ็นต์ของคำขอที่ล้มเหลวภายใต้ภาระงาน ระบบที่ยังคงรวดเร็วแต่เริ่มล้มเหลวเมื่อมีการทำงานพร้อมกันสูงไม่ได้ถือว่าผ่าน; ความเร็วที่ปราศจากความน่าเชื่อถือไม่ใช่ประสิทธิภาพ
การใช้ CPU และหน่วยความจำ (CPU and memory utilization) อธิบายว่า ทำไม ตัวเลขอื่นๆ จึงเปลี่ยนแปลง หากเวลาแฝงเพิ่มขึ้นในขณะที่ CPU ทำงาน 100% ระบบนั้นถูกจำกัดด้วยการประมวลผล หากเวลาแฝงเพิ่มขึ้นในขณะที่ CPU ไม่ได้ใช้งาน คอขวดอยู่ที่ปลายน้ำ มักจะเป็นฐานข้อมูล ล็อก หรือการพึ่งพาจากภายนอก
ผลลัพธ์ที่สมบูรณ์จะอ่านได้เหมือนประโยค: ที่การทำงานพร้อมกันระดับนี้ ปริมาณงานสูงสุดอยู่ที่นี่ เวลาตอบสนองเปอร์เซ็นไทล์ที่ 95 คือเท่านี้ อัตราข้อผิดพลาดคือเท่านี้ และเซิร์ฟเวอร์ถูกจำกัดด้วยทรัพยากรนี้
การทดสอบประสิทธิภาพเข้ากับกระบวนการอย่างไร
การทดสอบประสิทธิภาพเคยเป็นเพียงประตูเดียวใกล้จะสิ้นสุดโครงการ ซึ่งดำเนินการเพียงครั้งเดียวก่อนการเปิดตัวโดยทีมผู้เชี่ยวชาญ โมเดลนั้นล้มเหลวสำหรับระบบที่มีการจัดส่งอย่างต่อเนื่อง เพราะประสิทธิภาพจะถดถอยลงเกือบทุกครั้งที่มีการเปลี่ยนแปลง การสืบค้นใหม่ การรวมระบบที่เพิ่มเข้ามา คอลัมน์ที่ไม่ได้ทำดัชนี แต่ละอย่างล้วนเพิ่มเวลาแฝงอย่างเงียบๆ ซึ่งไม่มีการทดสอบฟังก์ชันใดตรวจพบได้
โมเดลที่ดีกว่าคือการปฏิบัติต่อประสิทธิภาพเหมือนความถูกต้อง: ตรวจสอบอย่างต่อเนื่อง โดยมีงบประมาณ กำหนดงบประมาณสำหรับเวลาตอบสนองและอัตราข้อผิดพลาดสำหรับเส้นทางที่สำคัญ รันการทดสอบโหลดแบบเบาใน CI/CD เพื่อให้การถดถอยทำให้บิลด์ล้มเหลวที่ pull request สำรองการรัน stress และ soak ที่หนักหน่วงไว้สำหรับการทดสอบก่อนการเปิดตัวตามกำหนดเวลา ซึ่งระยะเวลาการรันที่นานขึ้นเป็นที่ยอมรับได้
สำหรับระบบส่วนใหญ่ จุดที่มีมูลค่าสูงสุดในการทดสอบประสิทธิภาพคือเลเยอร์ API API มีตรรกะหลัก มันเรียกใช้ได้รวดเร็วและคาดเดาได้ และไม่มี UI ที่ไม่น่าเชื่อถือให้ต้องแก้ไข การทดสอบ API ภายใต้ภาระงานให้ตัวเลขที่เชื่อถือได้ในราคาถูก; การทดสอบประสิทธิภาพ API ครอบคลุมวิธีการที่มุ่งเน้นนี้โดยละเอียด การเก็บการทดสอบประสิทธิภาพไว้คู่กับการทดสอบ API ฟังก์ชัน หมายความว่าทุกการเปลี่ยนแปลงจะถูกตรวจสอบทั้งความถูกต้องและความเร็วพร้อมกัน
ข้อผิดพลาดทั่วไปในการทดสอบประสิทธิภาพ
การทดสอบประสิทธิภาพสามารถทำได้ง่ายในลักษณะที่สร้างคำตอบที่มั่นใจแต่ผิดพลาด ข้อผิดพลาดบางประการปรากฏขึ้นซ้ำแล้วซ้ำเล่า
การทดสอบกับโครงสร้างพื้นฐานที่ไม่สมจริง การทดสอบโหลดบนแล็ปท็อปของนักพัฒนา หรือกับสภาพแวดล้อม staging ที่มีทรัพยากรเพียงเล็กน้อยเมื่อเทียบกับการผลิต สร้างตัวเลขที่ไม่มีความหมาย ทดสอบบนโครงสร้างพื้นฐานที่ใกล้เคียงกับการผลิตให้มากที่สุดเท่าที่คุณจะทำได้
การละเลยผลกระทบจากการวอร์มอัพ ระบบหลายระบบทำงานช้าในช่วงไม่กี่วินาทีแรกของการรันในขณะที่แคชกำลังเติมและพูลการเชื่อมต่อกำลังเปิด การวัดทั้งช่วง cold start และ steady state พร้อมกันทำให้เกิดค่าเฉลี่ยที่ทำให้เข้าใจผิดได้ ให้ทิ้งช่วง warm-up ออกไป หรือรายงานแยกต่างหาก
การอ่านค่าเฉลี่ยแทนเปอร์เซ็นไทล์ ข้อผิดพลาดนี้ควรพูดซ้ำเพราะมันพบบ่อยมาก เวลาตอบสนองเฉลี่ย 200 มิลลิวินาทีอาจซ่อนเปอร์เซ็นไทล์ที่ 99 ที่เป็นสามวินาทีได้ ค่าเฉลี่ยอธิบายถึงคำขอที่ไม่มีใครทำจริง; เปอร์เซ็นไทล์อธิบายถึงผู้ใช้จริง
การใช้ข้อมูลที่ไม่สมจริง การทดสอบทุกคำขอด้วย user id เดียวกันหรือผลิตภัณฑ์เดียวกันหมายความว่าฐานข้อมูลจะให้บริการทุกอย่างจากแคช การใช้งานจริงจะกระจายไปทั่วชุดข้อมูล ทำให้เข้าถึงแถวที่ไม่ได้อยู่ในแคชและเกิด cache misses ปรับเปลี่ยนข้อมูลการทดสอบให้ตรงกัน
การทดสอบ endpoint เดียวแยกกัน ผู้ใช้จริงจะทำงานผ่านเวิร์กโฟลว์: เข้าสู่ระบบ, เรียกดู, ค้นหา, ชำระเงิน การทดสอบ endpoint เดียวอย่างหนักจะพลาดการแย่งชิงทรัพยากรที่เกิดขึ้นเมื่อหลายๆ endpoint แข่งขันกันเพื่อใช้ฐานข้อมูลและ connection pool เดียวกัน ทดสอบสถานการณ์แบบหลายขั้นตอนที่สมจริง ไม่ใช่แค่การเรียกใช้แต่ละครั้ง
การถือว่าการทดสอบทำเพียงครั้งเดียวจบ การทดสอบประสิทธิภาพครั้งเดียวก่อนการเปิดตัวจะล้าสมัยทันทีที่ฟีเจอร์ถัดไปถูกจัดส่ง ประสิทธิภาพจะถดถอยอย่างต่อเนื่อง ดังนั้นการทดสอบก็ต้องดำเนินการอย่างต่อเนื่องเช่นกัน
การหลีกเลี่ยงข้อผิดพลาดทั้งหกประการนี้คือส่วนใหญ่ที่แยกแยะการทดสอบประสิทธิภาพที่ให้ข้อมูลสำหรับการตัดสินใจออกจากการทดสอบที่สร้างเครื่องหมายถูกสีเขียวที่ดูสบายใจแต่ไม่มีความหมาย
การรันการทดสอบประสิทธิภาพด้วย Apidog
Apidog ได้รวมการทดสอบโหลดเข้าไว้ในพื้นที่ทำงานเดียวกันที่ใช้สำหรับการออกแบบ API และการทดสอบฟังก์ชัน ดังนั้นการตรวจสอบประสิทธิภาพจึงไม่จำเป็นต้องใช้เครื่องมือแยกต่างหากหรือสำเนาการนิยาม API แยกต่างหาก
คุณนำ endpoint หรือ สถานการณ์ทดสอบ แบบหลายขั้นตอน มายืนยันว่ามันผ่านการทำงานแบบฟังก์ชัน จากนั้นรันภายใต้จำนวนผู้ใช้เสมือนที่กำหนดไว้เป็นระยะเวลาหนึ่ง Apidog จะเพิ่มโหลดขึ้นทีละน้อยและรายงานเปอร์เซ็นไทล์เวลาตอบสนอง ปริมาณงาน และอัตราข้อผิดพลาดแบบเรียลไทม์ คุณจึงสามารถเห็นระดับการทำงานพร้อมกันที่ประสิทธิภาพเริ่มเปลี่ยนแปลงได้อย่างแม่นยำ สำหรับโหลดที่เกินกว่าเครื่องเดียว สถานการณ์นี้สามารถส่งออกไปยัง JMeter ได้โดยยังคงการนิยามเดิมไว้
เนื่องจากสถานการณ์ทดสอบเดียวกันใช้ได้ทั้งการรันแบบฟังก์ชันและประสิทธิภาพ คุณจึงดูแลรักษา artifact เพียงชิ้นเดียวแทนที่จะเป็นสองชิ้น ดาวน์โหลด Apidog เพื่อโปรไฟล์ endpoint ที่คุณมีอยู่แล้ว
คำถามที่พบบ่อย
การทดสอบประสิทธิภาพกับการทดสอบฟังก์ชันแตกต่างกันอย่างไร? การทดสอบฟังก์ชันจะตรวจสอบว่าซอฟต์แวร์ให้ผลลัพธ์ที่ถูกต้องหรือไม่ การทดสอบประสิทธิภาพจะตรวจสอบว่าซอฟต์แวร์ทำเช่นนั้นได้เร็วและน่าเชื่อถือเพียงใดภายใต้ภาระงาน ทั้งสองอย่างจำเป็น; ไม่มีอะไรมาแทนที่กันได้
ควรเริ่มรันการทดสอบประสิทธิภาพประเภทใดก่อน? Baseline แล้วตามด้วย load Baseline จะให้ข้อมูลอ้างอิงภายใต้เงื่อนไขปกติ; การทดสอบ load จะยืนยันว่าระบบสามารถอยู่รอดได้ในปริมาณการใช้งานสูงสุดที่คาดไว้ จากนั้นค่อยเพิ่มการทดสอบ stress, spike และ soak
ทำไมต้องใช้เปอร์เซ็นไทล์แทนเวลาตอบสนองเฉลี่ย? ค่าเฉลี่ยจะถูกดึงเข้าหาตรงกลางและซ่อนส่วนที่ช้าที่สุดไว้ เปอร์เซ็นไทล์ที่ 95 และ 99 จะเปิดเผยว่าคำขอที่โชคร้ายที่สุดประสบอะไร และส่วนที่ช้านั้นคือสิ่งที่ผู้ใช้รู้สึก
การทดสอบประสิทธิภาพสามารถทำได้โดยอัตโนมัติหรือไม่? ได้ การทดสอบโหลดแบบเบาสามารถรันได้ดีใน CI ทุกครั้งที่มีการเปลี่ยนแปลง โดยมีงบประมาณที่กำหนดไว้ว่าจะทำให้บิลด์ล้มเหลวหากเกิดการถดถอย การทดสอบ stress และ soak ที่หนักกว่ามักจะถูกกำหนดเวลาไว้แทนที่จะรันทุกครั้งที่มีการ commit
ควรเริ่มการทดสอบประสิทธิภาพเมื่อใดในวงจรการพัฒนา? เร็วกว่าที่ทีมส่วนใหญ่คิด คุณไม่สามารถได้ตัวเลขเวลาแฝงสุดท้ายหากไม่มีโครงสร้างพื้นฐานจริง แต่คุณสามารถกำหนดงบประมาณและเขียนสถานการณ์ทดสอบได้ตั้งแต่ช่วงการออกแบบ การรันการทดสอบโหลดพื้นฐานทันทีที่ endpoint สามารถใช้งานได้จะช่วยจับปัญหาในขณะที่ยังแก้ไขได้ในราคาถูก
ใครเป็นผู้รับผิดชอบการทดสอบประสิทธิภาพ? ในทีมสมัยใหม่มันเป็นความรับผิดชอบร่วมกัน นักพัฒนาจะรันการตรวจสอบโหลดแบบเบาในการเปลี่ยนแปลงของตนเอง; QA เป็นเจ้าของสถานการณ์ทดสอบและงบประมาณที่กว้างขึ้น; ฝ่ายปฏิบัติการหรือ SRE จัดหาโครงสร้างพื้นฐานที่เหมือนกับการผลิตและเมตริกฝั่งเซิร์ฟเวอร์ การมองว่าเป็นงานของผู้เชี่ยวชาญคนเดียวคือสาเหตุที่ทำให้ปัญหาประสิทธิภาพไปถึงการผลิต
การทดสอบประสิทธิภาพควรรันนานแค่ไหน? นานพอที่จะผ่านช่วงวอร์มอัพและเข้าสู่สถานะคงที่ โดยปกติจะใช้เวลาหลายนาทีสำหรับการทดสอบโหลด การทดสอบ Soak ถูกออกแบบให้รันเป็นเวลาหลายชั่วโมงหรือหลายวัน เนื่องจากวัตถุประสงค์ทั้งหมดคือเพื่อเปิดเผยการเสื่อมสภาพที่เกิดขึ้นช้าๆ ซึ่งการรันระยะสั้นจะพลาดไป
