为了编写基于cellnet的新一代游戏服务器框架,最近深入研究微服务,ServiceMesh等概念。研究过程中对Web和游戏两种服务器架构设计有一些心得,编写并记录下来。(下文中,Game表示游戏服务器,Web表示Web服务器) ``
状态缓存
所谓状态缓存,就是在内存而非专业数据缓存服务器(如redis)中保存和处理逻辑数据,手动编写此过程较为繁琐但是效率较高,但随着状态逻辑复杂性和并发、扩容问题提出,状态同步会变得越来越复杂。
Game:
强交互性的服务器类型需要在服务器做缓存,逻辑编写也较为容易,无需处理事务并发问题。例如:组队,匹配,战斗逻辑。服务器不能随意重启。
弱交互性的服务器类型可配合redis做成无状态服务器,例如:养成,技能升级,领取物品等。服务器随时支持重启。
游戏服务器为了提高性能,早期所有服务器都是使用状态缓存写法编写,特别是MMORPG这类强交互的游戏服务器尤为严重。
Web:
均为无状态服务器,弱交互。使用事务方式处理并发逻辑,例如:交易,下单等。
推送,单独发送
这里提到的所谓推送,单独发送是与RPC区别的通讯方法。RPC要求请求必须有回应。而推送单独发送则更像是通知和广播,无需目的方返回任何消息。
Game:
找到服务器的Session,直接Send
通过中转服务器,或称为中心服务器进行注册/广播
客户端的model数据需要更新时,服务器会主动推送消息。
游戏服务器没有严格的RPC设计需求,推送和单独发送较Web服务器更多。而且游戏服务器多使用长连接,所以主动推送也比Web服务器来的方便一些。
Web:
将推送做成专有的服务,并做排队和并发处理。
可用性
听说过游戏停服更新,支付宝服务器在刷二维码时停服了可一定被骂惨吧。Web对服务器高可用性要求很高,游戏虽然也注重服务器稳定性和可用性,但是由于版本迭代更新频繁,停服更新反而能获得玩家接受。
Game:
游戏对可用性要求不高。
游戏大版本更新时需要停服更新。支持热更新技术的服务器(例如Erlang,Skynet)仅使用热更新修复bug,很少直接更新新版本。
不是所有的游戏服务器支持动态添加服务器。
Web:
极高的可用性,服务不允许停服更新,使用蓝绿及灰度方式更新服务器。
随时可以横向扩展服务器,提高服务器容量和承载。
连接及传输
均使用TCP传输协议,游戏服务器注重性能,自有协议及二进制协议使用较多。
Web注重兼容和接口友好,使用JSON格式较多。
Game:
使用长连接,需要从逻辑层维护连接状态及处理服务器不在线情况
使用自有封包格式,大部分使用protobuf或二进制流格式。
Web:
微服务大部分使用短连接,grpc支持http2长连接
使用json编码方便调试和版本兼容。
流量限制
人数多了,任何服务器都扛不住,流量限制和登入限制能有效保护服务器稳定。
Game:
单服有人数限制,可以通过GM后台设置挡墙,超过无法进入
Web:
限流器中间件,可以精确到服务控制流量
断流,防止雪崩
Game:
游戏没有,也不需要这种概念,游戏请求不会突然升高,即便有,也通过GM后台人为控制
Web:
断流器中间件
服务发现
如何找到服务器地址。
服务有变化时,通过Watch系统通知订阅者更新本地缓存
服务器没有变化时,使用本地缓存找到服务地址
Game:
游戏服务器互相依赖复用只在很小的范围内,因此无需在不同语言不同进程服务间获得地址,大部分在配置文件中填写各服务的IP及地址即可互相访问。
早期游戏自己编写服务器状态及地址发现服务。
有用redis做服务发现
Web:
使用服务发现系统,分布式部署。无需依赖配置文件
网关需求
Game:
网关处理客户端上下线通知,心跳,维持连接,转发,广播上下行封包
Web:
根据请求地址路由,无上下线概念,无心跳。广播通过消息推送系统完成
由于笔者从事游戏行业,对Web服务器概念在逐渐熟悉中,若有错误和不足请各位大佬指出。
本人新书《Go语言从入门到进阶实战》,生动的语言,例子带有各种彩蛋,轻松了解Go语言特性,更有cellnet框架剖析解密