Alert, SLI/SLO & error budget — รู้ว่าพังจริงเมื่อไหร่
บทที่แล้วคุณ สำรวจ HyperDX ด้วยมือ — ตั้งคำถามใหม่กับ trace/log/metric ที่ระบบปล่อยไว้ ตอบ unknown-unknowns ได้เอง แต่การสำรวจด้วยมือมีเงื่อนไขข้อเดียวที่โหดร้าย: คุณต้องอยู่หน้าจอตอนมันพัง ตอนตีสามคุณไม่ได้อยู่ — สิ่งที่ต้องปลุกคุณคือ alert และบทนี้ตอบคำถามที่ยากกว่าการตั้ง alert ให้ทำงาน: จะปลุกคุณ เมื่อไหร่? ปลุกบ่อยไปคุณจะเลิกสนใจมัน ปลุกช้าไปลูกค้าเจอปัญหาก่อนคุณ เส้นแบ่งระหว่างสองอย่างนี้คือ SLO กับ error budget
บทนี้ตั้ง alert บน platform Order ตัวเดิม (Ordering/Kitchen/Delivery/Payment) — repo kaen-food-ordering (กำลังจัดทำ) ตัวเลข SLI/burn rate ทั้งหมดวัดจาก signal ที่เรา instrument มาตั้งแต่ บท2–บท5 และ query ผ่าน schema เดียวกับ บท6 (otel_traces, Duration เป็นนาโนวินาที) alert ที่เขียนในบทนี้เป็น ClickHouse SQL / Lucene ของ HyperDX จริง — เป็นบทเดียวคู่กับ บท6 ที่ผูกกับ HyperDX โดยตั้งใจ ที่เหลือ portable
version ดิบ: alert บน “สาเหตุ” — และทำไมมันปลุกคุณจนคุณเลิกฟัง
หัวข้อที่มีชื่อว่า “version ดิบ: alert บน “สาเหตุ” — และทำไมมันปลุกคุณจนคุณเลิกฟัง”❌ version ดิบ ของการ alert คือการตั้ง alert บน สาเหตุ (cause-based): CPU เกิน 90%, memory เกิน 80%, มี log Error หนึ่งบรรทัด, queue ลึกเกิน 100 มันดูสมเหตุสมผลเพราะพวกนี้ “ดูไม่ดี” — แต่ปัญหาคือ สาเหตุที่ดูไม่ดีส่วนใหญ่ไม่ทำให้ลูกค้าเจ็บ CPU 92% ตอน batch รันกลางคืนแต่ทุกออเดอร์ยังผ่านฉลุย, retry หนึ่งครั้งที่สำเร็จในรอบสองก็โยน Error หนึ่งบรรทัดออกมา ทุก alert เหล่านี้ปลุกคุณตอนตีสามเพื่อบอกว่า “มีบางอย่างแปลก” ทั้งที่ลูกค้าไม่รู้สึกอะไรเลย
ผลลัพธ์คือ alert fatigue: เมื่อ 95% ของ alert เป็น false alarm สมองคุณจะเรียนรู้ที่จะ เพิกเฉย มันทั้งหมด — รวมถึง 5% ที่เป็นของจริง นี่คือความล้มเหลวที่แพงที่สุดของ observability: ไม่ใช่การไม่มี alert แต่คือการมี alert เยอะจนไม่มีใครเชื่อมันอีกต่อไป
ทางแก้ของ Google SRE ตรงข้ามกันสุดขั้ว: alert บน อาการ (symptom-based) ที่ผู้ใช้เห็นจริงเท่านั้น — ออเดอร์วางไม่สำเร็จ, checkout ช้าเกินรับได้, ticket ค้างจนอาหารไม่ถึงครัว ไม่ใช่ alert เพราะ CPU สูง แต่ alert เพราะ ผลของ CPU สูงไปโดนลูกค้าแล้ว เพื่อทำแบบนั้นได้ เราต้องนิยาม “ดีพอ” ให้เป็นตัวเลขก่อน — นั่นคือ SLI, SLO และ error budget
SLI, SLO, SLA — นิยามตามตำรา (อย่าสับสนสามคำนี้)
หัวข้อที่มีชื่อว่า “SLI, SLO, SLA — นิยามตามตำรา (อย่าสับสนสามคำนี้)”Google SRE นิยามสามคำนี้ไว้ตรงๆ และความต่างของมันสำคัญมากพอที่จะยกมาคำต่อคำ (S37):
SLISLIService Level Indicator — ตัวชี้วัดเชิงปริมาณที่นิยามชัดของบางแง่มุมของระดับบริการProcess (Service Level Indicator) คือ ตัวชี้วัด — ตัวเลขที่วัดจริง:
“a carefully defined quantitative measure of some aspect of the level of service”
สำหรับ Ordering intake ของเรา SLI ที่เลือกคือ สัดส่วนคำขอวางออเดอร์ที่สำเร็จ (availability) และ สัดส่วน checkout ที่เสร็จภายใน X ms (latency) — วัดได้จาก otel_traces ที่เรา instrument มาแล้ว
SLOSLOService Level Objective — ค่าเป้าหมาย/ช่วงค่าของ SLI ในหน้าต่างเวลาหนึ่ง (คอร์สยึด 30 วัน)Process (Service Level Objective) คือ เป้าหมาย ที่ตั้งทับ SLI นั้น:
“a target value or range of values for a service level that is measured by an SLI”
เช่น “99.9% ของคำขอวางออเดอร์ต้องสำเร็จ ในหน้าต่าง 30 วัน” — SLI คือตัวเลขที่วิ่ง, SLO คือเส้นที่มันต้องอยู่เหนือ
SLA (Service Level Agreement) = SLO บวกผลตามมา (consequences) — สัญญาเชิงพาณิชย์ที่บอกว่า ถ้าพลาด SLO นี้ เราคืนเงิน/ชดเชยเท่านี้ กฎแยกง่ายๆ: ถ้าการพลาดเป้าไม่มีผลตามมาที่เขียนไว้ชัด มันคือ SLO ไม่ใช่ SLA ทีมวิศวกรรมส่วนใหญ่ทำงานกับ SLO (เป้าภายใน) ไม่ใช่ SLA — บทนี้จึงพูดเรื่อง SLO เป็นหลัก
ตัวเลขทุกตัวหลังจากนี้ — 43.2 นาที, 3,000 คำขอที่พังได้, และตาราง burn rate 2%/5%/10% — คำนวณบน หน้าต่าง rolling 30 วัน เป๊ะๆ ถ้าทีมคุณเปลี่ยนไปใช้หน้าต่าง 28 วันหรือรายไตรมาส ต้องคำนวณ budget-minute และเลข burn rate ทุกตัวใหม่ทั้งหมด อย่าเอาตารางไปใช้ข้ามหน้าต่างโดยไม่คิดเลข
Error budget: 100% ไม่ใช่เป้าที่ถูก
หัวข้อที่มีชื่อว่า “Error budget: 100% ไม่ใช่เป้าที่ถูก”จุดที่ปฏิวัติความคิดคือ SRE บอกว่า เป้า 100% เป็นเป้าที่ ผิด (S38) ระบบที่ไม่เคยพังเลยแปลว่าคุณ ลงทุนกับความน่าเชื่อถือมากเกินไป — deploy ช้าลง, กล้าทดลองน้อยลง, จ่าย infra แพงขึ้น เพื่อความต่างที่ผู้ใช้แทบไม่รู้สึก (ผู้ใช้บนมือถือ 3G แยกไม่ออกระหว่าง 99.9% กับ 99.999% เพราะเน็ตตัวเองพังบ่อยกว่า) ดังนั้นเราตั้งเป้าให้ ต่ำกว่า 100% อย่างจงใจ แล้วช่องว่างนั้นมีชื่อ
Error BudgetError Budget100% ลบ SLO — ปริมาณความไม่น่าเชื่อถือที่ยอมให้ได้ในงวดนั้น (99.9% ≈ 43.2 นาที/30 วัน)Process คือช่องว่างนั้น — ปริมาณความไม่น่าเชื่อถือที่ ยอมให้เกิดได้ ในงวดหนึ่ง (S41):
error budget = 100% − SLO
ถ้า SLO = 99.9% แปลว่า error budget = 0.1% ของทั้งงวด และนี่ไม่ใช่แค่เปอร์เซ็นต์นามธรรม — มันแปลงเป็น เวลา และ จำนวนคำขอ ที่จับต้องได้:
คิดเลขจริงกับ Ordering intake (SLO 99.9%, หน้าต่าง 30 วัน):
- หน้าต่าง 30 วัน = 30 × 24 × 60 = 43,200 นาที
- error budget เป็นเวลา = 0.1% × 43,200 = 43.2 นาที ต่อ 30 วัน
- ถ้ารับคำขอ ~3,000,000 ครั้งใน 30 วัน → error budget เป็นจำนวน = 0.1% × 3,000,000 = 3,000 คำขอที่พังได้
| SLO | budget ต่อ 30 วัน (เวลา) | ความหมายกับ Order |
|---|---|---|
| 99% | 432 นาที (7.2 ชม.) | หละหลวมไป — ลูกค้าเจอออเดอร์พังบ่อย |
| 99.9% | 43.2 นาที | จุดตั้งต้นที่สมเหตุสมผลของ intake |
| 99.95% | 21.6 นาที | เข้มขึ้น ต้องลงทุนความน่าเชื่อถือมากขึ้น |
| 99.99% | 4.32 นาที | เข้มมาก — เหมาะกับ path จ่ายเงินเท่านั้น |
พลังของ error budget อยู่ตรงนี้: มันเปลี่ยนการเถียงกันว่า “ปลอดภัยพอหรือยัง” (อัตวิสัย) ให้เป็นตัวเลขเดียวที่ทั้งทีมมองร่วมกัน — budget เหลือ 40 นาที = deploy feature ใหม่ได้สบาย; budget เหลือ 2 นาที = หยุด ship แล้วไปซ่อมความน่าเชื่อถือก่อน 3,000 คำขอที่พังได้นั้นคือ งบ ที่คุณจ่ายเพื่อความเร็วในการพัฒนา ไม่ใช่ความล้มเหลวที่ต้องกำจัดให้เป็นศูนย์
Burn rate: เผา budget เร็วแค่ไหน?
หัวข้อที่มีชื่อว่า “Burn rate: เผา budget เร็วแค่ไหน?”รู้ว่ามี budget 43.2 นาทีแล้วยังไม่พอ — คำถามที่ทำให้ปลุกคนได้ถูกเวลาคือ ตอนนี้เรากำลังเผามันเร็วแค่ไหน? นั่นคือ Burn RateBurn Rateอัตราการเผา error budget เทียบกับ SLO; 1 = เผาหมดพอดีในหน้าต่าง SLO; ใช้ทำ multi-window multi-burn-rate alertProcess (S42):
burn_rate = observed_error_ratio / (1 − SLO)
- burn rate = 1 แปลว่าเผา budget พอดีๆ ให้หมดเป๊ะเมื่อสิ้นหน้าต่าง SLO (30 วัน) — นี่คือ อัตราปกติที่ยอมรับได้
- burn rate = 2 เผาเร็วเป็นสองเท่า → budget หมดใน 15 วัน
- burn rate = 14.4 เผาเร็วมาก → budget 30 วันหมดใน ~2 วัน
เวลาที่ budget จะหมดคำนวณตรงๆ: time_to_exhaust = SLO_window / burn_rate (30 วัน ÷ 14.4 ≈ 2 วัน)
แปลงกลับเป็น error ratio ที่ต้องเห็นเพื่อให้ burn rate ถึงเกณฑ์: สำหรับ SLO 99.9% (1 − SLO = 0.001) burn rate 14.4 = observed error ratio 1.44%, burn rate 6 = 0.6%, burn rate 1 = 0.1% ตัวเลขเหล่านี้คือสิ่งที่ query ของ HyperDX จะวัดจริง
ตาราง multi-window multi-burn-rate (คัดลอกไปใช้ได้เลย)
หัวข้อที่มีชื่อว่า “ตาราง multi-window multi-burn-rate (คัดลอกไปใช้ได้เลย)”ปัญหาของ alert แบบหน้าต่างเดียว: หน้าต่างสั้น (5 นาที) ไว แต่ เสียงดัง — spike ชั่วครู่ก็ปลุกคุณ; หน้าต่างยาว (6 ชม.) เงียบ แต่ ช้า — กว่าจะรู้ก็สายไป SRE Workbook แก้ด้วย multi-window multi-burn-rate: fire ต่อเมื่อ ทั้งสองหน้าต่าง (ยาว + สั้น) เกินเกณฑ์พร้อมกัน หน้าต่างยาวกันของปลอม หน้าต่างสั้นยืนยันว่ายัง burn อยู่ ตอนนี้ (ไม่ใช่จบไปแล้ว) กฎ: หน้าต่างสั้น = 1/12 ของหน้าต่างยาว
ตารางมาตรฐานสำหรับ SLO 99.9%, หน้าต่าง 30 วัน (คัดลอกทั้งแถว เปลี่ยนแค่ค่า SLO ถ้า SLO ต่าง) (S42):
| Burn rate | หน้าต่างยาว + สั้น | budget ที่ถูกเผา | การแจ้งเตือน |
|---|---|---|---|
| 14.4 | 1 ชม. + 5 นาที | 2% | Page (ปลุกคน) |
| 6 | 6 ชม. + 30 นาที | 5% | Page (ปลุกคน) |
| 1 | 3 วัน + 6 ชม. | 10% | Ticket (เปิด ticket) |
ตรวจเลขให้เห็นว่าไม่ได้เสก: budget ที่ถูกเผา = burn_rate × (window / 30วัน) → แถวแรก 14.4 × (1ชม. / 720ชม.) = 2% ✓ · แถวสอง 6 × (6 / 720) = 5% ✓ · แถวสาม 1 × (72 / 720) = 10% ✓ ยิ่งเผาไว (14.4) ยิ่งกินสัดส่วน budget น้อยแต่อันตรายเฉียบพลัน → ปลุกคนทันที; เผาช้า (1) แต่กินไปแล้ว 10% → ไม่ต้องปลุก แต่ต้องมีคนดูใน ชม.ทำการ (ticket)
flowchart TD
SLI["SLI: สัดส่วนคำขอวางออเดอร์สำเร็จ<br/>(วัดจาก otel_traces)"] --> SLO["SLO: 99.9% ใน 30 วัน"]
SLO --> EB["Error Budget = 100% − SLO<br/>= 43.2 นาที / ~3,000 คำขอ"]
EB --> BR{"Burn rate ตอนนี้?<br/>= error_ratio / 0.001"}
BR -->|"14.4 · 1ชม.+5น. · เผา 2%"| PAGE["PAGE — ปลุก on-call"]
BR -->|"6 · 6ชม.+30น. · เผา 5%"| PAGE
BR -->|"1 · 3วัน+6ชม. · เผา 10%"| TICKET["TICKET — ดูใน ชม.ทำการ"]
BR -->|"< 1 · เผาช้ากว่าปกติ"| OK["ไม่ต้องแจ้ง — budget ยังพอ"]
CAUSE["version ดิบ: CPU 92%, error 1 บรรทัด"] -.->|"ไม่โดนลูกค้า → เสียงรบกวน"| NOISE["ห้าม page<br/>(alert fatigue)"]
classDef good fill:#0e7490,stroke:#155e75,color:#f0fdff;
classDef warn fill:#b45309,stroke:#92400e,color:#fffbeb;
classDef bad fill:#1e293b,stroke:#0f172a,color:#94a3b8;
class SLI,SLO,EB,OK good;
class PAGE,TICKET warn;
class CAUSE,NOISE bad;
คำบรรยายภาพ: เส้นทางจาก SLI ที่วัดได้จริง สู่ SLO สู่ error budget สู่การตัดสินใจ page/ticket ตาม burn rate — 3 branch บนคือ symptom-based ที่ fire ตามความเร็วการเผา budget ส่วน branch เส้นประด้านล่างคือ cause-based (CPU สูง, error หนึ่งบรรทัด) ที่ไม่โดนลูกค้าจึงต้องถูกกันออกจากการ page เพื่อไม่ให้เกิด alert fatigue
เขียน alert จริงใน HyperDX (ClickHouse SQL — ไม่ใช่ PromQL)
หัวข้อที่มีชื่อว่า “เขียน alert จริงใน HyperDX (ClickHouse SQL — ไม่ใช่ PromQL)”HyperDX มี alert สองแบบ (S28):
- Search alert — นับจำนวน event ที่ match คำค้น (Lucene) ในหน้าต่างเวลา แล้ว fire เมื่อ จำนวน ข้าม threshold; ใส่ group-by ได้ เหมาะกับ “นับ dead-letter ที่โผล่มา”
- Chart / SQL alert — รัน ClickHouse SQL แบบ aggregate เต็มรูป แล้ว fire เมื่อ ค่าที่ query คืน ข้าม threshold; ตรรกะ anomaly ทั้งหมดอยู่ใน query เอง เหมาะกับ “คำนวณ burn rate สองหน้าต่าง”
threshold รองรับ >=, >, <=, <, =, !=; interval ตั้งได้ตั้งแต่ 1 นาที ถึง 1 วัน การแจ้งเตือนใน OSS ส่งผ่าน generic webhook (native Slack/PagerDuty เป็นของ ClickHouse Cloud เท่านั้น) — ต่อ webhook เข้า PagerDuty/Opsgenie/Slack ของคุณเอาเอง
ตาราง multi-window multi-burn-rate ต้นฉบับใน SRE Workbook เขียนเป็น PromQL (rate(...)[1h]) HyperDX/ClickStack ไม่ใช้ PromQL — มันเป็น ClickHouse SQL เราจึงต้องแปลตรรกะ “burn rate สองหน้าต่างต้องเกินพร้อมกัน” เป็น SQL เอง โครงสร้าง SQL ด้านล่างคำนวณ burn rate ทั้งหน้าต่างยาวและสั้นในคิวรีเดียวแล้วคืน least(...) เพื่อบังคับเงื่อนไข “ทั้งสองต้องเกิน” — แต่ รูปแบบการดึงค่าออกมาเทียบ threshold ของ HyperDX SQL alert ควรยืนยันกับ UI จริงอีกครั้ง (version alert engine อาจต่างในรายละเอียด) ใช้เป็นโครงตั้งต้น ไม่ใช่คำตอบตายตัว
Alert #1 — checkout p99 / availability burn rate (Chart / SQL alert, threshold >= 14.4): คำนวณ burn rate หน้าต่าง 1 ชม. และ 5 นาทีในคิวรีเดียว แล้วคืน least เพื่อให้ fire ต่อเมื่อ ทั้งสอง หน้าต่างเกิน
-- burn rate หน้ายาว(1ชม.) + สั้น(5น.) ของ Ordering intake; SLO 99.9% => (1 - SLO) = 0.001-- fire เมื่อค่าที่คืน >= 14.4 (เกณฑ์ page แถวแรกของตาราง)SELECT least( -- หน้าต่างยาว 1 ชม. countIf(StatusCode = 'Error') / nullIf(count(), 0) / 0.001, -- หน้าต่างสั้น 5 นาที countIf(StatusCode = 'Error' AND Timestamp >= now() - INTERVAL 5 MINUTE) / nullIf(countIf(Timestamp >= now() - INTERVAL 5 MINUTE), 0) / 0.001) AS burn_rateFROM otel_tracesWHERE ServiceName = 'ordering-service' AND SpanAttributes['http.route'] = '/orders' AND SpanKind = 'Server' AND Timestamp >= now() - INTERVAL 1 HOUR;เปลี่ยนแค่ threshold ในหน้าตั้ง alert เป็น >= 6 (คู่กับหน้าต่าง 6 ชม./30 น.) หรือ >= 1 (คู่กับ 3 วัน/6 ชม. แล้วส่งเป็น ticket แทน page) ก็ได้อีกสองแถวของตารางครบ
Alert #2 — Kitchen dead-letter queue โต (Search alert, count >= 1 ใน 5 นาที → Page): ออเดอร์ที่ integration-event handler ของ Kitchen ประมวลไม่ได้จะตกไป dead-letter — เป็นอาการที่ผู้ใช้เห็น (อาหารไม่เข้าครัว) จึงควร page
# Search alert (Lucene) — นับ dead-letter event ของ Kitchen ในหน้าต่าง 5 นาทีServiceName:kitchen-service SpanName:*dead-letter*# threshold: count >= 1 interval: 5m → webhook: PagerDutyDLQ depth เป็น metric (wolverine-dead-letter-queue จาก บท4) ก็ใช้ Chart/SQL alert บน otel_metrics_* เทียบ threshold ได้เช่นกัน — เลือกแบบที่ตรงกับสิ่งที่คุณ instrument ไว้จริง 2 alert นี้ตรงกับ Order hook พอดี: checkout burn rate (intake พังเร็ว) และ Kitchen DLQ โต (handler ค้าง)
อย่าขาย alert เกินจริง: SLO/burn-rate alert ที่ตั้งดีๆ ทำให้คุณ รู้เร็วขึ้น จึง ลด MTTR (mean time to recovery) — แต่มัน ไม่ป้องกัน incident จากการเกิด และไม่ซ่อมอะไรให้เอง เส้นเดียวกับที่ย้ำทั้งคอร์ส: alert (เหมือน dashboard, เหมือน filter) เป็นเครื่องมือ ลด ต้นทุนของเหตุ ไม่ใช่ กำจัด เหตุ คุณค่าที่แท้จริงอยู่ที่การเลือก alert บน อาการที่ผู้ใช้เห็น ไม่ใช่จำนวน alert ที่ตั้ง — alert 100 ตัวบนสาเหตุ แย่กว่า alert 3 ตัวบน SLO เพราะ 100 ตัวสอนให้คุณเลิกฟัง
สรุปก่อนไปต่อ
หัวข้อที่มีชื่อว่า “สรุปก่อนไปต่อ”การ alert ที่ดีไม่ใช่การจับทุกอย่างที่ “ดูแปลก” — มันคือการปลุกคนเฉพาะตอนที่ ผู้ใช้เจ็บจริง SLI คือตัวเลขที่วัด, SLO คือเป้าที่ตั้งทับ (99.9% ใน 30 วัน), SLA เพิ่มผลตามมาเชิงพาณิชย์ (ไม่มีผล = เป็น SLO); error budget = 100% − SLO แปลงเป็น 43.2 นาที หรือ ~3,000 คำขอที่พังได้ต่อ 30 วัน และ 100% เป็นเป้าที่ผิด; burn rate = observed_error_ratio / (1 − SLO) บอกว่าเผา budget เร็วแค่ไหน; ตาราง multi-window 14.4/6/1 fire ต่อเมื่อทั้งหน้าต่างยาวและสั้นเกินพร้อมกัน — page สองแถวบน, ticket แถวล่าง; และใน HyperDX เราเขียนมันเป็น ClickHouse SQL (ไม่ใช่ PromQL) ส่งผ่าน webhook เหนือสิ่งอื่นใด: alert ลด MTTR แต่ ไม่ลบ incident — เลือก alert บนอาการ ไม่ใช่สาเหตุ
บทหน้าเป็น capstone: เราจะ ฉีด ความพังจริงเข้าไปในระบบ (Delivery ช้า / outbox ค้างหลังแยก service) แล้วให้ alert ของบทนี้ fire → ไล่จาก metric → trace → log จนถึงต้นเหตุ พร้อมเรื่อง sampling กับต้นทุนที่ยั่งยืนตอน scale — เอาสามสัญญาณที่ instrument มาทั้งคอร์สมาขับ incident จริงหนึ่งรอบให้จบ
บทนี้อิงต้นทางที่ลงวันที่กำกับ อ่านต่อได้โดยตรง:
- Google SRE Book Ch.4 — Service Level Objectives (2016) — นิยาม SLI/SLO/SLA คำต่อคำ: SLI = “a carefully defined quantitative measure of some aspect of the level of service”, SLO = “a target value or range of values for a service level that is measured by an SLI”, SLA เพิ่ม consequences
- Google SRE Book Ch.3 — Embracing Risk (2016) — ทำไม 100% เป็นเป้าที่ผิด และเลข nines / error budget เชิงเวลา
- Google SRE Workbook Ch.2 — Implementing SLOs (2018) — error budget = 100% − SLO และตัวอย่าง 3,000-error
- Google SRE Workbook Ch.5 — Alerting on SLOs (2018) — multi-window multi-burn-rate; ตาราง 14.4 / 6 / 1 (2%/5%/10%) — ต้นฉบับเป็น PromQL
- ClickStack — Alerts (เข้าถึง 2026-07-22) — Search vs Chart/SQL alert, threshold
>=,>,<=,<,=,!=, interval 1m…1d, webhook ใน OSS (Slack/PagerDuty native เฉพาะ Cloud) - ClickHouse blog — ClickStack SQL charting and alerting (2025) — เขียน alert ด้วย ClickHouse SQL, macro
$__filters/$__sourceTable
เช็กความเข้าใจ — บทที่ 7
ข้อ 1 / 3ทีมตั้งเป้าว่า '99.9% ของคำขอวางออเดอร์ต้องสำเร็จใน 30 วัน' แต่ไม่มีสัญญาคืนเงิน/ชดเชยเขียนไว้ถ้าพลาด — ตามนิยาม SRE นี่คืออะไร?