为什么游戏公司的server不愿意微服务化?
聊起微服务,互联网大厂几乎都奉为标配,但在游戏行业,尤其是做游戏服务器(server)的团队,大多对微服务化避之不及。我待过几家游戏公司,不管是做手游还是端游,核心服基本都是单体架构,顶多拆个网关、日志服这种非核心模块,问起为啥不搞微服务,老程序员的回答都很实在:不是不想,是真的不划算。
最核心的痛点——游戏对延迟和同步的要求,跟普通互联网应用完全不是一个量级。普通电商APP,用户点个下单按钮,延迟个100ms用户可能都没感觉;但游戏里,玩家放个技能、移动一下角色,要是延迟超过50ms,手感就会飘,要是同步出问题,比如A玩家看到自己打中了,B玩家那边显示没打中,直接就影响游戏体验了。
微服务的核心是拆成多个独立服务,靠网络调用通信,这本身就会引入网络延迟。算过一笔账,单体架构里调用一个战斗结算的函数,本地调用耗时可能就几毫秒;要是拆成微服务,战斗服、数据服、道具服分开,一次结算要跨3个服务调用,光网络往返就可能耗掉几十毫秒,还不算序列化、反序列化的时间。
给大家看个简单的对比,比如游戏里的“玩家使用道具”逻辑:
// 单体架构:本地调用,无网络开销publicvoiduseItem(Playerplayer,longitemId){// 1. 检查玩家道具数量(本地方法)Itemitem=itemManager.getPlayerItem(player.getId(),itemId);if(item.getCount()<=0)return;// 2. 扣减道具数量(本地方法)itemManager.decreaseItemCount(player.getId(),itemId,1);// 3. 触发道具效果(本地方法)buffManager.addBuff(player.getId(),item.getBuffId());// 4. 保存玩家数据(本地方法)playerManager.savePlayer(player);}这个逻辑在单体里执行,全程都是进程内调用,耗时基本在10ms以内。但要是拆成微服务:
// 微服务架构:跨服务调用,多了网络+序列化开销publicvoiduseItem(Playerplayer,longitemId){// 1. 调用道具服查数量(网络调用)ItemDTOitem=itemServiceClient.getPlayerItem(player.getId(),itemId);if(item.getCount()<=0)return;// 2. 调用道具服扣数量(网络调用)itemServiceClient.decreaseItemCount(player.getId(),itemId,1);// 3. 调用战斗服加buff(网络调用)buffServiceClient.addBuff(player.getId(),item.getBuffId());// 4. 调用数据服存玩家数据(网络调用)playerServiceClient.savePlayer(player);}每一次网络调用,就算用grpc这种高性能框架,也得至少5-10ms,四次调用下来,光网络开销就超20ms,再加上序列化、服务间的线程调度,总耗时很容易突破50ms,这在游戏里是绝对不能接受的。
更要命的是数据同步问题。游戏里有大量“实时状态”要维护,比如玩家的血量、位置、技能CD,这些状态必须强一致。单体架构里,所有状态都在进程内存里,加个锁就能保证同步;微服务里,状态分散在不同服务,要保证强一致,就得用分布式锁、事务,复杂度直接翻倍。
游戏服务器的“状态密集型”特性,天生就和微服务的“无状态”理念冲突。互联网的微服务,比如电商的订单服,处理完一个下单请求,不用保留用户的实时状态,下次请求再来重新查库就行;但游戏服不行,玩家在线的每一秒,都要维护他的实时状态,要是把状态拆到多个服务,比如位置存在场景服、血量存在战斗服,玩家掉血的时候,场景服没及时拿到血量更新,就会出现“玩家血条空了还在跑”的BUG。
再说说开发和运维成本。游戏行业的研发节奏跟互联网也不一样,互联网产品可以迭代优化,微服务拆错了还能慢慢调;但游戏上线前要过版号、要压测,上线后更新还要走审核,根本没那么多试错时间。
游戏团队的人员结构也不支持微服务。互联网大厂有专门的中间件团队、运维团队,能搞定服务注册、配置中心、链路追踪这些微服务基础设施;但游戏公司的server团队,大多是几个程序员包圆,既要写业务逻辑,又要搞部署运维,根本没精力去维护一套微服务体系。比如搞个服务注册发现,还要搭nacos、配置熔断降级,这些工作会占用大量开发时间,而游戏研发的核心是赶版本、做玩法,没人愿意把精力耗在这上面。
还有个容易被忽略的点——游戏服务器的负载特性。互联网应用的负载是“潮汐式”的,比如电商大促峰值高,平时低,微服务能弹性扩缩容;但游戏服务器的负载是“脉冲式”的,开服瞬间几万玩家同时登录,团战的时候几百人在一个场景里交互,这种高并发是集中在某几个核心模块的,拆成微服务也没法把压力分散,反而会因为服务间依赖,导致一个模块崩了,整个链路都出问题。
有人可能会说,那可以只拆非核心模块啊?其实很多游戏公司也这么做了,比如把日志、统计、充值这些不影响实时体验的模块拆成独立服务,但核心的战斗、场景、玩家数据这些,还是会留在单体里。这已经是权衡后的最优解了——既享受了微服务拆分非核心模块的便利,又保住了核心服的性能和稳定性。
微服务不是银弹,它解决的是互联网应用“复杂业务的解耦、团队协作、弹性扩缩”的问题,而游戏服务器的核心诉求是“低延迟、强同步、快速迭代”,这两者的核心目标是冲突的。
游戏公司不是不愿意微服务化,是微服务带来的解耦收益,远抵不上延迟增加、复杂度提升的成本。毕竟玩家不会关心你的服务器架构多先进,只会关心游戏卡不卡、有没有BUG,只要单体架构能扛住压力、保证体验,就没必要硬凑微服务的热闹。
当然,也不是说游戏服务器永远不会微服务化,现在有些大厂在尝试把云游戏的渲染服、逻辑服拆分,或者用容器化部署核心服,但这都是在不影响核心体验的前提下做的尝试。说到底,技术选型还是要服务于业务,对游戏来说,玩家体验永远是第一位的,这也是为什么单体架构在游戏server里依然是主流。