Trace Metrics และ DDSketch
ไอเดียหลักในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียหลักในหนึ่งประโยค”ไม่ว่า sampling ทั้งสองชั้นในบทที่แล้วจะเป็นยังไง Datadog คำนวณ trace metrics — hit count, error count และ latency — อย่างต่อเนื่องจากทุก span ที่มาถึง Agent/Datadog ทำให้ dashboard เรื่อง traffic กับ latency ของคุณยังแม่นยำในเชิงสถิติ แม้ว่า trace แต่ละตัวที่ยัง inspect ได้จะเหลืออยู่แค่เศษเสี้ยวก็ตาม
Trace metrics: คำนวณจากทุก span อย่างต่อเนื่อง
หัวข้อที่มีชื่อว่า “Trace metrics: คำนวณจากทุก span อย่างต่อเนื่อง”สำหรับทุก service และ resource Datadog aggregate สามอย่างนี้จาก stream ของ span ที่ไหลเข้ามา
- hit count — มี request/operation เกิดขึ้นกี่ครั้ง
- error count — กี่ครั้งที่ error
- latency — distribution ของเวลาที่ใช้ไป
การ aggregate นี้เกิดขึ้นต่อเนื่องและมาจากทุก span ที่มาถึง Agent/Datadog — ไม่ได้คำนวณจากการเปิด trace ที่เก็บไว้แล้วมาอ่านซ้ำทีหลัง นี่คือจุดสำคัญที่ต่างจากบทที่แล้ว ingestion-time sampling กับ retention filter ควบคุมว่า trace เต็มตัวใดตัวหนึ่งโดยเฉพาะ จะเปิดดูได้ทีหลังหรือไม่ แต่การนับและจับเวลาแบบ aggregate ทำงานจาก span stream เอง โดยไม่ขึ้นกับสอง layer นั้นเลย
DDSketch: percentile ที่รอดจากการ aggregate
หัวข้อที่มีชื่อว่า “DDSketch: percentile ที่รอดจากการ aggregate”latency ไม่ใช่ตัวเลขเดียว — สิ่งที่คุณสนใจคือ distribution โดยเฉพาะ tail (p95, p99) ไม่ใช่แค่ค่าเฉลี่ย แต่ percentile มีคุณสมบัติที่ยุ่งยาก — เอา percentile จากสอง host มา average กันแล้วได้ percentile รวมที่ถูกต้องไม่ได้ Datadog แก้ปัญหานี้ด้วย DDSketch ที่เป็น distribution metric type แบบ sketch ที่ออกแบบมาให้ percentile estimate แม่นยำและ merge กันได้ ที่ scale ใหญ่
# DDSketch merge is why percentiles stay accurate across many hosts/processessketch_host_a = DDSketch(relative_accuracy=0.01)sketch_host_b = DDSketch(relative_accuracy=0.01)# each host's sketch summarizes every observed span latency locallymerged = sketch_host_a.merge(sketch_host_b)p95 = merged.get_quantile_value(0.95)แต่ละ process หรือ host เก็บ sketch ของตัวเองที่สรุป latency ที่สังเกตเห็น sketch จากหลาย host merge กันเป็น sketch เดียว และ percentile ที่ดึงจาก sketch รวมนั้นยังเป็น estimate ที่แม่นยำของ percentile จริงระดับ global — สิ่งที่วิธี average-percentile แบบตรง ๆ ให้คุณไม่ได้
ทำไมสิ่งนี้ไม่ถูกกระทบจาก sampling แต่การเข้าถึง example trace ถูกกระทบ
หัวข้อที่มีชื่อว่า “ทำไมสิ่งนี้ไม่ถูกกระทบจาก sampling แต่การเข้าถึง example trace ถูกกระทบ”นี่คือจุดที่ควรจำให้แม่น trace metrics และ percentile ที่อิงอยู่บน DDSketch ไม่ถูกกระทบจาก trace sampling หรือ retention filter ทั้งชั้นที่ 1 (ingestion-time sampling) และชั้นที่ 2 (APM Retention Filters) ไม่แตะ hit count, error count หรือ p50/p95/p99 latency ที่คุณเห็นบนหน้า overview ของ service เลย — ตัวเลขพวกนั้นมาจาก span stream เอง aggregate อย่างต่อเนื่อง
สิ่งที่ถูกกระทบจากทั้งสอง layer คือความสามารถในการเปิด example trace ตัวใดตัวหนึ่งโดยเฉพาะ — เช่น request ที่ช้าที่สุดในชั่วโมงที่ผ่านมา หรือ error ตัวหนึ่งของ error type ใดตัวหนึ่ง การหาและเปิด trace ตัวนั้นขึ้นกับว่ารอดจาก ingestion-time sampling และ retention filter เก็บ trace ตัวนั้นไว้หรือเปล่า
# Two different questions, two different data pathsp95 latency for checkout-web <- DDSketch, from every span reaching Datadog, unaffected by sampling"show me one slow example trace" <- must have been ingested AND retained to openนี่เป็นเหตุผลตรง ๆ ว่าทำไมคุณถึงเชื่อถือ dashboard เรื่อง latency หรือ error rate ได้ แม้จะตั้ง ingestion sampling rate ต่ำมาก ส่วน retention filter ที่ออกแบบมาดี (จากบทที่แล้ว) ยังจำเป็น เพื่อรับประกันว่าคุณจะหาและเปิด trace ที่ช้าหรือ error ตัวใดตัวหนึ่งได้จริงตอนที่ต้องการ
flowchart LR Spans[Every span reaching Agent/Datadog] --> Stats[Trace metrics: hit count, error count, latency] Stats --> Sketch[DDSketch per service/resource] Sketch --> P[p50/p95/p99 dashboards: unaffected by sampling] Spans -->|ingestion-time sampling| L1[Layer 1 gate] L1 -->|retention filters rate/trace_rate| L2[Layer 2 gate] L2 --> Kept[Individual example traces you can open]