ถ้าคุณคิดว่าการแข่งขันฟุตบอลระหว่าง ตุรกี พบ ฝรั่งเศส เป็นเพียงเหตุการณ์กีฬา 90 นาที คุณอาจมองข้ามปัญหาทางวิศวกรรมที่ใหญ่ที่สุดอย่างหนึ่งของแพลตฟอร์มสตรีมมิ่งข้อมูลเรียลไทม์ไปโดยสิ้นเชิง แมตช์ระดับนานาชาติแบบนี้ไม่ได้สร้างแค่เสียงเชียร์ในสนาม แต่มันสร้างอีเวนต์ดิจิทัลหลายล้านรายการต่อนาที ตั้งแต่การเปลี่ยนคะแนน การเปลี่ยนตัว ใบเหลือง ไปจนถึงตำแหน่งของผู้เล่นจากระบบ tracking กล้องความละเอียดสูง

ในฐานะทีมวิศวกรที่เคยออกแบบระบบถ่ายทอดข้อมูลสดให้กับแพลตฟอร์มกีฬา เรามักใช้แมตช์อย่าง ตุรกี พบ ฝรั่งเศส เป็นโจทย์ทดสอบระบบในสภาพโหลดจริง สิ่งที่เราเรียนรู้จากการรัน production ไม่ใช่แค่ทฤษฎีในตำรา แต่คือการตัดสินใจเชิงสถาปัตยกรรมที่แยกแพลตฟอร์มที่รอดจากแพลตฟอร์มที่ล่มกลางการแข่งขัน

การแข่งขัน ตุรกี พบ ฝรั่งเศส หนึ่งแมตช์สามารถสร้างอีเวนต์สตรีมมากกว่า 2 ล้านรายการต่อนาที ถ้าระบบของคุณออกแบบมาไม่ดี มันจะล่มก่อนนกหวีดเริ่มด้วยซ้ำ บทความนี้จะพาคุณลงลึกถึงการออกแบบระบบวิเคราะห์ข้อมูลฟุตบอลแบบ real-time ผ่านกรณีศึกษาแมตช์นี้ โดยไม่ต้องรอให้ทีมคุณเจอปัญหาในคืนวันแข่งจริง

ทำไมแมตช์ ตุรกี พบ ฝรั่งเศส ถึงเป็นโจทย์วิศวกรรมข้อมูลระดับสูง

แมตช์ระหว่างทีมชาติตุรกีและฝรั่งเศสมีผู้ชมพร้อมกันหลายล้านคนทั่วโลก แพลตฟอร์มที่รายงานผลสดต้องรองรับการเชื่อมต่อ WebSocket จำนวนมากที่เปิดค้างไว้ตลอด 90 นาที แต่ละ connection ไม่ได้ร้องขอข้อมูลแค่ครั้งเดียว แต่รอรับ push notification ทุกครั้งที่มีอีเวนต์ใหม่เกิดขึ้น ปัญหาที่ตามมาคือ fan-out pattern แบบ 1:N ที่ต้องส่งข้อความเดียวกันให้กับผู้รับหลายล้านรายโดยไม่ทำให้เกิด head-of-line blocking

สิ่งที่ทำให้โจทย์นี้ยากกว่าแอปพลิเคชันทั่วไปคือความผันผวนของทราฟฟิกไม่ได้ค่อยเป็นค่อยไป แต่มาเป็นคลื่นแบบ spike เช่น ช่วงได้ประตูหรือช่วงทดเวลาบาดเจ็บ หากระบบไม่ถูกออกแบบด้วยหลัก backpressure และ circuit breaker ตั้งแต่แรก ปริมาณ message ที่พุ่งขึ้น 20 เท่าภายใน 5 วินาทีจะทำให้ queue ล้นและเกิด cascade failure อย่างรวดเร็ว

นอกจากนี้ ข้อมูลจากสนามไม่ได้มาจากแหล่งเดียว แต่มาจากผู้รวบรวมข้อมูลหลายราย เช่น ผู้บันทึกอีเวนต์ในสนาม ระบบ VAR และเซ็นเซอร์ติดตามผู้เล่น ซึ่งแต่ละแหล่งมี timestamp และรูปแบบข้อมูลที่ต่างกัน การรวมข้อมูลเหล่านี้ให้เป็น single source of truth ก่อนกระจายออกไป เป็นเรื่องที่ต้องออกแบบอย่างรอบคอบ หากทำผิดพลาด ผู้ใช้จะเห็นสกอร์ไม่ตรงกับจอถ่ายทอดสดและหมดความเชื่อถือทันที

สถาปัตยกรรมอีเวนต์ไดรฟ์เวนสำหรับการรายงานผลสดแบบเรียลไทม์

เราเลือกใช้สถาปัตยกรรม event-driven ที่มี Apache Kafka เป็น backbone หลักสำหรับแมตช์ ตุรกี พบ ฝรั่งเศส ทุกอีเวนต์จากสนาม เช่น การทำประตู การฟาวล์ หรือการเปลี่ยนตัว จะถูก publish เข้า topic ที่แยกตามประเภทของข้อมูล ตัวอย่างเช่น match-events raw, match-events normalized และ match-events audit การแยก topic แบบนี้ช่วยให้ทีม data science และทีม operations สามารถ consume ข้อมูลคนละ layer ได้โดยไม่กระทบกัน

การเลือก Kafka แทน message queue ทั่วไป เพราะเราต้องการคุณสมบัติ replayability และ log compaction เมื่อเกิดข้อผิดพลาดในการประมวลผล เราสามารถย้อนกลับไปอ่าน event จาก offset เดิมได้โดยไม่ต้องร้องขอข้อมูลจากต้นทางอีกครั้ง ซึ่งเป็นหลักการเดียวกับที่อธิบายไว้ใน เอกสารอย่างเป็นทางการของ Apache Kafka เรื่อง distributed log และ fault tolerance

ในทางปฏิบัติ เรา deploy Kafka cluster ขนาด 6 โบรกเกอร์สำหรับแพลตฟอร์มกีฬาหนึ่งลีก โดยตั้งค่า replication factor เป็น 3 และ min insync replicas เป็น 2 เพื่อให้ระบบยังทำงานต่อได้เมื่อมีโบรกเกอร์ล่มหนึ่งตัวระหว่างการแข่งขัน การตั้งค่านี้ช่วยให้เราไม่เคยเสียอีเวนต์สำคัญแม้แต่ครั้งเดียวในหลายฤดูกาลที่ผ่านมา

การออกแบบสคีมาข้อมูลการแข่งขันที่รองรับหลายลีกและหลายภาษา

หนึ่งในความผิดพลาดที่ทีมวิศวกรรมมักทำคือการออกแบบ schema ของอีเวนต์ฟุตบอลผูกกับภาษาใดภาษาหนึ่ง เช่น เก็บเฉพาะคำว่า "Goal" หรือ "ประตู" ไว้ใน payload โดยตรง เราเรียนรู้จากแมตช์ที่มีผู้ชมหลากหลายภาษาแบบ ตุรกี พบ ฝรั่งเศส ว่าควรเก็บเฉพาะรหัสเหตุการณ์ที่เป็นมาตรฐาน เช่น event_type: 1 สำหรับ goal และ event_type: 3 สำหรับ yellow card แล้วให้ frontend เป็นฝ่าย map รหัสไปยังข้อความภาษาท้องถิ่น

เรากำหนด schema ด้วย Apache Avro และใช้ Schema Registry เพื่อบังคับ compatibility ระหว่าง producer และ consumer version ต่าง ๆ การเปลี่ยน field โดยไม่ทำลาย backward compatibility เป็นเรื่องสำคัญ เพราะระหว่างการแข่งขัน เราไม่สามารถขอให้แอปผู้ใช้ทุกคนอัปเดตเวอร์ชันพร้อมกันได้ หาก schema เปลี่ยนแบบ breaking change จะทำให้ consumer บางราย decode payload ไม่ได้และผู้ใช้เห็นหน้าจอค้าง

นอกจากนี้ เรายังออกแบบให้ payload ทุกตัวมี event_id แบบ UUID v7 และ timestamp แบบ UTC โดยไม่ใช้เวลาท้องถิ่นของประเทศใดประเทศหนึ่ง สิ่งนี้สำคัญมากเมื่อตุรกีและฝรั่งเศสมี time zone ต่างกัน และผู้ชมจากเอเชียตะวันออกเฉียงใต้อย่างไทยต้องเห็นเวลาที่ถูกต้องตรงกับรอบอกของตน การใช้ UTC ภายในระบบแล้วแปลงที่ client เป็นแนวทางที่ลดความสับสนได้ดีที่สุด

เทคนิค Fan-out และการจัดการ WebSocket Connection ที่สเกลหลักล้าน

เมื่อมีผู้ใช้เชื่อมต่อเข้ามารับสกอร์สดของแมตช์ ตุรกี พบ ฝรั่งเศส พร้อมกัน 800,000 ราย เราไม่สามารถให้ Kafka consumer ตัวเดียวเป็นคนคอยส่งข้อความให้ทุกคนได้ เพราะจะเกิดคอขวดที่ connection เดียวและ memory ระเบิด เราเลือกใช้แนวทางแบบ tiered fan-out โดยให้ Kafka consumer กลุ่มหนึ่งอ่านจาก topic แล้ว publish เข้าสู่ Redis Pub/Sub หรือ NATS JetStream ตามโซนภูมิภาค

WebSocket gateway แต่ละตัวจะเปิด connection ค้างไว้กับผู้ใช้ประมาณ 50,000 ราย และรับ message จาก Redis channel ท

.

Need a Custom App Built?

Let's discuss your project and bring your ideas to life.

Contact Me Today →

Back to Online Trends