เมื่อการเพิ่มประสิทธิภาพแบบน่าประทับใจไม่ใช่สิ่งสำคัญ
(blog.colinbreck.com)- การปรับแต่งประสิทธิภาพเป็นวิธีทรงพลังในการทำความเข้าใจระบบที่ซับซ้อนและปรับปรุงผลิตภัณฑ์ แต่แม้ผลลัพธ์จะ เร็วขึ้น 10 เท่า ก็อาจยังไม่เปลี่ยนวิธีทำงานจริงหรือปริมาณงานที่ทำได้
- แม้จะลดเวลาตอบสนองของคิวรีจาก 5–10 นาที เหลือ 30 วินาที–1 นาที ได้ แต่หากยังเกิน เกณฑ์ราว 10 วินาที ที่มนุษย์ยังคงรักษาความสนใจไว้ได้ ผลที่ผู้ใช้รับรู้ก็อาจมีจำกัด
- หากงานถูกจำกัดเป็นหน่วยแบบจำนวนเต็ม เช่น วันละ 1 หรือ 2 งาน การปรับปรุงเพียง 25–50% อาจไม่พอ และเมื่อรวมเวลาเดินทางแล้ว แต่ละงานต้องใช้เวลา ไม่เกิน 4 ชั่วโมง จึงจะทำได้วันละ 2 งาน
- ใน data pipeline ขั้นตอนที่ช้าจะสร้าง backpressure ไปยังส่วนต้นน้ำ ดังนั้นแม้บางขั้นตอนจะเร็วขึ้นมาก ก็อาจยังไม่เพิ่ม throughput แบบ end-to-end จนกว่าคอขวดทั้งหมดจะถูกคลี่คลาย
- การประเมินการปรับปรุงประสิทธิภาพควรยึดตามผลลัพธ์ที่ต้องการ ไม่ใช่ benchmark ของแต่ละส่วน และหากยังไม่ข้ามข้อจำกัดอย่างการรักษาความสนใจ การเพิ่มจำนวนหน่วยงาน หรือ throughput โดยรวมได้ แม้การปรับปรุงครั้งใหญ่ก็อาจมีผลในทางปฏิบัติน้อย
ทำไมตัวเลขประสิทธิภาพกับผลลัพธ์จริงจึงไม่สอดคล้องกัน
- งานด้านประสิทธิภาพเป็นงานที่คุ้มค่า เพราะช่วยทำให้ระบบมีประสิทธิภาพมากขึ้นและเปิดความเป็นไปได้ใหม่ให้ลูกค้า
- ยังช่วยให้เข้าใจ เชิงประจักษ์ ว่าระบบซับซ้อนที่มีสเกลและโหลดทำงานสัมพันธ์กันอย่างไร
- ระหว่างที่ลงมือใกล้ชิดกับระบบ ก็มักเกิดไอเดียในการปรับปรุงผลิตภัณฑ์และบริการ ซึ่งบางส่วนก็ไม่ได้เกี่ยวกับ performance optimization โดยตรง
- แต่ถึงจะเป็นผลลัพธ์ที่ดูดีอย่าง “เร็วขึ้น 10 เท่า” หรือ “ลดทรัพยากรลง 50%” หากยังข้ามข้อจำกัดที่ซ่อนอยู่ไม่ได้ ก็อาจสร้างการเปลี่ยนแปลงตามที่คาดหวังได้ยาก
เกิน 10 วินาทีเมื่อไร ผู้ใช้ก็หลุดจากความสนใจ
- มีกรณีที่ปรับปรุงประสิทธิภาพคิวรีของฐานข้อมูลใหม่ ทำให้คิวรีที่แพงที่สุดบนฐานข้อมูลเดิมจากเดิมใช้เวลา 5–10 นาที ลดลงเหลือ 30 วินาที–1 นาที
- ผลลัพธ์นี้ถือว่าดีขึ้นระดับ 10 เท่า แต่หากจะเปลี่ยนประสบการณ์ผู้ใช้จริง ก็ยังต้องการการปรับปรุงครั้งใหญ่อีกครั้ง
- งานวิจัยด้านปฏิสัมพันธ์มนุษย์-คอมพิวเตอร์มองว่าขีดจำกัดที่คนจะยังคงรักษาความสนใจต่อทั้งงานไว้ได้อยู่ที่ประมาณ 10 วินาที
- 0.1 วินาที คือเกณฑ์ที่รับรู้ว่าเป็น feedback ทันที
- ประมาณ 1 วินาที คือเกณฑ์ที่ flow ของงานยังต่อเนื่อง
- ประมาณ 10 วินาที คือเกณฑ์ที่ยังรักษาความสนใจต่อทั้งงานไว้ได้
- feedback อย่างตัวบอกความคืบหน้าหรือเวลาที่คาดไว้ ช่วยพยุงความสนใจได้
- ทั้ง 30 วินาทีและ 5 นาทีต่างก็เกิน 10 วินาที ผู้ใช้จึงมักหันไปเช็กข้อความ ไปหยิบกาแฟ เริ่มคุยกับคนอื่น หรือสลับไปทำงานอย่างอื่น
- หากผู้ใช้กลับมาอีกไม่กี่นาทีหรือหลายชั่วโมงต่อมาแล้วพบว่า UI โหลดเสร็จแล้ว เวลารอจริงจะเป็น 30 วินาทีหรือ 5 นาที ก็อาจไม่สร้างความต่างใหญ่ต่อรูปแบบการทำงาน
- ในโปรเจ็กต์นั้น สุดท้ายสามารถลดคิวรีจำนวนมากให้เหลือ ต่ำกว่า 10 วินาที ได้ และยังทำให้บางคิวรีที่เดิมทำไม่ได้เพราะ timeout กลับมาทำได้
- ไม่ได้มีแค่ latency ของ data query เท่านั้นที่สำคัญ แต่ latency ของ metadata query และเวลา render หน้าเว็บก็สำคัญต่อการปรับปรุงประสิทธิภาพโดยรวมเช่นกัน
- ยังมีโอกาสปรับปรุงได้อีกระดับ 10 เท่าจาก asynchronous I/O และการปรับปรุง data aggregation ซึ่งหากทำได้ คิวรีที่เดิมใช้เวลาหลายนาทีอาจตอบกลับในเวลาไม่ถึง 1 วินาที
จุดเปลี่ยนจากวันละ 1 งานเป็น 2 งาน
- ในโปรเจ็กต์หนึ่ง มีการลดทั้งกระบวนการจากหลายชั่วโมงให้เหลือ ต่ำกว่า 1 ชั่วโมงอย่างสม่ำเสมอ ด้วยการทำงาน manual ให้เป็นอัตโนมัติ ตัดขั้นตอนที่ไม่จำเป็น เพิ่มความขนานในบางส่วน และเลื่อนบางขั้นตอนไปทำแบบ asynchronous ในภายหลัง
- แม้การปรับปรุงจะอยู่ราว 25–50% แต่กระบวนการทั้งหมดกลับยังไม่เปลี่ยนไปเพราะข้อจำกัดด้านโลจิสติกส์
- ลองนึกถึงช่างประปา ช่างไฟ หรือช่างไม้ ที่ต้องนัดหมาย เดินทางไปยังสถานที่ และทำงานให้เสร็จ
- หากทำงานวันละ 8 ชั่วโมง และงานในหนึ่งสถานที่ใช้เวลา 8 ชั่วโมง ต่อให้ประหยัดเวลาได้ 2–3 ชั่วโมง ก็ยังไม่มีเวลาพอจะเดินทางไปที่ใหม่และทำงานอีกงานให้เสร็จ
- ถ้าแต่ละงานรวมเวลาเดินทางแล้วยังใช้เกิน 4 ชั่วโมง ก็จะยังทำได้ไม่ถึงวันละ 2 งาน
- ก่อนจะข้ามเกณฑ์นี้ได้ การเพิ่มประสิทธิภาพในขั้นกลาง ๆ จะยังไม่แปลงเป็นการเพิ่มผลผลิต
- อย่างไรก็ตาม การโฟกัสเรื่อง performance ก็อาจนำไปสู่ การปรับปรุงด้านคุณภาพและความเสถียร ที่ส่งผลโดยตรงต่อประสบการณ์ลูกค้าได้ด้วย
- แม้การปรับปรุง performance เล็ก ๆ จะยังไม่ใช่จุดเปลี่ยนใน production แต่ก็อาจช่วยให้การวนรอบในสภาพแวดล้อมทดสอบเร็วขึ้น ทำให้พัฒนาฟีเจอร์และแก้บั๊กได้ไวขึ้น
คอขวดใน pipeline ที่มี backpressure
- โครงสร้างพื้นฐานของซอฟต์แวร์ธุรกิจจำนวนมากประกอบด้วย data pipeline ที่ประมวลผล event จากหลายแหล่ง เช่น รถยนต์ อุปกรณ์ในโรงงาน โทรศัพท์มือถือ หรือธุรกรรมการเงิน
- โดยทั่วไป event จะถูกเก็บไว้ใน log ที่คงทน และบริการปลายน้ำจะดึงไปประมวลผลต่อ
- เพื่อรองรับขนาดใหญ่และ throughput สูง log จำเป็นต้องแบ่ง partition และบริการปลายน้ำก็มักใช้เทคนิคอย่าง batching, pipelining, parallelism, การจัดสรรหน่วยความจำอย่างมีประสิทธิภาพ และ dynamic scaling
- คอขวดของ data pipeline หาได้ยาก เพราะพฤติกรรมของระบบแต่ละส่วนเชื่อมโยงกัน
- ขั้นตอนที่ช้าจะจงใจสร้าง backpressure ไปยังขั้นตอนต้นน้ำ
- หากมีคอขวดหลายจุด throughput โดยรวมจะยังไม่เพิ่มจนกว่าจะกำจัดคอขวดจุดสุดท้ายได้
- การแบ่ง pipeline ออกเป็นหลายขั้นและทำความเข้าใจคุณลักษณะด้านประสิทธิภาพกับข้อจำกัดของแต่ละขั้น เป็นแนวปฏิบัติทางวิศวกรรมที่ดี
- แต่ถึงจะปรับปรุงเพียงขั้นตอนเดียวให้ดีขึ้นหลายหลัก ก็อาจไม่ส่งผลต่อ throughput โดยรวมเลย
- สำหรับการปรับปรุง throughput ตัวเลขที่สำคัญไม่ใช่ benchmark ของแต่ละขั้น แต่คือ throughput แบบ end-to-end
วิธีเชิงประจักษ์ในการหาคอขวด
- หากต้องการเข้าใจพลวัตของระบบและคอขวดของระบบประเภทนี้ วิธีที่มีประโยชน์คือการตรวจสอบเชิงประจักษ์โดยเริ่มจากต้นทางของ pipeline
- ตัวอย่างเช่น เริ่มจากขั้นตอนที่อ่าน event จาก distributed log แล้วทิ้งมันไปก่อน
- ถ้าแค่ขั้นตอนนี้ยังไปไม่ถึง throughput เป้าหมาย การไป optimize ขั้นปลายน้ำก็เป็นการเสียเวลา
- benchmark ฝั่งปลายน้ำ เช่น ฐานข้อมูลสามารถ insert ได้กี่แถวต่อวินาที ก็อาจยังสำคัญ แต่การวิเคราะห์ควรเริ่ม จากต้นน้ำ
- การทำ simulation ก็เป็นวิธีที่มีคุณค่าในการทำความเข้าใจระบบซับซ้อนและประสิทธิภาพ
เกณฑ์ของการปรับปรุงประสิทธิภาพคือผลลัพธ์ที่ต้องการ
- งานด้านประสิทธิภาพแม้จะยาก แต่ก็เป็นการฝึกให้เข้าใจระบบซับซ้อนอย่างลึกซึ้งและสร้างผลิตภัณฑ์ที่ดีกว่าเดิม
- หากต้องการรักษาความสนใจของมนุษย์ไว้ ควรตอบสนองภายในประมาณ 10 วินาที
- หากข้อจำกัดอยู่ที่หน่วยงานทั้งหมด การปรับปรุงแบบเป็นเปอร์เซ็นต์อย่างเดียวไม่พอ แต่ต้องข้ามจากวันละ 1 งานเป็น 2 งานได้จริง
- หากต้องการเพิ่ม throughput ของ pipeline ที่มี backpressure ให้สูงสุด มักต้องแก้คอขวดทั้งหมด ไม่ใช่แค่หนึ่งหรือสองจุด
- หากยังข้ามข้อจำกัดเหล่านี้ไม่ได้ แม้การปรับปรุงประสิทธิภาพระดับ 10 เท่าก็อาจไม่สร้างผลลัพธ์ตามที่ต้องการ
1 ความคิดเห็น
ความคิดเห็นบน Lobste.rs
ถ้าเป็นกรณีที่ปรับปรุงขั้นตอนหนึ่งได้หลายสิบเท่าแต่กลับผิดหวัง เพราะมันไม่มีผลต่อ throughput โดยรวม ก็ควรพูดถึง กฎของ Amdahl ที่นี่
ได้ยินกฎใหม่ ๆ อยู่เรื่อย ๆ แต่หลายอันเป็นเรื่องเฉพาะทางจนไม่ได้ใช้บ่อย เลยลืมไปอีก ไม่ได้หมายความว่ากฎเหล่านั้นไม่ถูกต้องหรือไม่มีประโยชน์ในฐานะความรู้สืบทอดระหว่างรุ่น
สงสัยตั้งแต่แรกว่าทำไมถึงไป optimize ส่วนที่กินเวลาโดยรวมเพียงเศษเสี้ยวเล็กมาก
ไม่รู้ว่าเป็นเพราะ คำแนะนำไม่ดี หรือเครื่องมือวัด performance ไม่พอ คนที่ตั้งใจทำงานที่แทบไม่มีผลกระทบมีไม่มาก โดยปกติมักมีปัญหาใหญ่กว่านั้นซ่อนอยู่
กำลังดูปัญหาบางอย่างอยู่ แล้วผล sampling แสดงให้เห็นว่าฟังก์ชันหนึ่งเด่นขึ้นมา พอดูคร่าว ๆ ก็เหมือนว่าจะปรับปรุง implementation ได้ค่อนข้างง่าย แต่ตอนนั้นกำลังทำงานอื่นอยู่ เลยเลื่อนไว้ว่า “ค่อยจัดการทีหลัง”
ต่อมานึกถึงการปรับปรุงง่าย ๆ นั้นแล้วเริ่มลงมือ แต่พอแก้จริง ๆ กลับซับซ้อนกว่าที่คิด ก็เกิด tunnel vision และอยากแก้ปริศนาให้สำเร็จ จนใช้เวลาไปมาก
ความจริงแล้วปัญหา performance นั้นเป็นเรื่องเล็กน้อยเท่านั้น มันอาจดูใหญ่ในเชิงสัดส่วนภายในบริบทที่กำลังดูอยู่ตอนนั้น หรือเวลาแบบ absolute อาจไม่มีความหมายมาก หรืออาจเป็นสถานการณ์ที่ติด I/O ไม่ใช่ CPU ก็ได้ คล้ายกับการโดน nerd sniping จากตัวเอง
แต่ก็ยังเพิกเฉยและเดินหน้า optimize ต่อ แล้วก็แปลกใจเมื่อผลปรับปรุงโดยรวมออกมาต่ำกว่า 0.1% ถ้ามีความรู้โดเมนก็จะรู้โดยสัญชาตญาณอยู่แล้วว่าส่วนนั้นไม่แพง แต่เพื่อไม่ให้เสียเวลา ยังช่วยวัดต้นทุน performance จริงให้ด้วย
หรือ benchmark อาจทำให้เข้าใจผิดก็ได้ ไม่ใช่ทุกระบบจะแสดงต้นทุนของทุกเมธอดหรือโปรเซสใน production environment ได้ง่าย
คำอธิบายเหล่านี้ทั้งหมดต่างก็ใกล้เคียงกับ dysfunction ในระดับมากน้อยต่างกัน บางอย่างใกล้เป็นปัญหาของบุคคล บางอย่างใกล้เป็นปัญหาของสภาพแวดล้อม
3.1. ถ้าทำงานที่ hyperscaler แค่ ลดปริมาณการคำนวณ 0.1% ที่ผู้ใช้มองไม่เห็นเลย ก็อาจมีผลต่อกำไรขาดทุนมากพอจะจ่ายค่าบ้านริมทะเลได้
แนวปฏิบัติการเขียนโปรแกรมที่พบได้ทั่วไปมักทำให้ทั้งระบบช้าอยู่แล้ว ตัวอย่างเช่นนึกถึงโค้ดเชิงวัตถุที่เต็มไปด้วย pointer และมี heap allocation ผ่าน allocator ทั่วไปจำนวนมหาศาล ไม่ว่าจะแก้ตรงไหนก็เป็นเพียงเศษเล็กของเวลารวม ในกรณีแย่ที่สุดก็แก้ไม่ได้เว้นแต่จะ rewrite ใหม่ทั้งหมด ถ้าโชคดีก็อาจ rewrite แบบค่อยเป็นค่อยไปได้
ต่อให้มีคอขวดแค่สองจุด แต่ถ้าสองจุดนั้นอยู่ห่างกันไม่ถึงระดับหลายเท่าแบบเลขหลักเดียว แม้จะแก้คอขวดที่แย่ที่สุดได้สมบูรณ์ ก็ยังไม่ได้ improvement ถึงหลายเท่าแบบเลขหลักเดียวด้วยซ้ำ ในหลายกรณี อย่างที่บทความบอกไว้ ถ้าจะได้ผลลัพธ์ที่มีความหมาย ต้องก้าวข้ามให้มากกว่านั้นอีกมาก
อีกอย่าง คอมพิวเตอร์ก็คล้ายกับระบบกระจายศูนย์ที่ทำงานขนานกัน มี CPU หลายตัว, GPU, ดิสก์, Ethernet ฯลฯ และความเร็วของโปรเซสถูกจำกัดโดยขั้นตอนที่ช้าที่สุดใน pipeline พอแก้ขั้นตอนนั้น ขั้นตอนที่ช้าที่สุดถัดไปก็จะเป็นตัวจำกัด และในกรณีแย่ที่สุด มีขั้นตอนที่ช้าที่สุดหลายขั้น แก้แค่อันเดียวก็ไม่ได้ประโยชน์อะไร
ถึงอย่างนั้นนี่เป็นการตีความแบบให้ประโยชน์แห่งความสงสัย บางครั้งก็แค่หลงเข้าไปในเกม optimize จนเสีย ลำดับความสำคัญ หรือทำพลาด
แม้ผู้ใช้จะไม่สังเกตเห็น การ ลดเวลาคำนวณ ของซอฟต์แวร์ก็ยังเป็นเรื่องดี
เพราะช่วยลดต้นทุนและทำให้ scale ได้ง่ายขึ้น
ถ้าการทำให้โค้ดเร็วขึ้นแลกมาด้วย ความซับซ้อน ที่มากเกินไป ต่อให้ไม่นับ maintainability ก็จะมีผลตามมาในระยะยาวที่ทำร้าย performance ได้ เพราะเมื่อเปลี่ยนโครงสร้าง โค้ดที่ตอนนี้ไม่จำเป็นแล้วจะยังคงอยู่ และการจะเข้าใจหรือลบมันออกต้องเข้าใจความซับซ้อนทั้งหมดให้ครบถ้วน
เหตุผลว่า “มันเร็วขึ้น” ไม่ควรเป็น ใบอนุญาตให้ละเลย ความกังวลเรื่อง complexity หรือ maintainability
ตอนนี้อยู่ในสถานการณ์คล้ายกัน และกำลังทำหลายโปรเจกต์เล็ก ๆ เพื่อลด query ที่เคยใช้เวลา 5 นาที ให้เหลือน้อยกว่า 30 วินาที
บอกทีมอยู่ว่าในระยะยาวมันยังไม่พอ แต่แน่นอนว่านี่คือการปรับปรุงและมีผลกระทบมาก
ในมุมมองลูกค้า การรอคอยลดจากระดับเดือดดาลเหลือแค่ระดับน่ารำคาญ
โฟกัสตอนนี้ไม่ใช่ performance ต่อผู้ใช้แต่ละราย แต่เป็น performance โดยรวม ถ้า optimize โปรเซสจำนวนมากที่ใช้เวลา 5 นาที, 10 นาที, 30 นาทีได้ จะลด การแย่งชิงทรัพยากร กับส่วนอื่นของระบบลงได้มาก การกระหน่ำฐานข้อมูลเป็นเวลา 10 นาทีถือว่านานมาก และท้ายที่สุดทุกอย่างก็เร็วขึ้น ทุกคนได้ประโยชน์