SNS Webgame 社群類頁面網遊開發, 自己所用的架構,以及遇到的一些問題和困惑

jtyzs發表於2011-09-23
大家好,我第一次做伺服器的程式,之前我一直做手機客戶端,什麼WEB框架啥的都沒用過 ,遇到很多困難跟疑惑,請大家多多指教。
目前在做的一個社群頁面網遊,HTML頁面,非FLASH的,所有的互動都是基於HTTP的。

這個遊戲的邏輯比較常見,類似於SLG,玩家消耗時間採集資源(比如點一個按鈕,等5分鐘就可以採集了10個糧食),隨後製造了5個士兵,接著玩家之間可以進行PK,雙方損失N個士兵等等.
同時具有社群的常見功能,玩家之間也可以互相加好友,留言等等。 但是除了管理員,普通使用者沒有廣播的功能。也沒有專門的聊天頻道。
這個系統的特點是:
1. 使用者數可能會很多, 可能會有上百萬線上(至少所用的架構要能擴充套件到支援那麼多),並且不分割槽,大家都在同一個區。
也就是, 所有的玩家,都可以透過使用者名稱查詢到另外一個玩家的資訊,然後可以加好友或者PK。
2. PV量很大,並且資料庫操作頻繁,玩家的每個點選,都可能生成新的物件.比如生成幾個士兵,跟別人進行一場PK,會產生一條PK記錄。

我現在的設計是

瀏覽器 ----> LOAD BALANCE -----> 動態頁面伺服器 TOMCAT叢集 -----> Logic server -----> DB server

前端, 靜態的圖片,CSS什麼的,都可以交給 NGIX
動態頁面伺服器,用JSP,可以用 N臺 TOMCAT 叢集

後端, 邏輯伺服器 Logic server
資料庫 DB server , 一臺MYSQL


困惑之一: 頁面伺服器與邏輯伺服器的通訊問題
我現在的做法是,N臺 TOMCAT 透過SOCKET 連線到 邏輯伺服器, 然後傳送自定義的訊息格式;邏輯伺服器用一個執行緒維護訊息佇列,然後邏輯伺服器開啟一個執行緒,不停地處理訊息,並把結果返回對應的頁面伺服器。
然後頁面伺服器把邏輯伺服器返回的結果,翻譯成HTML返回給玩家
頁面伺服器
//
static Integer msgId = 0;
List<MyMsg> msgQueue = Collections.synchronizedList(new LinkedList());
HashMap<Integer, MyMsg> resultMap = new HashMap<Integer, MyMsg>();

public String requestHandler(HttpServletRequest hsr) {
// 一些檢查
// 根據 request 生成 msg
MyMsg msg = new MyMsg();
synchronized (msgId) {
msg.setId(msgId++);
}
msg.startTime = System.currentTimeMillis();
msgQueue.add(msg);

while (resultMap.get(msg.getMsgId()) == null) {
Thread.yield();
if (System.currentTimeMillis() > msg.startTime + 10000) {
break; // 超過 10 秒沒響應, 算超時
}
}

MyMsg result = resultMap.get(msg.getMsgId());
resultMap.remove(result);
if (result != null) {
return "翻譯result";
} else {
return "返回超時錯誤";
}
}

// 接收訊息 , 邏輯伺服器收到 MyMsg, 處理後, 會返回一個同樣 msgId 的MyMsg 給頁面伺服器, 頁面伺服器直接儲存
public void onReceiveMsg(MyMsg msg){
if (System.currentTimeMillis() > msg.startTime + 10000) {
return; // 超過 10 秒才回來, 直接丟棄
}
resultMap.put(msg.getMsgId(), msg);
}

請問這樣的設計,有沒有問題? 很多執行緒在等待自己的結果的時候,會不會造成伺服器出問題;
自己寫這些,總感覺有些不可靠, 有沒有現成的 伺服器間通訊框架,以及 訊息佇列什麼的可以直接用的?

邏輯伺服器中:
把所有收到的訊息都加入到佇列裡面,然後進行 序列處理。 這樣就省得同步什麼的了。
但這種做法,會不會造成效率損失?
一般大家做 邏輯伺服器與頁面伺服器的通訊是怎麼做的?


困惑之二
邏輯伺服器上的資料庫快取問題, 因為資料庫操作非常頻繁,所以肯定需要快取。
我現在的做法是
邏輯伺服器起三個執行緒, 一個負責邏輯處理以及資料管理, 一個負責資料庫讀取, 一個負責資料庫更新。 我沒有用 hibernate , 直接用的JDBC。

比如玩家登陸
頁面伺服器建立玩家登陸訊息 -> 邏輯伺服器 -> DB讀取執行緒讀取資料 -> 讀取到的資料,放入 資料管理程式 -> 返回玩家的資訊給 頁面伺服器
然後資料管理執行緒,定時遍歷 所有的賬戶資料(一個列表),判斷該賬戶是不是有更新,如果有更新, 則放到DB更新執行緒去更新資料庫。
我用的判斷資料是不是有更新的方法是,
在該 object 上次被更新到資料庫以後,就生成一個 saved = object.clone(), 把所有的成員物件都 clone一遍,
然後比較 當前object 與 saved 的所有成員, 看是否完全一致, 不一致,則說明有更新, 需要放到 資料庫更新執行緒去更新。


現在這種做法,
1.我感覺很麻煩, 所有的entity,都要寫 clone 方法 以及 saved與當前物件判斷更新的方法,
2.非常擔心的就是一旦伺服器突然出故障退出, 則可能會有很多賬戶的資料是過期的。只能靠日誌慢慢恢復。
3.所有的資料以及邏輯都放在一臺電腦上, 如果使用者數達到幾十上百萬以後, 會不會效能上有問題。


我後來看了一些資料庫快取的資料,比如memcache, redis ,都是類似於 hashMap 的功能, 好像是為了處理分散式系統,我的邏輯這塊,完全就在一臺機器上,所以我也不太懂怎麼把這些快取的工具應用到現在的系統中。
請大家多多指教。

相關文章