一直以來,分佈式服務器一直服務器開發一個比較高級的概念,實際上懂分佈式的人並很少,因此今天打算分享 java的分佈式遊戲服務器如何實現
java相對 erlang,golang 等函數式語言來講,實現分佈式並不十分方便,但若是採用akka組件,則問題迎刃而解。java
首先,大部分的遊戲服務器,都須要解決併發問題
傳統的命令式編程 並不能很好解決這個問題,因此大部分java面試,確定都會問及
多線程問題,併發問題, 而函數式語言,自然的解決了這個問題。
若是你學過erlang 和 golang ,網上也有相關 資料,搜索github 就有不少golang的項目,但使用了golang 不表明你使用了分佈式。
首先理解一個概念呢,erlang 實現的actor模型,在java中是否可實現。
答案是確定,早在scala 中就有actor 的實現,但若是你使用akka ,那就直接使用akka的actor來代替scala 的actor便可。
那光有actor 就實現分佈式了嗎? 並非
分佈式 的概念,意思是節點間的通信, 那麼簡單的節點通信,就應該是remote 了,
那麼使用java和golang實現remote ,方便嗎?
remote 須要 知道
本節點(ip - actor名) ----》 對方節點(ip - actor名)
那麼在實際實現中,就是須要在代碼中 爲每一個節點 的ip 和actor進行幾點註冊,發現。
是的,目前java 能夠經過 rmi,dubbo,akka等實現
duboo的實現 相對麻煩, 須要定義不少接口,須要對每一個節點進行註冊。
那麼在遊戲服務器中,這樣就能夠了嗎? 並非,由於當你擴建你的節點,你會發現你沒法判斷 目前你要通信的玩家登錄的是哪一個節點,那麼此時你要解決的是路由的問題。
而集羣正是爲了解決這個問題。
而遊戲服務器集羣建議採用golang ,或者 java(akka) 實現一套 集羣,自動路由,水平擴展的分佈式服務器git
golang的集羣我尚未實現過,下面主要 講講akka 集羣的使用:github
akka 中採用startProxy分區代理 訪問 ,跟使用shardRegion 來訪問的區別golang
這兩種訪問方式是否是重了呢。面試
而另外這是一個單例代理編程
private fun startUniverseCwarManager() {
val settings = ClusterSingletonManagerSettings.create(actorSystem).withRole(ClusterRole.universe_cwar.name)
actorSystem.actorOf(服務器
ClusterSingletonManager.props(UniverseCwarManager.props(), Handoff, settings), UNIVERSE_CWAR_MANAGER
)
}多線程
以上建立的集羣單例,經過如下方式進行訪問
protected fun startUniverseProxy(universeRole: UniverseRole) {
val proxySettings = ClusterSingletonProxySettings.create(actorSystem).withRole(universeRole.clusterRole.name)
val actorRef: ActorRef = actorSystem.actorOf(ClusterSingletonProxy.props(universeRole.proxyPath, proxySettings))
universeProxies[universeRole] = actorRef
}併發
worldActor 中 又 建立了一個訪問對象
/**分佈式
*/
private fun startUniverseCwarShardRegion() {
val settings = ClusterShardingSettings.create(actorSystem).withRole(ClusterRole.universe_cwar.name)
val region = ClusterSharding.get(actorSystem).start(
GameWorldShard.universe_cwar.name, UniverseCwarWorld.props(), settings, UCWorldMessageExtractor(), ShardCoordinator.LeastShardAllocationStrategy(5, 1), Handoff
)
logger.info("SharedRegion $region started.")
ClusterClientReceptionist.get(actorSystem).registerService(region)
}
經過這種方式建立的集羣分片 , 經過如下 代理進行訪問
/**
ShardRegion
.*/
就是隻要
protected fun startUniverseCwarShardProxy() {
ClusterSharding.get(actorSystem).startProxy(
GameWorldShard.universe_cwar.name, Optional.of(ClusterRole.universe_cwar.name), UCWorldMessageExtractor()
)
.let { logger.info("UniverseCwar shard proxy $it started.") }
} 開始的方式, 就能以如下的方式獲取到ClusterSharding.get(context.system()).let {ucWorldShardProxy = it.shardRegion(GameWorldShard.universe_cwar.name)}