遊戲伺服器程式內部都會統一設計所謂的tick機制,這個機制一般來說有兩個用途,一是許多業務模組都會有定時處理的需求,如:技能Buff計時、時間道具檢查、定時給玩家收益(打坐定時回血和藍,跳舞定時回經驗等)等等;二是遊戲伺服器內部會有一些日常主動驅動的事件,如:怪物移動、玩家移動等,這些需求都需要用到這個tick處理,誇張一點說,遊戲伺服器商務邏輯的處理絕大部分都會有涉及到tick處理的需求。
那這個相當重要的tick機制是如何?的呢?目前我們採用的是在主程式大迴圈中,每一次迴圈取一次當前系統時間並保留上次進入tick處理時的時間,然後拿這兩個時間相比較,若大於tick設定的間隔時間(如:200ms),則進入tick函數處理。這個tick函數中,註冊了系統所有業務模組需要定時處理的介面。於是,在大迴圈中每一次tick調用,就會將系統所有定時處理的介面都處理一遍。於是,問題便也隨之而來了... ...
顯而易見的問題是,所有的定時處理都放在一起調用,這會造成CPU的峰值瞬間拉高,並且也會造成server訊息處理的能力下降(因為tick處理的這段時間,本質上是可以作為server對訊息的延時處理時間),對於這個問題,我們也有顯而易見的處理方法,即將各個業務模組的定時時間進行分類,大致可以分為200ms、500ms、1s、3s、20s、30s、60s等適合各業務需求的定時間隔,這樣每一次tick調用時,就不會同時有許多模組一齊處理了,這可以在一定程度上平滑CPU的處理曲線。但也無法避免會在某個時間點,同時有許多(甚至所有)業務模組定時處理的情況,所以,我在想,是否還有其它更好的處理辦法呢?
首先想到的是,是將各個業務模組的定時間隔進行更精確和合理的分類,比較理想的情況是:使各個定時間隔互不包含,即各個間隔之間不要存在整除的關係,如:300ms、500ms、1100ms等,這個可以做一個測試,看一下這樣修改後,CPU的處理是否更平滑一些。
由於在linux下中,系統定時器是由SIGALRM訊號來實現的,而一般遊戲server為了穩定等原因,都屏蔽了linux的許多訊號操作,所以,一般就採用自訂的定時器來實現tick機制了,只是我們的這種機制是否還有更好的實現方式呢?這的確是一個值得思考的問題,畢竟,tick處理在遊戲server中佔了相當大的比重。
當然,只有讓每一個業務模組,每一次tick處理的時間儘可能縮小到最短,那麼,tick處理對於CPU的消耗就會減輕到最小了!