Cập Nhật Lớn Của Skynet
Skynet vừa trải qua một cuộc đại tu quy mô lớn, đánh dấu bước ngoặt quan trọng trong hành trình phát triển của hệ thống này. Bài viết này sẽ chia sẻ toàn bộ những suy tư đằng sau việc tái thiết kế kiến trúc nền tảng, cùng những bài học rút ra từ gần một thập kỷ đồng hành cùng Skynet.
Skynet không phải công trình thiết kế từ đầu mà là kết quả của quá trình tích lũy kinh nghiệm hơn 15 năm qua. Ý tưởng hạt nhân ban đầu xuất phát từ server game bài năm 2006, sau đó được định hình rõ ràng hơn nhờ tiếp thu tinh hoa từ Erlang trong giai đoạn 2008-2011. Tuy nhiên, chính những “người thầy” này cũng tạo nên những rào cản tư duy khiến nhiều quyết định thiết kế tưởng chừng hợp lý lại ẩn chứa bất cập về lâu dài.
Giai đoạn chuyển mình quan trọng bắt đầu khi dự án game di động đầu tiên chính thức đi vào ổn định. Điều đặc biệt là việc tiếp nhận phản hồi từ các đồng nghiệp trẻ như Tiểu Tĩnh - người trực tiếp vận hành dự án thứ hai của Skynet. Những câu hỏi sắc bén của cô đã khiến tôi nhìn lại những giả định tưởng như bất biến trong thiết kế ban đầu. Trong một tháng qua, hơn 3000 dòng mã nền tảng đã được viết lại hoàn toàn, tạo tiền đề cho cuộc cách mạng sắp tới.
Trong thế giới phát triển phần mềm, cải tiến hệ thống sống luôn là thách thức kép: vừa phải duy trì tính tương thích ngược để không làm đứt gãy hệ sinh thái hiện tại, vừa cần dũng cảm loại bỏ những gánh nặng lịch sử cản bước tiến. Đây chính là bài toán cân bằng mà chúng tôi luôn trăn trở.
Ban đầu, Skynet được thiết kế như một hệ thống xử lý phân tán, với việc tích hợp Lua vào Erlang như một giải pháp tối ưu cho logic nghiệp vụ phức tạp. Tuy nhiên thực tế cho thấy hiệu năng không đáp ứng kỳ vọng. Việc phải dựng thêm tầng trung gian C để kết nối Erlang và Lua đã tạo ra nút thắt cổ chai nghiêm trọng. Thêm vào đó, sự tồn tại song song của ba ngôn ngữ lập trình khác biệt - Erlang, Lua và C - cùng định dạng giao tiếp thống nhất dựa trên Google Protobuf khiến hệ thống trở nên cồng kềnh và khó bảo trì.
Chuyển hướng đột phá đến từ việc nhận thức lại ưu tiên hàng đầu trong kiến trúc game online: thay vì tập trung vào phân tán, chúng tôi cần khai thác tối đa hiệu năng đa nhân trên từng máy chủ để đảm bảo khả năng xử lý thời gian thực. Điều này dẫn đến quyết định táo bạo: sử dụng C để viết lại toàn bộ tầng nền, đồng thời lựa chọn Lua làm ngôn ngữ chính thức cho tầng logic.
Lua tỏ ra vượt trội trong vai trò này nhờ ba điểm mạnh: (1) Kích thước VM cực nhỏ (~300 byte/tác vụ) (2) Khả năng khởi tạo nhanh (3) Mô hình coroutine nhẹ nhàng nhưng mạnh mẽ. So sánh với Go routine, Lua coroutine không chỉ tiết kiệm tài nguyên hơn mà còn cho phép kiểm soát luồng thực thi hiệu quả hơn.
Một trong những thắc mắc phổ biến là tại sao RPC mặc định không có cơ chế timeout. Giải thích ngắn gọn: trong cùng một tiến trình, việc gọi dịch vụ thực chất là truyền thông nội bộ, không khác gì gọi hàm thông thường. Nếu một dịch vụ “treo”, đó là lỗi logic cần debug, chứ không phải vấn đề cần xử lý bằng timeout. Để hỗ trợ chẩn đoán, Skynet đã tích hợp sẵn các công cụ phân tích hiệu năng chi tiết, giúp xác định chính xác điểm nghẽn trong hệ thống.
Về cơ chế lập lịch, Skynet áp dụng mô hình pool thread cực kỳ đơn giản: cố định số lượng thread làm việc, mỗi thread chỉ tập trung xử lý một hàng đợi dịch vụ tại thời điểm bất kỳ. Khi không có công việc, thread sẽ ngủ 0.1s. Quyết định này từng bị chất vấn nhưng thực tế vận hành cho thấy nó cực kỳ phù hợp với đặc thù game MMORPG: hàng ngàn kết nối kéo dài hàng chục giờ, với tần suất dữ liệu thấp nhưng logic xử lý phức tạp. Khi hệ thống quá tải, việc giới hạn tốc độ xử lý ngược lại giúp kiểm soát tải hiệu quả hơn.
Điểm cải tiến gần đây nhất nằm ở module socket. Trước đây, việc xử lý kết nối mạng phân tán khắp hệ thống gây ra nhiều vấn đề về hiệu năng và bảo trì. Giải pháp hiện tại là tích hợp socket vào tầng nền, cho phép lắng nghe và chấp nhận kết nối trực tiếp mà không cần qua gate service trung gian. Điều này giúp giảm một tầng xử lý, đồng thời tối ưu hóa luồng dữ liệu từ socket vào hàng đợi nội bộ.
Kết quả thử nghiệm cho thấy:
Framework | QPS (PING test) | Notes |
---|---|---|
Redis (C) | 40K - 180K | Máy cũ vs máy mới |
Skynet (LuaJIT) | 40K - 130K | Tương đương Redis |
Erlang | ~180K | Triển khai chưa hoàn chỉnh |
Python + gevent | ~30K | Hiệu năng thấp |
PyPy | ~60K | Cải thiện rõ rệt |
Nhìn về tương lai, Skynet sẽ có những thay đổi cấu trúc quan trọng:
-
Phân tán hóa tầng ứng dụng: Di chuyển khả năng kết nối đa máy lên tầng trung gian, đơn giản hóa tầng nền. Điều này xuất phát từ thực tế: để đạt độ trễ tối ưu, dịch vụ liên quan (agent và map) phải cùng tiến trình.
-
Loại bỏ định danh toàn cục: Thay vì duy trì hệ thống tên phức tạp, khuyến khích sử dụng địa chỉ số trực tiếp - phương pháp mà đa số người dùng đã áp dụng tự nhiên.
-
Quản lý vòng đời dịch vụ: Phát triển cơ chế theo dõi trạng thái dịch vụ sâu hơn, tự động đóng kết nối socket khi dịch vụ bị hủy, đồng thời cho phép chuyển giao quyền sở hữu socket giữa các dịch vụ.
-
Tối ưu hóa socket API: Hoàn thiện tính năng quản lý kết nối theo ngữ cảnh dịch vụ, đảm bảo tính toàn vẹn khi chuyển giao giữa các thành phần hệ thống.
Để đảm bảo ổn định, các thay đổi này sẽ được thử nghiệm nội bộ ít nhất một tuần trước khi chính thức cập