Những Chiếc Đồng Hồ Không Hoàn Toàn Chính Xác - nói dối e blog

Những Chiếc Đồng Hồ Không Hoàn Toàn Chính Xác

Hiện tại, cơ chế đồng bộ trong game của chúng tôi phụ thuộc vào việc dự đoán dựa trên đồng hồ hệ thống của các thiết bị. Phương pháp này hoạt động dựa trên giả định rằng tốc độ chạy của đồng hồ trên máy client và server phải hoàn toàn giống nhau. Khi đã đồng bộ thời gian ban đầu, chúng ta có thể tính toán khoảng thời gian trễ của các sự kiện được truyền qua mạng mà không cần liên tục trao đổi thông tin thời gian. Cụ thể, người gửi chỉ cần gán nhãn thời gian (timestamp) cho từng sự kiện, sau đó người nhận sẽ tính toán độ trễ bằng cách so sánh với đồng hồ của mình.

Ban đầu tôi cho rằng, miễn là client không gian lận, chỉ cần đồng bộ thời gian duy nhất một lần lúc đăng nhập là đủ. Các máy chủ trong cụm server của chúng tôi cũng chỉ cần đồng bộ thời gian với nhau khi thiết lập kết nối ban đầu, sau đó có thể tự vận hành dựa trên đồng hồ nội bộ. Tuy nhiên, một sự việc xảy ra hôm nay khiến tôi nghi ngờ về độ chính xác của đồng hồ trên các máy tính cá nhân.

Chúng tôi sử dụng một máy chủ chạy hệ điều hành FreeBSD làm thiết bị tham chiếu chính để đồng bộ thời gian. Các thiết bị khác sẽ kết nối đến để lấy mốc thời gian. Chương trình đồng bộ sử dụng hàm clock_gettime để lấy thời gian ở độ phân giải nano giây, sau đó quy đổi thành đơn vị nhỏ nhất là 0.05 giây cho các ứng dụng khác sử dụng. Trong buổi kiểm thử thực tế, tôi phát hiện ra rằng đồng hồ của máy chủ FreeBSD này chạy nhanh hơn khoảng 0.1 giây so với chiếc PC của tôi (chạy Windows XP) sau mỗi 20 phút. Sai lệch này quả thực quá lớn!

Nếu tính theo tỷ lệ đó, một ngày trôi qua đồng hồ sẽ chạy nhanh tới 6-7 giây. Rõ ràng là không thể bỏ qua hiện tượng lệch thời gian này, và việc đồng bộ lại thời gian mỗi 30 phút là hoàn toàn cần thiết.

P/S. Ngoài ra tôi nghi ngờ vấn đề có thể nằm ở hệ điều hành FreeBSD, dự định sẽ tiếp tục nghiên cứu kỹ hơn vào thứ Hai tuần này.

Ngày 22 tháng 5 - Bổ sung sau khi đến công ty vào thứ Hai và thảo luận cùng đồng nghiệp: Trước tiên, có thể lỗi nằm ở chính tôi. Khi thực hiện đo thời gian trên client Windows, tôi đã sử dụng hàm clock(). Tôi hiểu sai chức năng của hàm này - theo tiêu chuẩn, clock() phải trả về thời gian xử lý của chương trình, tức là khoảng thời gian CPU dành cho tiến trình hiện tại. Vì vậy lẽ ra tôi nên dùng API GetTickCount của Windows. Tuy nhiên sau khi thử nghiệm thực tế, kết quả không có gì khác biệt, có thể do cách định nghĩa hàm này trên Windows có sự khác biệt.

Tiếp theo, khi chuyển sang sử dụng một máy chủ FreeBSD khác, vấn đề lệch thời gian đã được khắc phục đáng kể.

Thêm nữa, trên hệ điều hành Windows, hàm QueryPerformanceCounter không còn đáng tin cậy nữa. Theo tài liệu của MSDN, khả năng cao hàm này đang sử dụng thanh ghi TSC (Time Stamp Counter) để thực hiện. Trong thời đại máy tính đa nhân và công nghệ điều chỉnh tần số CPU, việc sử dụng TSC gần như không thể cho ra kết quả chính xác.

Trên FreeBSD, việc sử dụng TSC để lấy thời gian có độ ưu tiên thấp nhất. Hiện nay hệ thống này thường dùng giao thức ACPI để đồng bộ thời gian. Trong khi đó, trên Windows dường như không có cơ chế tương đương nào có thể khai thác hiệu quả.

0%