天天看點

遊戲伺服器緩存政策

1:什麼是緩存

    在資料庫與伺服器邏輯之間加入的資料層

2:作用

    減少資料庫操作

    伺服器使用mysql作為資料庫,mysql每秒鐘并發數量有限,是以我們要減少mysql的操作。

3:erlang的緩存

    erlang 在記憶體中可用 程序字典/ gen state / ets 儲存變量,理論上三種方式都可以作為緩存

4:緩存實作方案

    方案 1

        原理

        讀資料時從緩存内讀取,如果緩存不存在則從資料庫中篩選,并放入緩存内

        資料變更時直接操作資料庫,并清除緩存

        實作方式

        啟動一個gen_server程序将所有 ets建立起來,ets會分為 ets_player,ets_bag 等将資料分開儲存到ets表中,一般以玩家id作為ets的key,讀取某個資料會優先通路ets表中資料,再從資料庫篩選

        這是我們最初的方案,缺點十分明顯,隻能減少部分讀取操作,在頻繁更改資料的情況下,緩存幾乎沒有作用,緩存在不停的被清理,當需要讀取資料時又需要重新從資料庫中拉取。

    方案2

        讀取政策與方案1一緻

        資料變更時變更緩存内資料,不操作資料庫,當玩家下線時再将緩存資料同步到資料庫中

        同樣會啟動一個gen_server程序将所有 ets建立起來,不同的是ets中的每一行多了一個是否修改的辨別位,玩家讀取資料依然優先通路ets表中資料

        當玩家修改資料,例如更新後,修改ets_player中對應的資料,并将ets中修改辨別設為已修改

        玩家下線後,順序檢查各個ets中的資料,将辨別為已修改的資料同步到資料庫中

        方案2與方案1相比,最大的變更在于資料更改時不清理緩存,而是修改緩存,這就避免了頻繁的從資料庫中篩選資料。

        将資料庫同步操作積累到玩家下線而不是立即寫庫,可以減少許多sql語句,例如玩家在上線期間由 1級升到5級,下線寫庫隻會執行一條sql,而即時寫庫則需要4條,對2,3,4,5分别執行update

        最初我們以為這套方案已經可以滿足遊戲線上運作需求,直到我們做了一個壓力測試(膝蓋中了一箭?),例如你有10多個系統,玩家,競技場,背包,抽獎,等等等等那麼在玩家下線時會出現資料庫操作高峰。在壓力測試時峰值十分明顯,尤其是開服初期導量十分多的情況。

    方案3

        由于玩家下線時間可能會出現峰值,是以我們想到了使用定時寫庫這種方式,将寫庫時間設定為我們認為合适的間隔

        每一張資料表都啟動一個對應的gen_server來管理資料,程序内部會建立一個ets表,玩家讀取/修改資料時都會通路對應的gen_server

        當玩家修改資訊後,gen_server内部會記錄修改的資訊。

        gen_server内部啟動一個定時器,每隔一段時間将修改的資料同步到資料庫中

        與方案2相比,方案3将寫庫時間控制在自己手裡,在遊戲開新服導量期間,可能設定數小時同步一次資料,可以很大程度減少sql壓力

        但這套方案也有缺陷,由于玩家查詢/修改資料都需要通路同一個gen_server,部分gen_server 如玩家資訊,就會出現瓶頸,出現逾時現象

    方案4

        為了解決方案3中gen_server通路的瓶頸問題,我們在gen_server外層又添加了一層緩存

        在方案3的基礎上,又将方案1,2中的cache_process添加回來,玩家讀取資料會先通路cache_proces中的資料,如果其中沒有再通路對應的gen_server程序

        最終 讀取資料流程       玩家擷取資料 -> cache_process中查找 -> gen_server 中查找 -> 資料庫中查找

                                                玩家更改資料 -> 更改cache_process

                                                                         -> 更改 gen_server 中資料 -> 一定時間後 gen_server将資料寫回資料庫

繼續閱讀