王者荣耀竟然没用微服务架构?

Java大联盟

共 3294字,需浏览 7分钟

 ·

2020-11-25 22:07

  Java大联盟

  帮助万千Java学习者持续成长

关注



作者|hongjic93、brice

zhihu.com/question/359630395/answer/954452799


B 站搜索:楠哥教你学Java

获取更多优质视频教程


今天在知乎上看到这样一个问题:"为什么游戏公司的 Server 不愿意微服务化?

1、背景介绍

最近面试了一家游戏公司(满大间的,有上市),我问他,公司有没有做微服务架构的打算及考量?

他很惊讶的说,我没听说过微服务耶,你可以解释一下吗?我大概说了,方便测试,方便维护,方便升级,服务之间松耦合,可多语言开发,自动扩容…之类的点。

然后他说游戏 Server 不太需要微服务,因为要求 Real Time,做微服务会影响效能,分模组来开发就好了。

我也不确定,但微服务不是趋势吗?特别是大公司,游戏 Server 的服务应该很容易拆分吧?

下面,我们来看看两位高赞回答。

2、hongjic93 是这样回答的

比如 MOBA 类游戏/王者荣耀/LOL,就看王者荣耀的客户端吧,想象一下。

账号系统,符文系统,英雄系统,皮肤系统,好友系统,好友之间 Messaging,这些都是常规操作,如果流量足够大,当然可以用微服务的架构去做。

不过这不是这个游戏的核心,核心是 MOBA:Multiplayer online battle arena。

特性是什么?10 个人之间各种游戏事件的高速多向通讯,Streaming/Broadcast/Multicast/Pubsub 各种通讯模式。

所以游戏的核心在于小规模群体之间的高速网络通信。就是对方说的 Realtime。多了一个 10ms 的延迟玩家就要骂娘了。

①微服务为了把业务完美拆解,把原来的同一个进程里的模块拆分成不同的服务,显著增加额外的网络开销。

更别说什么 Service Mesh,各种 Gateway,Proxy,Sidecar,简直就是担心延迟太低。

②微服务基本只有 Request/Response的模式。做不了 Streaming?微服务通常要求应用是无状态的才能做到水平扩展。Streaming 本身就是加入了状态。

③我可以想像,为了提高通讯的性能,一场英雄联盟游戏很可能会使用同一个服务器负责这 10 个玩家之间的通讯,这样就使得数据可以在本地交换,性能最大化。

这对客户端或者说服务端统一网关的要求是必须支持 Sticky Routing。假设客户端连接断了,接下来的必须重连之前的同一个服务器。

微服务的 Stateless,水瓶扩展要求本身就是反 Sticky Routing 的,因为 Sticky Routing 本身就是状态。

④对服务端集群来说,同时有无数个王者荣耀的比赛在进行,每个都可以看成一个沙盒,每个沙盒都处于一个不同的状态:塔被推了几个了,你被杀了几次了,对面几个超神了,20 分钟到了没。

这些都是长时间存在的状态,直到游戏结束,服务端才可以清理一场游戏的状态。

所以虽然不用把这些状态写进持久性存储,但是必然会在内存中存在很长时间。都是状态,反正有状态,就别想用微服务。

除非你说把这些状态都移到 Redis 里去,那么在服务器在信息流传输到一半还要做一个 Remote Request,一来一回,延迟就上升了。

总之怎样都不好。(比如想象对方在 A 你的水晶,每一次 A 的操作都是一个 Event,被 Streaming 到服务端的沙盒中,沙盒中有一个流处理器,每次接收到一个你水晶被 A 的 Event 都会计算一下你水晶爆了没。这个计算需要极快,你是不可能把你水晶生命值的数据存在远端的。)

像这类游戏,都是对网络,内存,CPU 的优化需求很高,整个游戏进行过程中,几乎不存在什么 RPC call,真的需要 Remote Data,也应该是 Rrefetch,就是在游戏刚开始的时候加载好。

微服务不是什么银弹,也就是方便拆解一下原来的 CRUD 应用罢了而已,一没触及高级的交互方式,二没触及分布式系统真正的难点:状态,其实没有大家想的那么有用。

之所以感觉上好像微服务改变了互联网,只不过 90% 的互联网应用都只是简单小规模的 CRUD 而已。

对方没有听说过微服务完全没有问题,因为这本身就不是什么高深的概念,反而对方听你一说一下就知道微服务不适合游戏,说明对方理解能力很强,对游戏系统设计也了解足够深。

3、brice 是这样回答到

做过棋牌游戏(游戏最简单的一种),可以尝试说几个点:

①微服务本身是为了应对业务逻辑的复杂,需要要的新的组织接口的方式。

游戏本身逻辑其实没有这么复杂,比如大厅就是一些基本功能,修改帐号,登录等。游戏本身就是游戏本身的逻辑。

②游戏逻辑服务器本身(比如斗地主等棋牌)因为网络响应性能要求问题(玩家对每个操作的反馈时长敏感度远高于业务系统),所以游戏服务器都是有状态的。

状态就存在内存,偶尔会接受 Redis,MySQL 等是绝对不可以的接受的,关系行数据库仅用来定时异步持久化数据,仅游戏服务器而言持久化在 Redis 即可。

③游戏服务器一般纯需要主动推送,所以第一代微服务网关就没办法满足需求, TCP 的没有网关用,Spring Cloud Gateway 的 Web Socket 也许可以用(但是从防攻击角度讲端游用 TCP 绝对比 Web Socket 合理)。

④服务间通信 RPC 首先 Ribbon,Feign 等并不是合适,因为都是基于 HTTP 的,用 HTTP 存在一个消息乱序问题。

比如玩家出牌两次,在 HTTP 就可能出现次序不一致。游戏服务器集群一般使用长连接互联。可能需要用 Dubbo?(听说是长连接)

⑤游戏逻辑服务器(比如斗地主服务器),一般是不能用 Spring MVC 做的,因为线程模型完全不同。

多线程模型处理游戏性能差还非常复杂,一般都是使用单进程/线程 驱动固定数量房间的方式(这也是为何服务器一定有状态,一定不能直接读写 MySQL)。一般就直接 Netty 了。

⑥自动扩容在游戏这边叫做开服,早就有固定流程和工具和限流方式了。

⑦游戏很多操作不存在服务降级熔断,不行就要直接报错给用户。

⑧大厅服务器登录注册等的确可以做微服务,但是其实也不是做微服务,就是几个接口有自动水平扩容的方案即可。

服务注册发现用处不大,开服都是确定的事情,还有一系列运营手段配合,关服也是绝对不能随便关的。

⑨游戏处理的流量真的不算多,你在线 1 万的棋牌游戏已经很赚钱了,10万 就是个特别厉害的产品了。

⑩一些独立的服务器比如充值之类的需要微服务化么?只能说这种服务器都需要微服务处理了,项目组做梦都能笑醒。

虽然上面说了很多点,但是其实也是可以考虑用 Spring Cloud 改造的,因为游戏集群一样有注册中心,需要服务发现,需要编排启动顺序,只是 Spring Cloud 没有为了游戏设计而已。

比如至少要完全支持 Webflux吧(没有仔细研究),需要一个单线程的长连接最好支持 Protobuf RPC 框架吧(集成服务发现相关功能与接口)。

网关支持 TCP 或者至少封装或者暴露一些 Netty 的 Decoder Encoder(或者允许注入)等等。


推荐阅读

1、Spring Boot+Vue项目实战

2、B站:4小时上手MyBatis Plus

3、一文搞懂前后端分离

4、快速上手Spring Boot+Vue前后端分离


楠哥简介

资深 Java 工程师,微信号 southwindss

《Java零基础实战》一书作者

腾讯课程官方 Java 面试官今日头条认证大V

GitChat认证作者,B站认证UP主(楠哥教你学Java)

致力于帮助万千 Java 学习者持续成长。




有收获,就在看 
浏览 45
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报