天天看點

遊戲伺服器資料庫踩過的坑

     在頁遊伺服器這塊很早之前一直沒有認真考慮過,大部分是之前搭建好的,我隻需要按照他原來的設計繼續碼代碼就好了。

     可是這次伺服器重構的過程中,還是遇到了很多始料不及的問題。那麼就按照踩過的坑,去一個個講講分析分析。

     1:起初mysql的方案

   起初的設計方案是這樣,用一個roleplayer 去做玩家資料的緩存,所有玩家的資料更新到roleplayer中,定時十秒中更新到資料庫。roleplayer大概是這樣一個設計

      class roleplayer 

      {

        public int roleid;

            public string packinfo;

            public string equipinfo;

            public string taskinfo;

            .....

      }

      每十秒鐘對所有線上的roleplayer做一個批處理的更新,用的jdbc,對于玩家的流水也是如此,隻是更多的是拼湊的字元串,比如這樣insert into onlineserials(roleid,rolename,oltime) values (1212929,"wanjia1",12222),(1212929,"wanjia1",12222),(1212929,"wanjia1",12222)(1212929,"wanjia1",12222),(1212929,"wanjia1",12222) 。對于流水的處理還算比較謹慎,當流水條目到達5k之後 才做一次插入。我想這大概是一個頁遊伺服器對mysql的通用設計,可是無奈總是出現記憶體洩露,用工具檢視,基本是 string中的char占到了記憶體的40%,無論我使用什麼回收方式都無效。  當然我依然覺得這是一個很好的設計,隻是我自己在使用上還是欠水準。

  2:mongo的資料庫方案

  後來調整資料庫為mongo的,大家不要驚訝,我用的是json格式存儲的資料庫,這樣相容mysql和mongo,是以調整起來比較容易。mongo使用起來就比較簡單了,對于這種nosql 記憶體資料庫,使用起來就友善不少,無論是更新還是查詢。基本的設計就是當玩家的資料改變的時候,就更新到資料庫,當然是通過一條消息異步到資料庫線程去做更新,對于流水的記錄也是同樣的道理。隻是mongo 是一個記憶體怪獸,對于記憶體的貪婪,想必用過的人都清楚,對于mongo對于記憶體的管理大家可以百度下,有很多這樣的文章,在這裡就不詳細解釋。我起初也是毫無辦法,甚至去讀外文資料。找到我們之前的運維,他們也說并沒有對mongo做太多的設定,隻是用了一個記憶體25g+raid10硬碟 去專門部署mongo資料庫,ssd确實太貴用不起。在網上微網誌上搜集了一些資料也分享給大家,雖然并不能完全控制,但是也不失為一個很好的辦法。

  3:控制mongo的記憶體

    1: 調整linux核心的記憶體管理方式: shell> sysctl -w vm.drop_caches=1

       2:利用mongo提供的方式去回收整理記憶體:使用時會影響mongo的效率

                mongo>use mmo;

       mongo>db.repairdatabase();

       3:主動清理linux的cache記憶體: echo 3 > /proc/sys/vm/drop_caches

      說明,釋放前最好sync一下,防止丢資料。

 可以用一個将上面的指令定時跑 去釋放mongo的記憶體。

  4:控制mongo記憶體最終的方案

  在翻看《mongo實戰》這本書的時候發現了capped collection的用法。capped collections有如下優點:

                 1: 固定大小集合,如此便防止了記憶體無限擴張。

                 2: 以lru(least recently used)規則和插入順序進行age-out(老化移除) 處理,自動維護集合中的插入順序。      

      初看會以為 固定大小是一個很大的限制,但其實對于也有來說已經足夠,現在的頁遊導入使用者 基本在萬級别。 老化移除防止了記憶體的無限礦長,對于流水,我們大部分隻是要最近的流水來查找問題,對于一個月以前的流水,我想沒人會關心。        

      另外補充,調整ulimit 并不能控制住mongo對于記憶體的使用。

      如有誤,望批評!