เรียนรู้วิธีปฏิบัติของ Brendan Gregg (USE, RED, flame graphs) เพื่อสอบสวนความหน่วงและคอขวดในโปรดักชันด้วยข้อมูล ไม่ใช่การเดา

Brendan Gregg เป็นหนึ่งในเสียงที่มีอิทธิพลในด้านประสิทธิภาพของระบบ โดยเฉพาะในโลกของ Linux เขาเขียนหนังสือที่ถูกใช้อย่างแพร่หลาย สร้างเครื่องมือเชิงปฏิบัติ และที่สำคัญที่สุดคือแบ่งปันวิธีการชัดเจนสำหรับการสืบสวนปัญหาในโปรดักชัน ทีมงานนำแนวทางของเขาไปใช้เพราะมันใช้ได้จริงเมื่ออยู่ภายใต้ความกดดัน: เมื่อตัวชี้วัดความหน่วงพุ่งขึ้นและทุกคนต้องการคำตอบ คุณต้องการวิธีจาก “อาจเป็น X” ไปสู่ “แน่นอนว่าเป็น Y” โดยไม่เกิดละครมาก
ระเบียบวิธีด้านประสิทธิภาพไม่ใช่เครื่องมือเดียวหรือคำสั่งที่ฉลาด มันคือวิธีการที่ทำซ้ำได้ในการสืบสวน: เช็คลิสต์ว่าต้องดูอะไรเป็นอันดับแรก จะตีความสิ่งที่เห็นอย่างไร และจะตัดสินใจทำอะไรต่อ
ความเป็นไปได้ในการทำซ้ำนี้แหละที่ช่วยลดการเดาเดา แทนที่จะพึ่งพาคนที่มีสัญชาตญาณมากที่สุด (หรือเสียงดังที่สุด) คุณทำตามกระบวนการที่สม่ำเสมอซึ่ง:
การสืบสวนความหน่วงมักพังในห้านาทีแรก คนมักกระโดดไปหาการแก้ไขทันที: “เพิ่ม CPU”, “รีสตาร์ทเซอร์วิส”, “เพิ่มแคช”, “ปรับ GC”, “ต้องเป็นเครือข่ายแน่ๆ” บางครั้งการกระทำนั้นช่วย—แต่บ่อยครั้งมันทำให้สัญญาณหายไป เสียเวลา หรือเพิ่มความเสี่ยงใหม่ๆ
วิธีของ Gregg ผลักดันให้คุณชะลอการทำ “วิธีแก้” จนกว่าจะตอบคำถามง่ายๆ ได้: อะไรอิ่มตัว? อะไรมีข้อผิดพลาด? อะไรช้าลง—throughput, queueing หรือการดำเนินการแต่ละรายการ?
คู่มือนี้ช่วยจำกัดขอบเขต วัดสัญญาณที่ถูกต้อง และยืนยันคอขวดก่อนปรับจูน เป้าหมายคือเวิร์กโฟลว์ที่มีโครงสร้างสำหรับสืบสวนปัญหาความหน่วงและการโปรไฟล์ในโปรดักชัน เพื่อให้ผลลัพธ์ไม่ขึ้นกับโชค
ความหน่วงเป็นอาการ: ผู้ใช้รอให้งานเสร็จนานขึ้น สาเหตุมักอยู่ที่อื่น—การแย่งชิง CPU การรอดิสก์หรือเครือข่าย การแย่งล็อก การเก็บขยะ การคิวยท์ หรือความล่าช้าจากบริการระยะไกล การวัดความหน่วงเพียงอย่างเดียวบอกว่ามีอาการแต่ไม่บอกว่ามาจากไหน
สัญญาณทั้งสามนี้เชื่อมโยงกัน:
ก่อนปรับจูน ให้เก็บทั้งสามข้อมูลในหน้าต่างเวลาเดียวกัน มิฉะนั้นคุณอาจ “แก้” ความหน่วงโดยการทิ้งงานหรือทำให้ fail เร็วขึ้น
ค่าเฉลี่ยซ่อนสไปก์ที่ผู้ใช้จดจำ บริการที่มีค่าเฉลี่ย 50 ms อาจยังมีการสะดุด 2 s บ่อยครั้ง
ติดตาม เปอร์เซ็นไทล์:
ดูรูปร่างของ latency ด้วย: p50 ที่นิ่งแต่ p99 ที่เพิ่มขึ้นมักบ่งชี้การสะดุดเป็นครั้งคราว (เช่น การแย่งล็อก, I/O hiccups, หยุดโลกของ GC) มากกว่าการชะลอตัวโดยรวม
งบประมาณความหน่วงคือแบบจำลองการนับง่ายๆ: “ถ้า request ต้องเสร็จใน 300 ms เวลาไปอยู่ที่ไหนได้บ้าง?” แบ่งเป็นบั๊คเก็ตเช่น:
งบนี้ช่วยกำหนดงานวัดแรก: ระบุว่าบั๊คเก็ตไหนโตขึ้นในช่วงสไปก์ แล้วสืบสวนพื้นที่นั้นแทนการปรับจูนโดยพลการ
งานความหน่วงมักไปผิดทางเมื่อปัญหาถูกอธิบายว่า ระบบช้า วิธีของ Gregg เริ่มต้นก่อนหน้านั้น: บังคับให้ปัญหาเป็นคำถามที่ทดสอบได้เฉพาะเจาะจง
เขียนสองประโยคก่อนจะแตะเครื่องมือใดๆ:
สิ่งนี้ช่วยป้องกันการปรับจูนชั้นที่ผิด—เช่น CPU โฮสต์—เมื่อความเจ็บปวดถูกจำกัดอยู่ที่ endpoint หรือบริการ downstream เฉพาะ
เลือกหน้าต่างเวลาที่ตรงกับคำร้องเรียนและรวมช่วงเปรียบเทียบ “ปกติ” ถ้าเป็นไปได้
กำหนดขอบเขตการสืบสวนอย่างชัดเจน:
ความแม่นยำตรงนี้ทำให้ขั้นตอนต่อไป (USE, RED, โปรไฟล์) เร็วขึ้นเพราะคุณจะรู้ว่าข้อมูลอะไร ควร เปลี่ยนหากสมมติฐานของคุณถูกต้อง
จด deploys, การเปลี่ยน config, การเปลี่ยนทราฟฟิก, และเหตุการณ์โครงสร้างพื้นฐาน—แต่ไม่สมมติความเป็นสาเหตุ เขียนเป็น “ถ้า X, เราควรคาดหวัง Y” เพื่อให้สามารถยืนยันหรือปฏิเสธได้เร็ว
บันทึกสั้นๆ ป้องกันการทำงานซ้ำโดยเพื่อนร่วมทีมและทำให้การส่งงานต่อราบรื่นขึ้น
Time | Question | Scope | Data checked | Result | Next step
แม้แต่ห้าบรรทัดแบบนี้ก็เปลี่ยนเหตุการณ์ตึงเครียดให้เป็นกระบวนการที่ทำซ้ำได้
USE Method (Utilization, Saturation, Errors) เป็นเช็คลิสต์ด่วนของ Gregg สำหรับสแกน “ทรัพยากรหลักสี่อย่าง”—CPU, หน่วยความจำ, ดิสก์ (storage), และเครือข่าย—เพื่อให้คุณหยุดเดาและเริ่มจำกัดปัญหา
แทนที่จะจ้องหลายแดชบอร์ด ให้ถามคำถามสามข้อเดียวกันสำหรับแต่ละทรัพยากร:
เมื่อประยุกต์อย่างสม่ำเสมอ นี่จะเป็นการตรวจสอบอย่างรวดเร็วว่า “แรงกดดัน” อยู่ที่ไหน
สำหรับ CPU utilization คือ % การใช้งาน CPU, saturation แสดงเป็นแรงกดดันของ run-queue หรือเธรดที่รอรัน, และ errors อาจรวมถึงการ throttling (ในคอนเทนเนอร์) หรือการขัดข้องของ interrupt
สำหรับ memory utilization คือหน่วยความจำที่ถูกใช้งาน, saturation มักปรากฏเป็น paging หรือการทำงานของ garbage collection บ่อย ๆ, และ errors รวมถึงการจัดสรรล้มเหลวหรือเหตุการณ์ OOM
สำหรับ disk utilization คือเวลาที่อุปกรณ์ยุ่ง, saturation คือความลึกคิวและเวลารออ่าน/เขียน, และ errors คือ I/O errors หรือ timeouts
สำหรับ network utilization คือ throughput, saturation คือการดรอป/คิว/latency, และ errors คือ retransmits, resets, หรือ packet loss
เมื่อผู้ใช้รายงานความช้า สัญญาณ saturation มักเผยมากที่สุด: คิว เวลารอ และการแย่งชิงมักสอดคล้องกับ latency มากกว่าการใช้งานดิบ
เมตริกระดับบริการ (เช่น latency ของคำขอและอัตราข้อผิดพลาด) บอกคุณถึง ผลกระทบ ในขณะที่ USE บอกคุณ จะต้องไปดูที่ไหนต่อ โดยชี้ว่าทรัพยากรใดกำลังถูกกดดัน
ลูปปฏิบัติได้คือ:
RED Method ช่วยให้คุณยึดโยงกับประสบการณ์ผู้ใช้ก่อนจะลงลึกในกราฟโฮสต์
RED ป้องกันไม่ให้คุณไล่ตามเมตริกที่ “น่าสนใจ” แต่ไม่กระทบผู้ใช้ มันบังคับให้เป็นวงปิดที่เข้มงวดขึ้น: endpoint ไหนช้า สำหรับผู้ใช้กลุ่มใด และตั้งแต่เมื่อไหร่? ถ้า Duration กระโดดเฉพาะเส้นทางเดียวในขณะที่ CPU รวมราบเรียบ คุณก็มีจุดเริ่มต้นที่คมชัดขึ้นแล้ว
นิสัยที่มีประโยชน์: เก็บ RED แยกตาม เซอร์วิสและ endpoints ชั้นนำ (หรือ RPC สำคัญ) เพื่อให้แยกแยะการเสื่อมสภาพทั่วไปจากการถดถอยที่จำกัดได้ง่าย
RED บอกคุณ ที่ไหนเจ็บปวด USE ช่วยทดสอบ ทรัพยากรไหนเป็นสาเหตุ
ตัวอย่าง:
เก็บเลย์เอาต์ที่เน้น:
ถ้าต้องการเวิร์กโฟลว์เหตุการณ์ที่สม่ำเสมอ ให้จับคู่ส่วนนี้กับการตรวจ USE ใน /blog/use-method-overview เพื่อให้คุณย้ายจาก “ผู้ใช้รู้สึกได้” ไปเป็น “ทรัพยากรนี้คือข้อจำกัด” โดยลดการผันผวนลง
การสืบสวนประสิทธิภาพอาจขยายเป็นกราฟและสมมติฐานนับสิบในเวลาไม่กี่นาที กรอบความคิดของ Gregg คือทำให้แคบลง: งานของคุณไม่ใช่ “เก็บข้อมูลให้มากขึ้น” แต่เป็นการถามคำถามถัดไปที่ตัดความไม่แน่นอนได้เร็วที่สุด
ปัญหาความหน่วงส่วนใหญ่ถูกครอบงำโดยต้นทุนเดียว (หรือคู่เล็กๆ): ล็อกร้อนหนึ่งตัว, การพึ่งพาช้า, ดิสก์ออเวอร์โหลด, รูปแบบ GC หนึ่งแบบ การจัดลำดับความสำคัญคือการตามหาต้นทุนที่โดดเด่นนั้นก่อน เพราะการลด 5% จากห้าจุดต่างกันแทบจะไม่เปลี่ยนความหน่วงที่ผู้ใช้เห็นได้
การทดสอบเชิงปฏิบัติ: “อะไรที่อธิบายการเปลี่ยนแปลงความหน่วงส่วนใหญ่ที่เราเห็นได้?” ถ้าสมมติฐานให้คำอธิบายเพียงเศษเสี้ยว มันคือคำถามที่มีลำดับต่ำกว่า
ใช้แนว top-down เมื่อคุณตอบคำถามว่า “ผู้ใช้ได้รับผลกระทบไหม?” เริ่มจาก endpoints (สัญญาณสไตล์ RED): latency, throughput, errors นี่ช่วยหลีกเลี่ยงการปรับจูนสิ่งที่ไม่อยู่ในเส้นทางสำคัญ
ใช้แนว bottom-up เมื่อโฮสต์ป่วยชัดเจน (อาการแบบ USE): CPU อิ่มตัว, หน่วยความจำวิ่งเพี้ยน, I/O wait ถ้าโหนดหนึ่งติดลม คุณจะเสียเวลาเพ่งที่เปอร์เซ็นไทล์ endpoint โดยไม่เข้าใจข้อจำกัด
เมื่อมีการแจ้งเตือน ให้เลือกสาขาและยืนอยู่ที่นั่นจนกว่าคุณจะยืนยันหรือปฏิเสธ:
จำกัดตัวเองไว้ที่ชุดสัญญาณเริ่มต้นเล็ก ๆ แล้วเจาะลึกเฉพาะเมื่อบางอย่างเคลื่อนไหว ถ้าต้องการเช็คลิสต์เพื่อให้โฟกัส ให้เชื่อมขั้นตอนของคุณกับ runbook เพื่อให้เมตริกใหม่ทุกตัวมีจุดประสงค์: ตอบคำถามเฉพาะ
การโปรไฟล์ในโปรดักชันอาจรู้สึกเสี่ยงเพราะแตะระบบสด—แต่บ่อยครั้งมันเป็นวิธีที่เร็วที่สุดในการเปลี่ยนการถกเถียงเป็นหลักฐาน บันทึกและแดชบอร์ดบอกคุณ ว่ามีอะไรช้า การโปรไฟล์บอกคุณ เวลาไปอยู่ที่ไหน: ฟังก์ชันไหนร้อน เธรดไหนรอ และเส้นทางโค้ดใดโดดเด่นในช่วงเหตุการณ์
การโปรไฟล์คือเครื่องมือ “งบประมาณเวลา” แทนการถกเถียง (“เป็น DB” vs “เป็น GC”) คุณจะได้หลักฐานเช่น “45% ของตัวอย่าง CPU อยู่ใน JSON parsing” หรือ “คำขอส่วนใหญ่ถูกบล็อกบน mutex” ซึ่งจำกัดก้าวถัดไปให้เป็นการแก้ไขที่เป็นรูปธรรมหนึ่งหรือสองอย่าง
แต่ละแบบตอบคำถามต่างกัน ความหน่วงสูงพร้อม CPU ต่ำมักชี้ไปที่ off-CPU หรือการรอล็อก มากกว่าจุดร้อนของ CPU
หลายทีมเริ่มจาก on-demand แล้วค่อยขยับไป always-on เมื่อเชื่อถือในความปลอดภัยและเห็นปัญหาซ้ำๆ
การโปรไฟล์ที่ปลอดภัยในโปรดักชันคือการควบคุมต้นทุน เลือก sampling (ไม่ต้องติดตามทุกเหตุการณ์), ให้หน้าต่างจับสั้น (เช่น 10–30 วินาที), และวัด overhead ใน canary ก่อน ถ้าไม่แน่ใจ ให้เริ่มด้วย sampling ความถี่ต่ำแล้วเพิ่มเมื่อตัวสัญญาณยังมีเสียงรบกวนมากเกินไป
Flame graphs แสดงภาพเวลาที่ถูกสุ่มในช่วงโปรไฟล์ แต่ละ “กล่อง” คือฟังก์ชัน (หรือเฟรมสแตก) และแต่ละสแตกแสดงเส้นทางการเรียกที่นำไปสู่ฟังก์ชันนั้น เหมาะมากสำหรับการมองเห็นรูปแบบอย่างรวดเร็ว—แต่ไม่ได้บอกโดยอัตโนมัติว่า “บั๊กอยู่ตรงนี้”
Flame graph โดยทั่วไปจะแสดง ตัวอย่าง on-CPU: เวลาที่โปรแกรมกำลังรันบนคอร์ CPU มันสามารถเน้นเส้นทางโค้ดที่ใช้ CPU หนัก การแปลงที่ไม่มีประสิทธิภาพ การซีเรียลไลซ์มากเกินไป หรือ hotspot ที่เผา CPU จริงๆ
มันไม่แสดงโดยตรงถึงการรอดิสก์ เครือข่าย ความล่าช้าของ scheduler หรือเวลาที่บล็อกบน mutex (นั่นคือ off-CPU และต้องการการโปรไฟล์แบบต่างหาก) นอกจากนี้มันก็ไม่พิสูจน์สาเหตุสำหรับ latency ที่ผู้ใช้เห็นเว้นแต่คุณจะผูกกับอาการที่กำหนดช่วงเวลาและบริบท
กล่องที่กว้างที่สุดน่าจะถูกโทษ แต่ถามตัวเอง: นี่คือ hotspot ที่คุณเปลี่ยนได้หรือแค่ “เวลาไปใน malloc, GC หรือ logging” เพราะปัญหาจริงอยู่ต้นน้ำ? ดูบริบทที่ขาด (JIT, inlining, symbols) ที่อาจทำให้กล่องดูเหมือนเป็นผู้ร้ายทั้งที่เป็นแค่ผู้ส่งสาร
ถือว่า flame graph เป็นคำตอบต่อคำถามที่กำหนด: endpoint ไหน, ช่วงเวลาไหน, โฮสต์ไหน, และ อะไรเปลี่ยนไป เปรียบเทียบ flame graphs “ก่อน vs หลัง” (หรือ “ปกติ vs เสีย”) สำหรับเส้นทางคำขอเดียวกันเพื่อลดเสียงรบกวนจากการโปรไฟล์
เมื่อ latency พุ่ง ทีมส่วนใหญ่มอง CPU% ก่อน นั่นเข้าใจได้—แต่บ่อยครั้งมันชี้ผิดทิศ บริการอาจใช้ CPU เพียง 20% แต่ยังช้ามากหากเธรดใช้เวลาส่วนใหญ่ ไม่ได้ถูกรัน
CPU% ตอบคำถามว่า “ตัวประมวลผลยุ่งแค่ไหน?” แต่มันไม่ตอบว่า “คำขอของฉันเวลาไปอยู่ที่ไหน?” คำขอสามารถหยุดชะงักในขณะที่เธรดรอ บล็อก หรือถูกพักโดย scheduler
แนวคิดสำคัญ: เวลาจริงของคำขอรวมทั้ง on-CPU และ off-CPU
เวลาที่ไม่ได้อยู่บน CPU มักซ่อนอยู่หลังการพึ่งพาและการแย่งชิง:
สัญญาณไม่กี่อย่างมักสอดคล้องกับคอขวด off-CPU:
สัญญาณเหล่านี้บอกว่า “เรากำลังรอ” แต่ไม่บอกว่าเรากำลังรออะไร
การโปรไฟล์ off-CPU ให้เวลาที่จะระบุ เหตุผลที่เราไม่ได้ถูกรัน: บล็อกใน syscalls, รอล็อก, หลับ, หรือถูกยกเลิก นั่นมีพลังสำหรับงาน latency เพราะมันเปลี่ยนการชะลอตัวที่คลุมเครือให้เป็นหมวดหมู่ที่ทำได้จริง: “บล็อกบน mutex X”, “รอ read() จากดิสก์”, หรือ “ติดใน connect() ไปยัง upstream” เมื่อคุณตั้งชื่อการรอได้ คุณก็สามารถวัด ยืนยัน และแก้ได้
งานประสิทธิภาพมักพังตรงจุดเดียวกัน: ใครบางคนเห็นเมตริกที่น่าสงสัย ประกาศว่า “นี่คือปัญหา” แล้วเริ่มปรับจูน วิธีของ Gregg ผลักดันให้คุณชะลอและ พิสูจน์ ว่าสิ่งใดจำกัดระบบก่อนเปลี่ยนแปลงใดๆ
คอขวด คือทรัพยากรหรือองค์ประกอบที่ตอนนี้จำกัด throughput หรือขับเคลื่อน latency หากคุณบรรเทามัน ผู้ใช้จะเห็นการปรับปรุง
hot spot คือที่ที่เวลาไป (เช่น ฟังก์ชันที่ปรากฏบ่อยในโปรไฟล์) Hot spot อาจเป็นคอขวดจริง—หรือเป็นงานที่ยุ่งแต่ไม่ได้อยู่บนเส้นทางช้า
เสียงรบกวน คือทุกอย่างที่ดูมีความหมายแต่ไม่ใช่: งานแบ็กกราวด์, สไปก์ครั้งเดียว, artifacts ของการสุ่มตัวอย่าง, ผลกระทบการแคช, หรือ “top talkers” ที่ไม่สอดคล้องกับปัญหาที่ผู้ใช้เห็น
เริ่มจากการจับภาพ “ก่อน” ที่ชัดเจน: อาการที่ผู้ใช้เห็น (latency หรืออัตราข้อผิดพลาด) และสัญญาณผู้สมัครชั้นนำ (CPU saturation, ความลึกคิว, I/O ดิสก์, การแย่งล็อก ฯลฯ) แล้วทำการ เปลี่ยนที่ควบคุมได้ ที่ควรส่งผลเฉพาะต่อสาเหตุที่สงสัย
ตัวอย่างการทดสอบเชิงสาเหตุ:
ความสอดคล้องเป็นแค่เบาะแส ไม่ใช่คำตัดสิน ถ้า “CPU ขึ้นเมื่อ latency ขึ้น” ให้ยืนยันด้วยการเปลี่ยนแปลงความพร้อมใช้งาน CPU หรือการลดงาน CPU แล้วสังเกตว่า latency เป็นไปตามหรือไม่
เขียนลงว่า: วัดอะไร เปลี่ยนแปลงอะไรอย่างแม่นยำ ผลก่อน/หลัง และการปรับปรุงที่สังเกต นี่จะเปลี่ยนชัยชนะครั้งเดียวให้เป็นเพลย์บุ๊กที่ใช้ซ้ำได้สำหรับเหตุการณ์ถัดไป—และป้องกันไม่ให้ “สัญชาตญาณ” เขียนประวัติใหม่ในภายหลัง
เหตุการณ์ด้านประสิทธิภาพรู้สึกเร่งด่วน ซึ่งเป็นเวลาที่การเดาเดาแทรกซึมได้ง่าย เวิร์กโฟลว์เบา ๆ ที่ทำซ้ำได้ช่วยให้คุณย้ายจาก “บางอย่างช้า” เป็น “เรารู้ว่าอะไรเปลี่ยนไป” โดยไม่วุ่นวาย
Detect: แจ้งเตือนจาก latency และอัตราข้อผิดพลาดที่ผู้ใช้เห็น ไม่ใช่แค่ CPU แจ้งหน้าเมื่อ p95/p99 ข้ามเกณฑ์เป็นเวลาต่อเนื่อง
Triage: ตอบทันทีสามคำถาม: อะไรช้า, เริ่มเมื่อไหร่, ใครได้รับผลกระทบ? ถ้าคุณบอกขอบเขต (เซอร์วิส, endpoint, ภูมิภาค, cohort) ไม่ได้ คุณยังไม่พร้อมจะปรับจูน
Measure: เก็บหลักฐานที่จำกัดคอขวด ชอบการจับแบบมีขอบเขตเวลา (เช่น 60–180 วินาที) เพื่อให้เปรียบเทียบ “ไม่ดี” กับ “ดี” ได้
Fix: เปลี่ยนครั้งละอย่าง แล้ววัดสัญญาณเดิมเพื่อยืนยันการปรับปรุงและหักล้างผลลวงตา
เก็บแดชบอร์ดร่วมที่ทุกคนใช้ตอนเหตุการณ์ ทำให้มันน่าเบื่อและสม่ำเสมอ:
เป้าหมายไม่ใช่การกราฟทุกอย่าง แต่เพื่อลดเวลาไปสู่ข้อเท็จจริงแรก
ติดตั้งเครื่องมือตรวจสอบสำหรับ endpoints ที่สำคัญที่สุด (checkout, login, search) ไม่ใช่ทุก endpoint สำหรับแต่ละอัน ให้ตกลง: p95 ที่คาดหวัง, อัตราข้อผิดพลาดสูงสุด, และ dependency สำคัญ (DB, cache, third-party)
ก่อนเกิด outage ครั้งต่อไป ให้ตกลงชุดการจับ:
บันทึกไว้ใน runbook สั้นๆ (เช่น /runbooks/latency), รวมถึงใครสามารถเรียกการจับและที่เก็บ artifacts
วิธีของ Gregg เน้นที่ การเปลี่ยนแปลงที่ควบคุมได้และการยืนยันอย่างรวดเร็ว หากทีมคุณสร้างเซอร์วิสโดยใช้ Koder.ai (แพลตฟอร์มแชทสำหรับสร้างและวน iterate เว็บ, แบ็กเอนด์, และแอปมือถือ) ฟีเจอร์สองอย่างเชื่อมโยงกับแนวคิดนี้ได้ดี:
แม้คุณจะไม่ได้สร้างโค้ดใหม่ระหว่างเหตุการณ์ นิสัยเหล่านั้น—diffs เล็ก ๆ ผลลัพธ์ที่วัดได้ และการย้อนกลับเร็ว—คือสิ่งที่ Gregg ส่งเสริม
เวลา 10:15 น. แดชบอร์ดของคุณแสดง p99 latency ของ API พุ่งจาก ~120ms เป็น ~900ms ในช่วงทราฟฟิกพีค อัตราข้อผิดพลาดคงที่ แตาลูกค้ารายงานคำขอ “ช้า”
เริ่มจากมุมมองเซอร์วิส: Rate, Errors, Duration
คุณแยก Duration ตาม endpoint และเห็นเส้นทางหนึ่งโดดเด่นที่ p99: POST /checkout Rate ขึ้น 2×, errors ปกติ, แต่ Duration พุ่งเฉพาะตอนที่ความขนานเพิ่มขึ้น นั่นชี้ไปที่ การคิวหรือการแย่งชิง, ไม่ใช่ความล้มเหลวโดยตรง
จากนั้นตรวจดูว่า latency เป็นเวลาประมวลผลหรือเวลารอ: เปรียบเทียบ “handler time” ของแอปกับเวลาคำขอทั้งหมด (หรือ upstream vs downstream spans ถ้ามี tracing) Handler time ต่ำ แต่เวลาทั้งหมดสูง—คำขอกำลังรอ
สำรวจคอขวดที่เป็นไปได้: Utilization, Saturation, Errors ของ CPU, memory, disk, และ network
การใช้งาน CPU ประมาณ 35% แต่ run queue และ context switches เพิ่มขึ้น ดิสก์และเครือข่ายดูนิ่ง ความไม่ตรงกันนี้ (CPU% ต่ำ แต่รอสูง) เป็นเบาะแสคลาสสิก: เธรดไม่ได้เผา CPU—พวกมันถูกบล็อก
คุณจับ off-CPU profile ระหว่างสไปก์และพบเวลามากใน mutex รอบแคช “promotion validation” ที่แชร์กัน
คุณเปลี่ยน global lock เป็น per-key lock (หรือทางอ่านแบบ lock-free), ปรับใช้ และสังเกต p99 กลับสู่ปกติขณะที่ Rate ยังคงสูง
เช็คลิสต์หลังเหตุการณ์: