2 คะแนน โดย darjeeling 1 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

แชร์กระบวนการจำลองและแก้ไขบั๊ก race condition ของ KV Cache สองกรณี รวมถึงการปรับแต่งเพื่อเพิ่ม throughput ที่พบระหว่างให้บริการ Coding Agent บน GLM-5 ในระดับหลายร้อยล้านคำขอต่อวัน

ภูมิหลัง

กฎการสเกล (Scaling Laws) ไม่ได้ผลักดันแค่นวัตกรรมด้านพารามิเตอร์โมเดลและขนาดข้อมูลเท่านั้น แต่ยังผลักวิศวกรรมโครงสร้างพื้นฐานไปจนสุดขีดด้วย Z.ai เรียกผลข้างเคียงที่เกิดขึ้นในกระบวนการนี้ว่า Scaling Pain

ระหว่างประมวลผลเวิร์กโหลด Coding Agent ที่ซับซ้อนด้วยซีรีส์ GLM-5 ในระดับหลายร้อยล้านครั้งต่อวัน มีผู้ใช้บางส่วนรายงานอาการผิดปกติ เช่น เอาต์พุตเพี้ยน (garbled output), การสร้างซ้ำ, การสร้างอักขระหายาก ปัญหาเหล่านี้ไม่สามารถจำลองได้เลยในสภาพแวดล้อมการอนุมานมาตรฐาน และเกิดขึ้นเฉพาะในสภาพแวดล้อมที่มี การทำงานพร้อมกันสูงและบริบทยาวมาก เท่านั้น


สรุปผลลัพธ์สำคัญ

รายการ ตัวเลข
สัดส่วนเอาต์พุตผิดปกติหลังใช้ Bug Fix #1 0.1% → น้อยกว่า 0.03%
การปรับปรุง throughput ของ LayerSplit (40K~120K โทเค็น) +10% ~ +132%
HiCache fix มีส่วนร่วมใน SGLang PR #22811

การตรวจจับอาการผิดปกติ: ใช้ตัวชี้วัดของ Speculative Decoding

การตรวจจับอาการผิดปกติแบบอัตโนมัติเป็นโจทย์ยากในตัวเอง ฮิวริสติกอย่าง regex มีทั้ง false positive และ false negative มากเกินไป ส่วนตัวจำแนกแบบอิงโมเดลก็มีต้นทุนสูงเกินไปสำหรับการทดลองขนาดใหญ่

จุดเปลี่ยนคือ เมตริกของ Speculative Decoding

  • เอาต์พุตเพี้ยน / อักขระหายาก: spec_accept_length ต่ำผิดปกติอย่างมาก → เป็นสัญญาณว่ามีความไม่สอดคล้องกันของสถานะ KV Cache ระหว่าง draft model กับ target model
  • การสร้างซ้ำ: spec_accept_rate สูงผิดปกติอย่างมาก → เป็นสัญญาณว่าความเสียหายของ KV Cache ทำให้แพตเทิร์น attention ลู่เข้าไปสู่วงวนซ้ำ

จากนั้นจึงนำไปสร้างกลยุทธ์มอนิเตอร์แบบออนไลน์ หากจำนวนโทเค็นที่สร้างเกิน 128 แล้ว spec_accept_length < 1.4 หรือ spec_accept_rate > 0.96 จะหยุดการสร้างทันทีและส่งต่อให้ load balancer ทำการ retry กล่าวได้ว่า Speculative Decoding ได้ขยายบทบาทจาก เครื่องมือเพิ่มประสิทธิภาพ ไปเป็น เครื่องมือมอนิเตอร์คุณภาพเอาต์พุตแบบเรียลไทม์


Bug Fix #1: race condition ของ KV Cache ในสถาปัตยกรรมแยก PD

สาเหตุ

ในสถาปัตยกรรมแยก PD (Prefill-Decode) มีการใช้กลไกยกเลิกคำขอแบบอิง timeout เพื่อควบคุม tail latency หาก Prefill ไม่เสร็จภายในเวลาที่กำหนด ฝั่ง Decode จะ abort คำขอนั้นและเรียกคืน KV Cache

ปัญหาคือ สัญญาณ abort ไม่ถูกส่งไปถึงฝั่ง Prefill อย่างถูกต้อง แม้หลังจากที่ Decode เรียกคืน KV Cache และนำไปจัดสรรใหม่ให้คำขอถัดไป (Req2) แล้ว RDMA write และการประมวลผล Prefill ของคำขอเดิม (Req1) ก็ยังดำเนินต่อ ส่งผลให้เกิดการ เขียนทับ KV Cache ของ Req2

การแก้ไข

หลังจาก Decode ส่ง abort แล้ว ได้เปลี่ยนให้มีการส่งการแจ้งเตือนไปยังฝั่ง Prefill และให้ Prefill ส่งสัญญาณ "ปลอดภัยต่อการเรียกคืน" กลับมาเฉพาะเมื่อเข้าเงื่อนไขข้อใดข้อหนึ่งต่อไปนี้

  1. RDMA write ยังไม่เริ่มต้น
  2. write ที่ส่งไปก่อนหน้านี้เสร็จสมบูรณ์ทั้งหมดแล้ว

Decode จะนำ KV Cache กลับมาใช้ใหม่ได้ก็ต่อเมื่อได้รับการยืนยันนี้เท่านั้น ผลลัพธ์หลังใช้งานคือสัดส่วนเอาต์พุตผิดปกติลดลงจาก 0.1% → น้อยกว่า 0.03%


Bug Fix #2: การขาดการรับประกันลำดับ Load-Use ใน HiCache

สาเหตุ

เวิร์กโหลดของ Coding Agent มีความยาวอินพุตเฉลี่ยเกิน 70K โทเค็น และมีอัตราการนำ prefix กลับมาใช้ซ้ำสูง จึงมีการใช้งาน HiCache (KV Cache แบบลำดับชั้น) ซึ่งมีโครงสร้างที่สลับนำ KV Cache จากหน่วยความจำ CPU เข้ามาแบบอะซิงโครนัส พร้อมซ้อนการทำงานของ Load Stream และ Forward Stream

ปัญหาคือเคอร์เนล Indexer ไม่ได้ระบุข้อกำหนดการซิงโครไนซ์กับการโหลด indexer cache ให้เสร็จสิ้น หาก Forward Stream เริ่มทำงานก่อน Load Stream จะเกิดแพตเทิร์น read-before-ready ที่อ่าน KV Cache ก่อนโหลดเสร็จ และนำไปสู่อาการเอาต์พุตผิดปกติ

การแก้ไข

มีการแทรก จุดซิงโครไนซ์แบบชัดเจน กับ Load Stream ก่อนรันเคอร์เนล Indexer เพื่อให้ Forward Stream เดินหน้าคำนวณได้ก็ต่อเมื่อข้อมูลพร้อมแล้วเท่านั้น การแก้ไขนี้ได้ มีส่วนร่วมกลับไปยังคอมมูนิตี้ SGLang ในรูป PR #22811


การปรับแต่ง: LayerSplit (การกระจายการเก็บ KV Cache ระดับเลเยอร์)

คอขวดร่วมของทั้งสองบั๊กคือภาระของขั้นตอน Prefill เอง เพื่อแก้ที่ต้นตอจึงได้ออกแบบและพัฒนา LayerSplit

เดิมทีในสภาพแวดล้อม Context Parallelism (CP) แต่ละ GPU จะเก็บ KV Cache ของทุกเลเยอร์แบบซ้ำกันทั้งหมด แต่ใน LayerSplit แต่ละ GPU จะรับผิดชอบเพียง บางส่วนของเลเยอร์ และเก็บแบบกระจาย ทำให้ลดการใช้หน่วยความจำต่อ GPU ลงอย่างมาก

ระหว่างรันจริง CP rank ที่เป็นเจ้าของ KV Cache ของเลเยอร์นั้นจะ broadcast แคชก่อนเริ่มคำนวณ attention โดยซ้อนการ broadcast กับการทำงานของ indexer เพื่อซ่อน communication overhead และเนื่องจากข้อมูลสื่อสารเพิ่มเติมมีเพียง indexer cache (ประมาณ 1/8 ของขนาด KV Cache) overhead รวมจึงแทบไม่มีนัยสำคัญ

ภายใต้เงื่อนไข cache hit rate 90% throughput สำหรับคำขอขนาด 40K~120K โทเค็นดีขึ้น 10%~132% และยิ่งความยาวคอนเท็กซ์มาก การปรับปรุงก็ยิ่งชัดเจน


บทสรุป

> "การดูแค่ throughput, latency และ availability นั้นไม่พอ ระบบยังต้องรับประกัน ความถูกต้อง ของสถานะโมเดลที่อยู่เบื้องหลังทุกคำขอสร้างผลลัพธ์ด้วย กฎการสเกลผลักดันขีดความสามารถให้สูงขึ้น แต่สิ่งที่จะทำให้ความสามารถนั้นเชื่อถือได้ในระดับใหญ่ มีเพียงวิศวกรรมระบบที่เข้มงวดเท่านั้น"


ที่มา: Z.ai Research Blog (2026-04-30)

1 ความคิดเห็น