Chia sẻ quá trình tái hiện và sửa hai lỗi race condition trong KV Cache cùng các tối ưu cải thiện thông lượng khi vận hành Coding Agent dựa trên GLM-5 ở quy mô hàng trăm triệu lượt.
Bối cảnh
Các quy luật mở rộng (Scaling Laws) không chỉ thúc đẩy đột phá về số lượng tham số mô hình và quy mô dữ liệu, mà còn đẩy kỹ thuật hạ tầng tới giới hạn. Z.ai gọi các tác dụng phụ phát sinh trong quá trình này là Scaling Pain.
Trong quá trình xử lý hàng trăm triệu workload Coding Agent phức tạp mỗi ngày với dòng GLM-5, một số người dùng đã báo cáo các hiện tượng bất thường như đầu ra bị lỗi (garbled output), sinh lặp, sinh ký tự hiếm. Các vấn đề này hoàn toàn không tái hiện trong môi trường suy luận tiêu chuẩn mà chỉ xuất hiện trong môi trường đồng thời cao và ngữ cảnh dài.
Tóm tắt kết quả chính
| Hạng mục | Chỉ số |
|---|---|
| Tỷ lệ đầu ra bất thường sau khi áp dụng Bug Fix #1 | 0.1% → dưới 0.03% |
| Cải thiện thông lượng của LayerSplit (40K~120K token) | +10% ~ +132% |
| Bản sửa HiCache được đóng góp dưới dạng SGLang PR #22811 | ✅ |
Phát hiện hiện tượng bất thường: tận dụng chỉ số Speculative Decoding
Việc tự động phát hiện các hiện tượng bất thường bản thân nó đã là một bài toán khó. Các heuristic như regex có nhiều false positive và false negative, còn bộ phân loại dựa trên mô hình thì quá tốn kém cho thử nghiệm quy mô lớn.
Bước đột phá đến từ các metric của Speculative Decoding.
- Đầu ra bị lỗi / ký tự hiếm:
spec_accept_lengthcực thấp → tín hiệu cho thấy trạng thái KV Cache giữa draft model và target model không khớp - Sinh lặp:
spec_accept_ratecực cao → tín hiệu cho thấy mẫu attention hội tụ vào vòng lặp lặp lại do KV Cache bị hỏng
Dựa trên đó, nhóm đã triển khai chiến lược giám sát online. Khi số token sinh ra vượt quá 128, nếu spec_accept_length < 1.4 hoặc spec_accept_rate > 0.96 thì lập tức dừng sinh và chuyển việc retry cho load balancer. Nói cách khác, Speculative Decoding đã được mở rộng từ công cụ tối ưu hiệu năng thành công cụ giám sát chất lượng đầu ra theo thời gian thực.
Bug Fix #1: race condition của KV Cache trong kiến trúc tách PD
Nguyên nhân
Trong kiến trúc tách PD (Prefill-Decode), hệ thống đang vận hành cơ chế hủy request dựa trên timeout để kiểm soát tail latency. Nếu Prefill không hoàn tất trong thời gian quy định, phía Decode sẽ abort request đó và thu hồi KV Cache.
Vấn đề là tín hiệu abort không được truyền đúng cách sang phía Prefill. Sau khi Decode thu hồi KV Cache và cấp lại cho request mới (Req2), RDMA write và phép tính Prefill của request trước đó (Req1) vẫn tiếp tục chạy, dẫn tới hiện tượng ghi đè KV Cache của Req2.
Cách sửa
Sau khi Decode phát lệnh abort, hệ thống được thay đổi để gửi thông báo sang phía Prefill, và Prefill chỉ trả về tín hiệu "an toàn để thu hồi" khi thỏa một trong hai điều kiện sau.
- RDMA write vẫn chưa bắt đầu
- Tất cả các write đã phát lệnh đều đã hoàn tất
Decode chỉ tái sử dụng KV Cache sau khi nhận được xác nhận này. Kết quả áp dụng cho thấy tỷ lệ đầu ra bất thường giảm từ 0.1% xuống dưới 0.03%.
Bug Fix #2: thiếu bảo đảm thứ tự Load-Use trong HiCache
Nguyên nhân
Workload Coding Agent có độ dài đầu vào trung bình vượt 70K token và tỷ lệ tái sử dụng prefix cao. Để xử lý điều này, hệ thống vận hành HiCache (KV Cache phân cấp), với cấu trúc hoán đổi bất đồng bộ KV Cache từ bộ nhớ CPU vào và chạy chồng Load Stream với Forward Stream.
Vấn đề là kernel Indexer không khai báo ràng buộc đồng bộ với việc hoàn tất tải indexer cache. Nếu Forward Stream bắt đầu trước Load Stream, sẽ xảy ra mẫu read-before-ready khi đọc KV Cache chưa được tải xong, từ đó dẫn tới đầu ra bất thường.
Cách sửa
Trước khi thực thi kernel Indexer, nhóm đã chèn điểm đồng bộ tường minh với Load Stream, để Forward Stream chỉ tiếp tục tính toán sau khi dữ liệu đã sẵn sàng. Bản sửa này đã được đóng góp cho cộng đồng SGLang dưới dạng PR #22811.
Tối ưu hóa: LayerSplit (lưu trữ phân tán KV Cache theo từng layer)
Nút thắt cổ chai chung của cả hai lỗi là tải của chính giai đoạn Prefill. Để cải thiện tận gốc, nhóm đã thiết kế và triển khai LayerSplit.
Trước đây, trong môi trường Context Parallelism (CP), mỗi GPU lưu trữ trùng lặp KV Cache của mọi layer. Với LayerSplit, mỗi GPU chỉ lưu trữ phân tán một phần các layer, từ đó giảm mạnh mức sử dụng bộ nhớ trên mỗi GPU.
Khi chạy, CP rank sở hữu KV Cache của layer tương ứng sẽ broadcast cache đó trước phép tính attention. Việc broadcast được chạy chồng với phép tính indexer để che giấu chi phí truyền thông, và dữ liệu truyền thêm chỉ là indexer cache (khoảng 1/8 kích thước KV Cache), nên overhead tổng thể gần như không đáng kể.
Trong điều kiện cache hit rate 90%, thông lượng cho các request 40K~120K token đã tăng 10%~132%, và độ dài ngữ cảnh càng lớn thì mức cải thiện càng rõ rệt.
Kết luận
> "Chỉ thông lượng, độ trễ và tính sẵn sàng là chưa đủ. Hệ thống còn phải bảo đảm tính chính xác của trạng thái mô hình phía sau mọi request sinh. Các quy luật mở rộng đẩy năng lực đi xa, nhưng để khiến năng lực đó trở nên đáng tin cậy ở quy mô lớn thì chỉ có kỹ thuật hệ thống chặt chẽ mới làm được."
Nguồn: Z.ai Research Blog (2026-04-30)
1 bình luận
LIÊN KẾT PR https://github.com/sgl-project/sglang/pull/22811