【技术·真相】微服务管理

善始善终。

上次我们聊了服务器微服务架构中的服务状态依赖管理,今天继续聊聊在游戏服务器中比较常遇到的在线服务更新策略,也就是俗称的热更新在线更新

热更新的背景

在微服务应用广泛的互联网产品项目中,服务一般会做成无状态的,逻辑操作一般是直接操作数据库数据:

而游戏类项目比较特殊:由于玩家与游戏服务器的交互很多,对延迟要求很高,且数据间耦合较高,因此游戏服务器一般会将玩家的信息缓存在逻辑服务的内存中,逻辑操作是直接操作内存,状态数据会根据策略异步地落地到存储服务中:

服务器在线热更新是提升玩家体验的重要手段,可以在玩家在线游戏时无感知(或弱感知)更新服务器内容,或者做 fixbug。项目在平时小版本更新和bug修复可以大量使用这种方式。

对于无状态的服务,更新时,分批替换即可。

而对于有状态的游戏服务器中的状态,如何在线无感知更新是一个挑战。


需求分析

前面也说了,服务器进程按照数据状态分,一般分为两种:

无状态 有状态

无状态服务在线热更比较简单,分批启停进程即可;

有状态服务,需要在服务器重启更新前,将状态维护起来,可以是保持住,或者下线,或者将状态切换到其他服务器;

此外,游戏服务对外主要使用长连接(这个在我们之前的CS通信选型中也讨论过),和互联网常用的 http 协议区别在于如何及时重建长连接。

热更新方案选择

热更新的主要难点在于状态的维护,常用的维护方式有:

共享内存。普通内存中的数据,如果停服进程退出,则内存回收,数据也就丢失了。而共享内存在停服时不丢失,如果我们把状态数据保存在共享内存中,在服务器再拉起后就可以从共享内存中恢复。具体实施时,可以把状态数据以原始的对象形式(如C++中的类对象)直接保存,也可以将状态数据序列化之后以二进制形式保存在共享内存中。不管哪种形式,需要一开始框架就有完善的支持。另外,这种方式还有一个缺点,就是共享内存绑定在特定机器上,不好适配多实例部署的架构。 脚本,一些逻辑使用 lua/python 等脚本编写,状态只保存在宿主语言如 C++中,脚本只有逻辑,没有状态数据,要更新只需要热更脚本即可。还有一些服务器框架,游戏逻辑全部使用脚本语言,脚本中也存储了状态数据,热更新会依赖于脚本本身的 reload 机制,稍微麻烦一些,往往只能做特定的 bugfix 用途。用脚本的这种方式做热更新,需要一开始框架就有脚本引擎引入,且热更的范围有限,不能全量更新。如果数据格式有更新,适配起来也很麻烦。 逻辑/状态分离,一些 C++ 服务器框架会这么做,通常是将服务器进程编译时拆分成 2 个 so 来处理,一个 so 负责存储状态数据,一个 so 只有逻辑,热更时重新 dlopen 逻辑 so 做热加载,数据 so 保持不变。这种方法也需要框架一开始就支持,且代码编写有特定要求,如果不小心逻辑 so 中混有数据就麻烦了。 滚动更新,借助数据服存盘或者 Redis 来保存状态数据,分批处理,一批进程上的状态数据存储后再从另外一批中进程加载出来,状态相当于做了切换,各批进程依次循环更替重启,我们称这种方式为热重启。这种方式改造量小,只需要将状态数据的维护和已有的数据存盘、数据加载流程兼容起来,比较方便做改造。

热重启流程

分批热重启的流程很简单:

一批进程开始发起热重启 保证这批进程的状态安全存入数据服/ Redis,有成功返回 通过通知客户端重连或其他 server 请求等手段,触发状态数据的重新加载 状态数据通过路由机制加载并恢复到其他进程上 所有状态切换后,原进程退出,更新版本,启动

关键在于如何将这个流程做到比较完善,考虑多种可能的缺陷。下面我们通过方案演进的方式来阐述作者在实际项目中的探索。

方案演进

热重启方案1.0

根据我们项目的特点及版本进度,在1.0版本中,我们只支持了主游戏逻辑进程 Game 的热重启。

热重启 1.0 的具体执行如下:

通过工具客户端发起热重启指令到某一 Game Game 通过内部通信中的权重控制,保证该 Game 不能有新的玩家登录请求路由过来 Game 依次对已经在线的玩家做状态维护 依次对本 Game 上的每个玩家开启热重启流程,发起安全存盘(保证成功) 客户端收到服务器通知,重连到其他 Game 服,继续游戏 等待本 Game 上所有玩家热重启成功后,服务器自动关服;如果有任一玩家热重启失败,暂停整个热重启过程,待问题解决后,可以再次发起热重启 所有 Game 热重启后,整个热重启操作结束

示意图如下:

在依次热重启时,每个玩家互不影响;

在热重启期间,没有轮到的玩家可以继续正常游戏。

遇到的问题

几次测试后,这套机制运行良好,但是也遇到了一些问题,主要有:

只有 Game 专门设计了热重启机制,其他服没有专门设计,如果遇到 bug 需要更新,则只能通过直接重启来解决,会损失体验。 虽然做了分批下线更新,但是没有对各批次恢复登录态的请求做路由控制,从老服下线的玩家可能会重连再进入别的老服,则下次别的老服热重启时会被再次踢出,导致重复下线的问题。从服务器角度看会多次存盘下线,存在数据安全问题;从玩家角度看就可能被多次踢出重连,体验不好。 部分服务有损,一些玩法的临时数据如战斗、场景互动等,不存盘,该部分状态数据在热重启时得不到恢复,只能采取特殊方式处理,如强制结束战斗、强制退出场景等。 对于一部分无状态服务器,可直接重启,但是在进程重启的过程中,存在短暂的时间窗:从开始停服到重启成功,在这个时间窗内有新来的请求过来,这部分请求无法处理,存在体验上的瑕疵。 分批热重启过程中,需要人工查看日志确认热重启是否完成。 只能一个个串行地对目标进程进行操作,如果开启的进程数量较多,运维操作流程太长。 解决方案

针对上面遇到的问题,我们优化了热重启的方案,主要解决方式如下:

设计一套通用的状态数据下线流程,由各进程实现自己的数据保存、数据加载及通知; 控制状态数据切换流向,只会从老版本进程切换到新版本进程。各进程增加备服,热重启前备服先更新到新版本然后提供服务。各批进程状态在切换时,控制恢复状态时只会路由到新版本进程中,减少切换次数,所有切换完成后,备服做最后一次切换后停服; 战斗和场景交互等旁路系统独立出来做成微服务,这些微服务如果需要热重启,也增加等待这些临时状态下线的处理,会等所有的逻辑如战斗、交互结束后,对应的微服务进程再退出; 定时上报热重启进度结果,发起方可以查看进度; 分批热重启时支持多个实例同时做热重启;

对于无状态服的重启,在实施前,我们将对应进程的权重降低,这样就不会有新的请求路由过去了。我们在 路由服上增加权重控制,防止请求遭遇重启过程中的时间窗。


热重启方案2.0

有状态服

优化后的有状态服热重启方案 2.0 流程图如下:

每批次流转示意图如下:

无状态服

对于无状态服,增加降权步骤,禁止请求路由到本进程。权重操作完毕后,运维直接重启即可。


热重启方案 3.0

增加对外 SLB 权重降权

我们之前热重启各种服务,主要是服务器内部服务,不直接和玩家交互,在热重启过程中,降低其权重的措施也是通过内部的路由机制来实现的。

我们还有一类服是直接与玩家建立连接的,有维护 Tcp 连接的 gate 网关服、imserver 聊天服;有维护 Https 连接的 rank 排行榜服等。

这类有对外连接的服务通过云服务提供商的 LB 负载均衡组件与玩家建立连接。这类服务的状态基本都是临时的,如玩家的连接信息等。

如果我们要热重启这类服务,还需要额外处理 LB 负载均衡组件上的权重。运维同事帮助我们通过负载均衡组件的 API 实现了自动修改权重。

退出间隔

在实际使用时,也遇到了一些其他小问题,例如热重启的进程在做完所有状态切换后,还会做一些服务器资源清理释放工作,可能不是立即退出的,但是定时上报的热重启结果里显示该进程已经退出了,运维脚本如果立即拉起,会失败。

这里我们在一些原子过程后面加了 sleep,等待几秒后,进程完全退出再拉起。


热重启方案4.0

几次前期测试之后,我们热重启 3.0 版本的方案已经基本运行平稳了,但是每次运维操作的时候比较繁琐,步骤较多(将近10个步骤),还需要输入大量的参数,很容易出错;

另外这几次测试的服务器部署的比较少,而公测时有几百组服务器,如果依赖运维输入必然不现实,为此我们决定将热重启做成运维自动化流水线,可以分布式执行,也减少了人工干预,效率和容错性都大大提高。

运维自动化

实施完成后,一次热重启大约一百多组服务器,由于是并行执行,耗时也就十几分钟的量级。

灰度化

正式上线后的热重启一般都力求稳健,我们需要一定程度的灰度机制来测试某次更新是否达到预期目标。

在实行热重启时,如果待热重启进程是小区进程,则可以简单的选择一个区先做热重启,等QA验收通过后,再全量铺开到所有小区。

如果待热重启的进程是全局进程,则我们选择该进程所部署的N个实例中的某几个,热重启后,等待QA 验收结果。

以上两种维度的灰度我们目前都已经支持,通过参数的不同来加以区分,目前运行良好。

未来 K8S 环境下的热重启

作者的项目目前的内网环境通过 K8S 来管理,也需要更好的适配 K8S 的滚动更新策略。方案还在持续优化之中。

小结

好了,本文对分布式微服务的更新策略的探讨就到这里,让我来为你回顾一下要点:

改善产品的体验是重要的,因此在线无感知/弱感知更新服务是非常有必要的; 游戏服务相对于互联网服务,需要维护较多的状态,其在线热更新难度更大; 热更新有多种方案可以实施,我们采用了一种最适合当前项目背景的方案; 方案本身的难点在于针对遇到的问题持续演进,使之持续改善和稳定;

希望能为你提供一点参考。希望你方便的话点个免费的赞,感谢!


作者:我是码财小子,会点编程代码,懂些投资理财;期待你的关注,不要错过我后续的文章更新。

相关知识

网络游戏社区管理与服务方案.doc
如何有效管理移动游戏中内购服务的收益
电子竞技运动与管理
《网络游戏管理暂行办法》解读
游戏云玩服务app下载
手游管理平台:助力游戏开发者高效管理游戏业务
Unity UOS免费试用计划 一站式游戏开发与云服务解决方案
白鹭重度微信小游戏优化技巧
网络游戏产业游戏社区平台建设与管理策略.doc
steam游戏服务器如何管理

网址: 【技术·真相】微服务管理 http://www.hyxgl.com/newsview366873.html

推荐资讯