Vấn Đề Đăng Nhập Người Dùng Trong Khung Skynet
Hôm nay tôi nhận được một email từ một người bạn đang vận hành một game server sử dụng khung skynet. Khi số lượng người chơi đạt đến mức ~1000, họ gặp phải hiện tượng kết nối mới bị nghẽn tại các thành phần gate hoặc watchdog, dẫn đến tình trạng người dùng không thể đăng nhập được.
Theo diễn giải của họ: “Hệ thống server của chúng tôi sử dụng kiến trúc gate-watchdog-agent. Khi số lượng người chơi tiếp cận mốc 1000, nhiều kết nối socket mới bị treo tại tầng gate hoặc watchdog. Nguyên nhân được xác định là do phía client tích hợp cơ chế timeout khi đăng nhập - nếu vượt quá thời gian chờ cho phép, client sẽ ngắt kết nối và thực hiện reconnect để bắt đầu quy trình đăng nhập lại từ đầu. Vấn đề nằm ở chỗ watchdog chỉ tạo service agent khi nhận được thông điệp đầu tiên từ client. Điều này dẫn đến việc hệ thống phải chịu tải nặng do liên tục tạo/destroy agent, trong khi chi phí hệ thống để khởi tạo agent lại rất cao. Dù sau đó chúng tôi đã loại bỏ cơ chế timeout phía client và tối ưu một số logic server, tình trạng trễ vẫn xảy ra vào giờ cao điểm.”
Trong buổi ăn trưa, nhóm kỹ thuật chúng tôi đã cùng phân tích nguyên nhân vì sao hệ thống của mình không gặp vấn đề tương tự ở quy mô 1000 người dùng. Chúng tôi rút ra được những điểm khác biệt:
Giải pháp của chúng tôi:
-
Phân tách quy trình xác thực:
Chúng tôi thực hiện xác thực người dùng trước khi khởi tạo agent. Toàn bộ quá trình xác thực được xử lý bởi watchdog, chỉ khi nào xác thực thành công mới tiến hành khởi tạo agent. Điều này giúp ngăn chặn việc tạo ra lượng agent vượt quá khả năng xử lý của hệ thống trong trường hợp có lượng lớn kết nối đồng thời. -
Tối ưu luồng dữ liệu:
Watchdog đảm nhiệm vai trò xử lý tất cả các gói tin từ gate trong giai đoạn xác thực. Sau khi hoàn tất, mới thông báo cho gate chuyển hướng gói tin trực tiếp đến agent. Dù điều này làm phức tạp hóa logic của watchdog, nhưng đổi lại giúp giảm tải đáng kể cho hệ thống.
Phân tích hiệu năng:
- Việc khởi tạo agent là công đoạn tiêu tốn nhiều tài nguyên CPU. Mặc dù service object trong skynet rất nhẹ và việc tạo mới Lua VM không tốn kém, nhưng việc tải và biên dịch các đoạn mã Lua lên VM mới lại là tác nhân gây delay lớn.
- Khi watchdog phải xử lý tuần tự việc khởi tạo agent, mọi gói tin khác sẽ bị trì hoãn. Điều này đặc biệt nghiêm trọng trong trường hợp nhiều người dùng cùng lúc cố gắng đăng nhập với cơ chế retry tự động, tạo thành hiện tượng “thủy triều” yêu cầu.
Giải pháp kỹ thuật được triển khai: Tôi đã cải tiến quy trình khởi tạo service Lua trong skynet thành 2 giai đoạn:
- Giai đoạn 1: Tạo ra một Lua VM trống và đăng ký hàm xử lý tin nhắn khởi động đặc biệt.
- Giai đoạn 2: VM tự gửi cho chính mình một tin nhắn khởi động (đảm bảo nằm ở đầu hàng đợi tin nhắn) để kích hoạt quá trình khởi tạo tiếp theo.
Lợi ích của thay đổi này:
- Tận dụng đa lõi CPU để xử lý đồng thời nhiều yêu cầu đăng nhập
- Giảm thời gian chờ khởi tạo dịch vụ ban đầu
Cảnh báo tiềm ẩn:
Cơ chế mới này có thể làm giảm khả năng phát hiện lỗi khởi động ngay lập tức từ phía đối tượng gọi.
Giải pháp dài hạn đề xuất: Chúng tôi khuyến nghị xây dựng một server chuyên dụng để xử lý hàng đợi đăng nhập. Watchdog có thể chuyển tiếp các yêu cầu xác thực đến server này để quản lý theo cơ chế xếp hàng, đảm bảo xử lý từng bước theo thứ tự ưu tiên mà không gây nghẽn cổ chai tại các thành phần lõi của hệ thống.
Hiện tại nhóm đang tiếp tục theo dõi hiệu năng hệ thống sau các tối ưu đã thực hiện, đồng thời chuẩn bị phát triển giải pháp xếp hàng chuyên nghiệp để chuẩn bị cho các đợt tăng tải trong tương lai.