การวิเคราะห์หลังเหตุขัดข้องของ Cloudflare เมื่อวันที่ 18 พฤศจิกายน 2025
(blog.cloudflare.com)- เมื่อเวลา 11:20 น. (UTC) ของวันที่ 18 พฤศจิกายน 2025 ฟังก์ชันหลักในการส่งต่อทราฟฟิกของเครือข่าย Cloudflare หยุดทำงาน ทำให้ผู้ใช้ทั่วโลกเห็นหน้าแสดงข้อผิดพลาด
- สาเหตุคือ ไฟล์
featureของระบบ Bot Management มีขนาดใหญ่ผิดปกติจากการเปลี่ยนสิทธิ์ของฐานข้อมูล และไม่เกี่ยวข้องกับการโจมตีทางไซเบอร์ - การเพิ่มขึ้นของขนาดไฟล์นี้ทำให้ ซอฟต์แวร์กำหนดเส้นทางทราฟฟิกทำงานล้มเหลวเพราะเกินค่าขีดจำกัด ส่งผลให้เกิดข้อผิดพลาด HTTP 5xx ในวงกว้าง
- ราว 14:30 น. ได้หยุดการปล่อยไฟล์ที่มีปัญหาและแทนที่ด้วยเวอร์ชันก่อนหน้าที่ปกติ ทำให้ ทราฟฟิกหลักกลับมาใช้งานได้ และทุกบริการกลับสู่ภาวะปกติในเวลา 17:06 น.
- Cloudflare ประเมินเหตุการณ์นี้ว่าเป็น เหตุขัดข้องที่ร้ายแรงที่สุดนับตั้งแต่ปี 2019 และกำลังผลักดันมาตรการป้องกันการเกิดซ้ำ เช่น การเพิ่มความเข้มงวดในการตรวจสอบไฟล์คอนฟิกและการเพิ่ม global kill switch
ภาพรวมของเหตุขัดข้อง
- ราว 11:20 น. เกิด ความล้มเหลวในการส่งต่อทราฟฟิกหลัก บนเครือข่าย Cloudflare และผู้ใช้พบหน้าแสดงข้อผิดพลาดภายในของ Cloudflare
- ไม่ใช่ผลจากการโจมตีทางไซเบอร์หรือการกระทำที่เป็นอันตราย โดยสาเหตุโดยตรงคือการเปลี่ยนสิทธิ์ในระบบฐานข้อมูล
- การเปลี่ยนแปลงดังกล่าวทำให้ ขนาดของไฟล์
featureที่ระบบ Bot Management ใช้งาน เพิ่มขึ้นเป็นสองเท่า และถูกกระจายไปทั่วทั้งเครือข่าย - ระหว่างที่ซอฟต์แวร์กำหนดเส้นทางทราฟฟิกอ่านไฟล์นี้ ได้ เกินข้อจำกัดด้านขนาดไฟล์ จนเกิดข้อผิดพลาดของระบบ
- ในช่วงแรกถูกเข้าใจผิดว่าเป็นการโจมตี DDoS ขนาดใหญ่ แต่หลังจากระบุสาเหตุได้แล้วจึง เปลี่ยนกลับไปใช้ไฟล์เวอร์ชันปกติก่อนหน้า เพื่อกู้คืนระบบ
ลำดับเหตุการณ์และผลกระทบ
- ก่อนเวลา 11:20 อัตราข้อผิดพลาด 5xx อยู่ในระดับปกติ แต่หลังจากนั้น การปล่อยไฟล์ feature ที่ผิดพลาดทำให้ข้อผิดพลาดพุ่งสูงขึ้น
- บนบางโหนดของคลัสเตอร์ฐานข้อมูล ClickHouse มี ผลลัพธ์คิวรีที่ผิดพลาดถูกสร้างทุก ๆ 5 นาที ทำให้ไฟล์ปกติและไฟล์ผิดปกติถูกปล่อยสลับกัน และระบบจึงวนซ้ำระหว่างการฟื้นตัวกับการล้มเหลว
- ตั้งแต่ 14:30 น. ได้หยุดการสร้างไฟล์ที่มีปัญหาและ ใส่ไฟล์ที่ถูกต้องด้วยตนเอง จากนั้นกู้คืนด้วยการรีสตาร์ต core proxy
- ทุกบริการกลับสู่ภาวะปกติในเวลา 17:06 น.
| บริการ | รายละเอียดผลกระทบ |
|---|---|
| Core CDN และบริการด้านความปลอดภัย | เกิดข้อผิดพลาด HTTP 5xx |
| Turnstile | โหลดไม่สำเร็จ ทำให้ล็อกอินไม่ได้ |
| Workers KV | ความล้มเหลวของเกตเวย์ทำให้ข้อผิดพลาด 5xx เพิ่มสูงขึ้น |
| Dashboard | ล็อกอินไม่ได้เนื่องจาก Turnstile ขัดข้อง |
| Email Security | ความแม่นยำในการตรวจจับสแปมลดลงชั่วคราว และการย้ายอัตโนมัติบางส่วนล้มเหลว |
| Access | เกิดความล้มเหลวในการยืนยันตัวตนจำนวนมาก แต่เซสชันเดิมยังคงอยู่ |
- ระหว่างช่วงเหตุขัดข้อง ค่า latency ของการตอบสนองจาก CDN เพิ่มขึ้น โดยมีสาเหตุจากการใช้งาน CPU ของระบบดีบักที่พุ่งสูงขึ้น
สาเหตุของเหตุขัดข้อง: ระบบ Bot Management
- โมดูล Bot Management ของ Cloudflare ใช้โมเดลแมชชีนเลิร์นนิงเพื่อสร้างคะแนนบอตสำหรับแต่ละคำขอ
- ไฟล์คอนฟิก feature ที่ใช้เป็นอินพุตของโมเดลจะถูกปล่อยไปยังทั้งเครือข่ายทุก ๆ ไม่กี่นาทีเพื่อรับมือกับภัยคุกคามล่าสุด
- จากการเปลี่ยนพฤติกรรมของคิวรี ClickHouse ทำให้ มีแถว feature ที่ซ้ำกันจำนวนมาก และขนาดไฟล์เพิ่มขึ้น
- ส่งผลให้โมดูล Bot Management เกิดข้อผิดพลาดและ ส่งคืนการตอบสนอง HTTP 5xx อีกทั้งยังกระทบต่อ Workers KV และ Access
- บนเอนจินพร็อกซีรุ่นใหม่ FL2 เกิดข้อผิดพลาด 5xx ส่วนบน FL รุ่นเก่า คะแนนบอตถูกตั้งเป็น 0 ทำให้ false positive เพิ่มขึ้น
การเปลี่ยนพฤติกรรมของคิวรี ClickHouse
- เวลา 11:05 น. มีการปล่อย การเปลี่ยนสิทธิ์การเข้าถึงฐานข้อมูล ของ ClickHouse
- เดิมสามารถดูได้เฉพาะเมทาดาทาของฐานข้อมูล
defaultแต่หลังการเปลี่ยนแปลง เมทาดาทาของฐานข้อมูลr0ก็ถูกเปิดเผยด้วย - คิวรีสำหรับสร้างไฟล์ feature ของ Bot Management ทำงานโดยไม่มีตัวกรองชื่อฐานข้อมูล ส่งผลให้ มีการคืนค่าคอลัมน์ซ้ำ
- ด้วยเหตุนี้จำนวนแถวในไฟล์ feature จึงเพิ่มขึ้นมากกว่าสองเท่าและเกินขีดจำกัดของระบบ
การจัดสรรหน่วยความจำล่วงหน้าและ system panic
- โมดูล Bot Management มีการ จำกัดจำนวนแมชชีนเลิร์นนิง feature สูงสุดไว้ที่ 200 รายการ และจัดสรรหน่วยความจำล่วงหน้า
- เมื่อไฟล์ที่ผิดพลาดมี feature เกิน 200 รายการ จึงเกิด panic ในโค้ด Rust พร้อมแสดงข้อผิดพลาด
thread fl2_worker_thread panicked: called Result::unwrap() on an Err value - ทำให้ เกิดข้อผิดพลาด HTTP 5xx จำนวนมาก
ผลกระทบอื่น ๆ และกระบวนการกู้คืน
- Workers KV และ Access พึ่งพา core proxy ทำให้ผลกระทบจากเหตุขัดข้องขยายวงกว้าง
- เวลา 13:04 น. Workers KV ถูกแพตช์ให้ข้ามพร็อกซี ทำให้อัตราข้อผิดพลาดลดลง
- Dashboard ไม่สามารถล็อกอินได้เนื่องจากพึ่งพา Turnstile และ Workers KV
- ความพร้อมใช้งานลดลงสองช่วงคือ 11:30–13:10 และ 14:40–15:30
- จาก backlog และคำขอ retry ทำให้ค่า latency เพิ่มขึ้น ก่อนจะกู้คืนได้ราว 15:30 น.
- หลัง 14:30 น. บริการส่วนใหญ่กลับมาเป็นปกติ และกู้คืนสมบูรณ์ในเวลา 17:06 น.
มาตรการป้องกันการเกิดซ้ำ
- เพิ่มความเข้มงวดในการตรวจสอบอินพุตของไฟล์คอนฟิกที่ Cloudflare สร้างขึ้น
- ขยายการใช้ global kill switch
- ป้องกันการใช้ทรัพยากรระบบจนหมดจากการรายงานข้อผิดพลาด
- ทบทวนเงื่อนไขข้อผิดพลาดในโมดูล core proxy ทั้งหมด
สรุปไทม์ไลน์ (UTC)
| เวลา | สถานะ | คำอธิบาย |
|---|---|---|
| 11:05 | ปกติ | ปล่อยการเปลี่ยนแปลงการควบคุมการเข้าถึงฐานข้อมูล |
| 11:28 | เริ่มได้รับผลกระทบ | เกิดข้อผิดพลาดครั้งแรกบนทราฟฟิกของลูกค้า |
| 11:32–13:05 | อยู่ระหว่างตรวจสอบ | วิเคราะห์สาเหตุของข้อผิดพลาดใน Workers KV และพยายามบรรเทาผลกระทบ |
| 13:05 | ผลกระทบลดลง | ใช้มาตรการ bypass สำหรับ Workers KV และ Access |
| 13:37 | เร่งดำเนินการกู้คืน | เตรียม rollback ไฟล์คอนฟิกของ Bot Management |
| 14:24 | หยุดปล่อยไฟล์ที่มีปัญหา | ทดสอบไฟล์ปกติเสร็จสิ้น |
| 14:30 | ผลกระทบหลักคลี่คลาย | ปล่อยไฟล์ปกติทั่วโลกและเริ่มกู้คืนบริการ |
| 17:06 | กู้คืนสมบูรณ์ | ทุกบริการกลับสู่ภาวะปกติเรียบร้อย |
บทสรุป
- เหตุขัดข้องครั้งนี้เกิดจาก ปฏิสัมพันธ์ระหว่างตรรกะการสร้างไฟล์คอนฟิกของ Bot Management กับการเปลี่ยนสิทธิ์ฐานข้อมูล
- Cloudflare ประเมินว่านี่คือ การหยุดชะงักของเครือข่ายที่ร้ายแรงที่สุดนับตั้งแต่ปี 2019
- ในอนาคตจะผลักดันการปรับปรุงเชิงโครงสร้างและการเสริมระบบป้องกันอัตโนมัติเพื่อเพิ่มความทนทานของระบบ
8 ความคิดเห็น
ปัญหาที่เกี่ยวกับไฟล์คอนฟิกเกิดขึ้นได้ทุกที่เลยนะ
พอ Cloudflare ใช้งานไม่ได้ บริการสารพัดก็หยุดชะงักไปหมด เหมือนนรกเลย..
เอกสารวิเคราะห์สาเหตุถูกเผยแพร่ออกมาค่อนข้างเร็วเลยนะเนี่ย หุหุ
ว่าแต่คนเขียนบทความนี้คือ CEO เองนี่นะ
ความคิดเห็นจาก Hacker News
นี่คือเรื่องราวอุบัติเหตุจาก .unwrap() ที่มูลค่าความเสียหายระดับหลายล้านดอลลาร์
การเรียก
.unwrap()บนเส้นทางโครงสร้างพื้นฐานหลักของอินเทอร์เน็ต ก็แทบเท่ากับการประกาศว่า “มันจะไม่มีวันล้มเหลว และถ้าล้มเหลวก็ให้ฆ่าเธรดนั้นทิ้งทันที”Rust compiler บังคับให้แสดงความเป็นไปได้ของความล้มเหลวอย่างชัดเจน แต่ที่นี่กลับเลือก panic แทนการจัดการอย่างเหมาะสม
คิดว่านี่เป็นตัวอย่างคลาสสิกของ anti-pattern แบบ parse, don’t validate
.unwrap()อาจเป็นเพราะมันโผล่ในโค้ดตัวอย่างบ่อยในโค้ดที่ใช้งานจริง ควรรีวิว
.unwrap()หรือ.expect()เหมือนกับการรีวิว panicถ้าจะใช้
.unwrap()ในโปรดักชัน ก็ควรต้องมีคอมเมนต์ “INFALLIBILITY” กำกับไว้เสมอ และบังคับใช้ได้ด้วยclippy::unwrap_usedไม่ใช่แค่
.unwrap()อย่างเดียว แต่ยังมีการที่ query ไม่แยกฐานข้อมูล ทำให้ payload ใหญ่ขึ้น และ ClickHouse ก็เปิดเผยฐานข้อมูลเพิ่มขึ้นด้วยแทนที่จะสรุปง่ายๆ ว่า “เป็นเพราะ unwrap” ผมคิดว่าการปรับปรุงดีไซน์เพื่อไม่ให้ global kill switch หรือการใช้ทรัพยากรของระบบเกินขนาดนั้นสำคัญกว่า
ควรดักจับ panic ของแต่ละคอมโพเนนต์ที่เลเยอร์ FL2 แต่ fail-open ก็ไม่ได้ดีกว่าเสมอไป
ควรเพิ่มตรรกะให้สามารถตัดสินใจอย่างชัดเจนที่ระดับ FL2 ว่าจะดักจับ panic แล้วจัดการต่อหรือไม่
ถ้าเป็น ระบบแบบ sharded ก็สงสัยเหมือนกันว่าทำไมถึงไม่มีการ rollout แบบค่อยเป็นค่อยไปและการมอนิเตอร์
!และแบบชัดเจน?ผมแทบไม่ใช้การ unwrap แบบปริยายเลย ต่อให้เป็นค่าที่รับประกันได้ก็ยังจัดการแบบชัดเจนเสมอ
เช่นกำหนด
@IBOutlet weak var someView?แทน@IBOutlet weak var someView!เป็นแนวทางแบบ belt & suspenders
การเผยแพร่ post mortem ภายในไม่ถึง 24 ชั่วโมงหลังเหตุขัดข้องเป็นเรื่องที่น่าทึ่งจริงๆ
ถ้าเป็นบริษัทยักษ์ใหญ่ส่วนมาก คงแทบเป็นไปไม่ได้ที่จะเผยแพร่โค้ด เพราะต้องผ่านการตรวจจาก stakeholder หลายฝ่าย
ตอนอ่านคำอธิบายเหตุขัดข้องของ Cloudflare ก็สงสัยว่า “ทำไมกว่าจะกู้คืนได้ถึงใช้เวลานานขนาดนั้น”
เข้าใจสาเหตุของปัญหาแล้ว แต่ถ้าเครือข่ายส่วนใหญ่ล่มไปหมด มันไม่ควรเป็นลำดับแรกหรือที่จะ ย้อนการเปลี่ยนแปลงคอนฟิกล่าสุดกลับไป
แน่นอนว่าพอมองย้อนหลังมันชัดเจน แต่การเริ่มสืบสวนได้ภายใน 7 นาทีก็น่าประทับใจ
เหตุการณ์นี้ให้ความรู้สึกคล้ายกับ เหตุการณ์ CrowdStrike
ไฟล์คอนฟิกที่สร้างอัตโนมัติทำให้ซอฟต์แวร์พัง และแพร่กระจายไปทั้งเครือข่าย
เข้าใจว่าจำเป็นต้อง deploy เร็ว แต่ครั้งนี้ก็เผยให้เห็นการขาด กลยุทธ์ rollout แบบค่อยเป็นค่อยไปและ rollback
ถ้าดูแผนการปรับปรุงในอนาคตที่ Cloudflare ประกาศ
มีสิ่งเหล่านี้อยู่
แต่กลับไม่มี canary deployment หรือการปล่อยคอนฟิกแบบค่อยเป็นค่อยไป
global switch อาจมีความเสี่ยง และบั๊กเพียงตัวเดียวก็อาจหยุดทั้งระบบได้
ก็ยังสงสัยว่าทำไมถึงใช้ ClickHouse เป็น feature flag store ด้วย เอกสาร ClickHouse deduplication เองก็พูดถึงความเสี่ยงอยู่
ถ้ามี การทำแผนที่ dependency ระหว่างบริการ การไล่หาต้นเหตุคงง่ายขึ้นมาก
การ deploy โค้ดนั้นระมัดระวัง แต่การ deploy คอนฟิกกลับไม่ใช่ จำเป็นต้องมองว่าคอนฟิกก็คือโค้ด
ประเด็นที่หน้าสถานะล่มด้วยจนทำให้เข้าใจผิดว่าเป็นการโจมตีนั้นน่าสนใจ
เขาบอกว่าแยกจากโครงสร้างพื้นฐานของ Cloudflare อย่างสิ้นเชิง แต่ไม่มีคำอธิบายว่าทำไมถึงล่มตามกัน
ผมรวม Turnstile เข้ากับระบบด้วยกลยุทธ์ fail-open และมันช่วยได้ในเหตุขัดข้องครั้งนี้
ถ้า JS โหลดไม่ขึ้น ก็ให้ส่งด้วยโทเคนหลอก และแม้การตรวจสอบฝั่งแบ็กเอนด์จะล้มเหลวก็ยังจัดการแบบ fail-open
ผู้ใช้บางส่วนยังคงถูกบล็อกอยู่ แต่ผลกระทบโดยรวมลดลง
แนวทางนี้ทำได้เพราะมี มาตรการบรรเทาบอต แบบอื่นร่วมอยู่ด้วย
แต่ดูเหมือนว่านี่จะใช้ได้ เฉพาะตอนที่ไม่ใช่การโจมตีแบบเจาะจงเป้าหมาย เท่านั้น
สงสัยว่าทำไมถึงอนุญาตให้มี
.unwrap()อยู่ในโค้ดของ Cloudflareอย่างน้อยก็ควรใช้
expect("สิ่งนี้ไม่มีทางเกิดขึ้น")ปรัชญาที่มอง error เป็นค่า ก็มีไว้เพื่อป้องกันปัญหาแบบนี้ และมันน่าจะช่วยให้วินิจฉัยได้ง่ายกว่ามาก
ในโค้ดที่มี network call มีความเป็นไปได้ที่จะล้มเหลวมากเกินไป
ตอนพัฒนาผมใช้
.unwrap()แต่ในโปรดักชันก็มักปล่อย expect() ไว้เหมือนกัน เพราะบางครั้งมันก็ไม่มีทางเดินต่อจริงๆบทเรียนที่แท้จริงคือ ฟีเจอร์จำนวนมากเกินไปกำลังพึ่งพา ผู้เล่นเพียงไม่กี่ราย
โครงสร้างแบบผู้ชนะกินรวบกำลังรุนแรงขึ้นและทำให้ ความยืดหยุ่น ของระบบลดลง
แน่นอนว่าพวกเขามาถึงจุดนี้ได้ด้วยความสามารถ แต่ก็ดูจะมากเกินไปหากคาดหวังว่าอินเทอร์เน็ตจะ “ทำงานได้ปกติ” ตลอดเวลา
คำพูดที่ว่า “ถ้าเป็น Rust ก็ปลอดภัยหมด” นั้นเกินจริง
ไม่ว่าภาษาไหน ถ้าใช้ผิดก็ไม่ต่างจาก เอาปากกระบอกปืนเล็งใส่เท้าตัวเอง
แม้แต่บริษัทระดับ Cloudflare ก็ยังใช้
.unwrap()กันเลยนะ ตะลึงโค้ดนั้นหลุดไปใช้ในโปรดักชันได้ยังไงเนี่ย
ดูเหมือนว่าปัญหาจะไม่ใช่
unwrapปัญหาที่เป็นต้นเหตุจริง ๆ คือคิวรีที่ผิดพลาด
แต่ผมก็คิดว่าการข้ามการตรวจสอบปัญหาด้วย
unwrapก็เป็นปัญหาเหมือนกันถึงภายในจะเกิดปัญหาขึ้น อย่างน้อยถ้ามีการจัดการข้อผิดพลาดก็คงไม่ถึงขั้นทำให้ทราฟฟิกล่ม