Cách Roblox mở rộng nền tảng Kafka của mình lên hơn 18 nghìn tỷ tin nhắn mỗi ngày
Tối ưu hóa từ đầu đến cuối cho các hệ thống hiệu quả

Trong hai năm qua, chúng tôi đã mở rộng quy mô nền tảng hàng đợi tin nhắn nội bộ của mình gấp 2,5 lần mỗi năm, đạt hơn 18 nghìn tỷ tin nhắn mỗi ngày. Hiện tại, chúng tôi xử lý hơn 300 triệu tin nhắn mỗi giây trong khi duy trì mức độ sẵn sàng 99,995%. Nền tảng hàng đợi tin nhắn này, được xây dựng trên Apache Kafka, đã trở thành một phần quan trọng trong cách chúng tôi truyền dữ liệu trong toàn công ty. Nền tảng này hỗ trợ các khối lượng công việc như sự kiện phân tích, quy trình kiểm duyệt, hệ thống kết nối và nhiều hơn nữa. Những con số này rất ấn tượng, nhưng điều quan trọng hơn là cách chúng tôi đạt được thành quả đó.
Tác động của việc tối ưu hóa từ đầu đến cuối
Một quan niệm sai lầm phổ biến về các hệ thống quy mô lớn là khả năng xử lý chủ yếu là vấn đề phần cứng. Theo kinh nghiệm của chúng tôi, những cải tiến có tác động lớn nhất được thực hiện bằng cách xem khả năng mở rộng như một vấn đề kỹ thuật từ đầu đến cuối.
Các nhóm trong toàn bộ Roblox đã xây dựng nhiều nền tảng khác nhau dựa trên hàng đợi tin nhắn, bao gồm các quy trình đào tạo AI, các trừu tượng xử lý luồng và các hệ thống đo từ xa. Hợp tác với các chủ sở hữu của những nền tảng này cho phép chúng tôi giúp đảm bảo tuân thủ các phương pháp hay nhất, chẳng hạn như kích hoạt tính năng xử lý hàng loạt và nén dữ liệu. Điều này dẫn đến các hệ thống hiệu quả mà không cần người dùng cuối phải tham gia vào việc thiết lập cấu hình chi tiết.

Việc phối hợp với các nhóm sử dụng nền tảng này về các ưu tiên kinh doanh, chỉ số đo lường và tiêu chí thành công là rất quan trọng và giúp thúc đẩy sự hợp tác giữa các nhóm. Các chỉ số chính khác nhau giữa các lớp của hệ thống: Trong khi chúng tôi có thể tối ưu hóa các máy chủ Kafka để xử lý hiệu quả khối lượng dữ liệu lớn với ít máy hơn, người dùng cuối có thể muốn tối ưu hóa độ trễ từ đầu đến cuối xuống mức mili giây, hoặc tổng thời gian để công việc hàng loạt của họ hoàn thành việc ghi dữ liệu.
Không phải tất cả lưu lượng truy cập đều như nhau
Một bài học quan trọng mà chúng tôi rút ra được là các nền tảng quy mô lớn sẽ đáng tin cậy hơn khi không đối xử bình đẳng với mọi lưu lượng truy cập. Một số khối lượng công việc yêu cầu độ trễ rất thấp và khả năng bảo vệ mạnh mẽ trong các đợt tăng đột biến, chẳng hạn như các hệ thống ghép đôi của chúng tôi, vốn hoạt động với độ trễ từ đầu đến cuối dưới 10 mili giây. Các tác vụ khác có lưu lượng cực lớn nhưng lại chịu được độ trễ cao hơn, như các đường ống thu thập sự kiện phân tích của chúng tôi, có thể hoạt động trơn tru ngay cả khi độ trễ từ đầu đến cuối lên đến vài giây. Nếu cả hai loại lưu lượng này được xử lý giống nhau, lưu lượng có khối lượng lớn nhất có thể làm chèn ép lưu lượng quan trọng hơn đối với hoạt động kinh doanh, đặc biệt là trong các đợt tải cao điểm.
Để giải quyết vấn đề này, chúng tôi phân nhóm lưu lượng theo yêu cầu của từng trường hợp sử dụng để đảm bảo mỗi trường hợp đều được hỗ trợ tốt. Sự cân bằng giữa độ trễ đầu cuối và thông lượng trong Kafka là một trong những yếu tố quan trọng hàng đầu khi thiết lập các trường hợp sử dụng mới. Điều này áp dụng cho toàn bộ đường dẫn dữ liệu từ nhà sản xuất (producer) đến máy chủ (server) đến người tiêu dùng (consumer): Mỗi thành phần này đều có các cấu hình có thể được điều chỉnh để tối ưu hóa cho thông lượng hoặc độ trễ. Các cấu hình phía client có thể được điều chỉnh cho từng trường hợp sử dụng riêng lẻ, nhưng các cấu hình phía server lại kém linh hoạt hơn, vì việc duy trì một cụm chuyên dụng cho mỗi trường hợp sử dụng riêng biệt là không khả thi.
Chúng tôi áp dụng phương pháp tối ưu hóa từng cụm cho các trường hợp sử dụng mà nó phục vụ xuống đến lớp phần cứng.
Phần cứng vẫn rất quan trọng
Chúng tôi bắt đầu bằng việc chạy Kafka trên các máy chủ sử dụng ổ cứng HDD với cấu hình RAID10. Khi lưu lượng truy cập tăng lên, khả năng I/O đĩa của các máy chủ trở thành nút thắt cổ chai chính hạn chế thông lượng Kafka trên mỗi máy chủ. Để giải quyết vấn đề này, chúng tôi đã thực hiện hai tối ưu hóa. Chúng tôi chuyển các broker sang sử dụng SSD càng nhiều càng tốt, chuyển nút thắt cổ chai từ khả năng I/O đĩa sang thông lượng mạng hoặc dung lượng đĩa (vì các SSD chúng tôi mua có dung lượng đĩa hạn chế hơn). Điều này đã tăng thông lượng I/O đĩa lên gấp 10 lần. Chúng tôi cũng bắt đầu chuyển đổi các ổ HDD còn lại từ RAID10 sang RAID0. Điều này đã tăng gấp đôi dung lượng I/O đĩa, vì mỗi lần ghi với RAID0 chỉ cần ghi vào một đĩa thay vì hai.
Đổi lại, do mỗi bản sao tin nhắn chỉ được ghi vào một đĩa cho mỗi broker thay vì hai, việc chuyển từ RAID10 sang RAID0 có thể đi kèm với rủi ro về độ tin cậy. Để duy trì độ tin cậy, chúng tôi đã tập trung vào các trường hợp sử dụng quan trọng để tăng số lượng xác nhận (acks) và nhân bản dữ liệu, bao gồm việc nhân bản sang nhiều khu vực.
Việc tận dụng tối đa khả năng lưu trữ và thông lượng của từng máy đòi hỏi thêm công sức. Chúng tôi đã tối ưu hóa việc phân bổ bộ nhớ và cấu hình quản lý bộ đệm trang (page cache) để Kafka có thể đệm các tin nhắn và phục vụ các yêu cầu đọc hoặc dữ liệu gần đây từ bộ nhớ, chỉ truy cập vào đĩa và tiêu tốn IOPS quý giá khi cần thiết, chẳng hạn như khi đọc dữ liệu lịch sử.
Chúng tôi cũng thực hiện các bài kiểm tra hiệu năng để hiểu rõ giới hạn phần cứng và xác định các giới hạn ở cấp độ phần mềm cần thiết. Trên thực tế, điều này có nghĩa là thiết lập các giới hạn đọc và ghi cho các broker Kafka, tùy thuộc vào phần cứng mà các cụm đang chạy. Các máy chủ SSD của chúng tôi có thể xử lý thông lượng cao hơn trên mỗi broker, trong khi các máy chủ HDD phù hợp hơn cho các trường hợp sử dụng yêu cầu lưu trữ lâu dài dữ liệu lịch sử.
Xây dựng để đảm bảo độ tin cậy
Nền tảng hàng đợi là thành phần quan trọng trong hạ tầng của Roblox, và việc duy trì độ tin cậy là vô cùng quan trọng. Các bài kiểm tra trước khi ra mắt cũng như các bài kiểm tra kịch bản sự cố liên tục (thường được gọi là các bài tập “game day”) đã đóng vai trò then chốt trong việc xác nhận rằng hạ tầng của chúng tôi có khả năng chống chịu trước các chế độ sự cố như sự cố máy chủ đơn lẻ, sự cố giá đỡ, vấn đề mạng và nhiều tình huống khác. Nền tảng thử nghiệm hỗn loạn nội bộ của đội ngũ đảm bảo độ tin cậy đã hỗ trợ và tối ưu hóa quy trình mô phỏng các kịch bản sự cố khác nhau. Các thử nghiệm này giúp xác định các cải tiến hoặc sự suy giảm hiệu suất của hệ thống, đồng thời xây dựng sự xuất sắc trong vận hành bằng cách thường xuyên xác thực các cảnh báo và đảm bảo rằng các nhà điều hành quen thuộc với các bước xử lý các vấn đề khác nhau — ngay cả những trường hợp hiếm gặp.
Chúng tôi cũng đã thiết kế và triển khai các quy trình chuyển đổi dự phòng (failover) có thể nhanh chóng khôi phục chức năng hàng đợi cho các trường hợp sử dụng phụ thuộc. Ngay cả trong trường hợp một cụm cụ thể bị hỏng hoàn toàn, chúng tôi vẫn có thể chuyển các client sang một cụm hoạt động bình thường có dung lượng đủ. Để đảm bảo luôn có đủ dung lượng trống sẵn sàng, chúng tôi duy trì một cụm Kafka dự phòng. Điều này giúp loại bỏ mọi rủi ro liên quan đến hiện tượng "hàng xóm ồn ào" khi chuyển lưu lượng giữa các cụm đang hoạt động.
Sơ đồ dưới đây minh họa các bước tổng quan để thực hiện chuyển đổi dự phòng. Đầu tiên, người vận hành xác định phạm vi của quá trình chuyển đổi. Tiếp theo, các chủ đề (topics) và danh sách kiểm soát truy cập (ACLs) được tạo trên cụm dự phòng thông qua một thao tác tự động hàng loạt. Cuối cùng, người vận hành cập nhật cấu hình dịch vụ mặt phẳng điều khiển, mà các client sẽ kiểm tra định kỳ để xác định xem có cần kết nối lại hay không. Hình minh họa dưới đây áp dụng cho các trường hợp sử dụng thời gian thực chung. Chúng tôi có các chiến lược và công cụ bổ sung cho các trường hợp sử dụng và kịch bản khác, bao gồm sao chép chủ đề bằng Mirror Maker 2, công cụ bổ sung dữ liệu (data backfill) và nhiều tính năng khác.

Roblox có các yêu cầu nghiêm ngặt về bảo mật, đây cũng là một phần quan trọng của độ tin cậy. Chúng tôi đã triển khai các tính năng bảo mật tiêu chuẩn như mã hóa trong quá trình truyền tải (với mTLS), mã hóa khi lưu trữ (với đĩa mã hóa), các yêu cầu về thời hạn lưu trữ dữ liệu, cũng như xác thực/cấp quyền thông qua các thực thể Kafka và ACL. Ngoài ra, chúng tôi tự động xoay vòng thông tin đăng nhập của người dùng để nâng cao thêm mức độ bảo mật.
Ngoài ra, chúng tôi đã xây dựng cơ chế xử lý tùy chỉnh trong hệ thống điều khiển để hỗ trợ việc vá hệ điều hành và xả rack nhanh chóng. Trong quá trình vá hệ điều hành, chúng tôi lưu giữ dữ liệu trên đĩa để các máy đã được vá có thể nhanh chóng khôi phục trạng thái hoạt động bình thường sau khi kết nối lại với cụm Kafka. Nhờ đó, chúng tôi có thể vá toàn bộ hệ thống trong vòng 30 ngày, ngay cả khi hệ thống tiếp tục mở rộng. Với các công cụ như Cruise Control, chúng tôi sao chép dữ liệu theo cách nhận biết từng rack, để có thể ngừng hoạt động toàn bộ các rack nhằm bảo trì và vá lỗi mạng mà không ảnh hưởng đến tính sẵn sàng của dữ liệu.
Hướng đi tiếp theo
Chương tiếp theo cho nền tảng hàng đợi của chúng tôi tập trung vào việc đơn giản hóa nền tảng hơn nữa cho các nhà phát triển đồng thời tiếp tục cải thiện tính co giãn và khả năng cách ly. Chúng tôi đang đầu tư vào các lớp trừu tượng mới, bao gồm các proxy nhà sản xuất và người tiêu dùng cũng như các kết nối được quản lý hoàn toàn. Các hệ thống này sẽ tách biệt các nhóm ứng dụng khỏi sự phức tạp của hạ tầng và giúp nền tảng của chúng tôi dễ dàng triển khai và quản lý hơn ở quy mô lớn. Ví dụ, proxy người tiêu dùng sẽ hỗ trợ mô hình người tiêu dùng cạnh tranh, cho phép nền tảng đáp ứng đa dạng trường hợp sử dụng hơn và tách biệt việc mở rộng quy mô bộ xử lý khỏi việc mở rộng phân vùng Kafka. Điều này đặc biệt hữu ích cho các trường hợp như xử lý các đợt thông báo đột biến quy mô lớn, vốn không yêu cầu thứ tự xử lý và có thể tận dụng việc tạm thời tăng số lượng bộ xử lý mà không bị ràng buộc bởi các mục tiêu giao hàng end-to-end nhất định.
Mở rộng quy mô Kafka không chỉ đơn thuần là tăng số lượng và kích thước của các cụm máy chủ. Đó là việc xây dựng kỷ luật kỹ thuật, các lớp trừu tượng và mô hình vận hành cho phép Roblox tiếp tục hành trình kết nối một tỷ người mỗi ngày với tinh thần lạc quan và văn minh.
Lời cảm ơn: Xin cảm ơn Danny Yuan và George Li vì những đóng góp quan trọng của họ cho nền tảng hàng đợi Roblox.


