热更新场景1:
游戏新功能上线,发现线上存在BUG(死锁、活锁、死循环),在保证其他玩家正常游戏的前提下,在最短
时间修复BUG。
热更新场景2:
根据运营需要,策划上线新活动,但是活动没有达到运营预期,需要下线此活动。因为策划的工作疏忽,线
上没有提供活动开关功能,目前需要在玩家正常游戏的前提下,下线活动。
热更新场景3:
运营、开发、数据分析等人员需要实时监控服务器某个指标、现场数据,或是玩家角色信息等,但恰好没有
相关数据的统计,在保证玩家正常游戏的前提下,加入相关功能。
什么是热更新?
热更新一般指在应用运行状态中,动态替换部分组件、模块的代码,以适应新的需求,并且不会对系统运行
(代码、数据)造成不可逆的伤害。
为什么需要热更新?
随着人们生活的节奏越来越快,游戏的更新也越来越快,早期一个版本玩一年,到现在一个版本玩一天,更
快的内容迭代部署,对服务器架构提出了很大的挑战。
MMO类型游戏,需要通过长连接连上服务器,以达到通信全双工目的,同时降低延迟。
为了提高玩家游戏体验,提高响应速度,需要将角色数据缓存到服务器应用本地,避免序列化和反序列化耗
时,提高CPU利用率。
针对以上两个技术问题,常用代码更新部署应用冷启动,会导致:
1 玩家断开连接,无法继续游戏。
2 一段时间无法提供服务。
3 出现大量连接同时建立,瞬间大量访问数据库读取角色信息请求、反序列化操作。
造成IO和CPU压力巨大,出现游戏卡顿现象,更有可能出现服务器应用启动就宕机的严重事故。
从游戏更新频率、技术上考虑,热更新比冷启动更新带来不仅是效率上的提升,同时解决了连接和内存数据
冷启动上的技术难题,提高了玩家游戏体验。
如何进行热更新?
如何进行热更新是一项工程应用领域的课题。
对于一些弱时效性,强事务的业务服务器架构来说,可以不考虑热更新,但对于游戏服务器架构,必须考虑
热更新方案。
据我所知,目前游戏热更新方案一般分为"宿主-脚本"型(以下称脚本化)、"数据-业务分离,插件重加载"
型(以下称插件化)。
脚本化热更新方案通过宿主语言完成数据、连接、定时任务功能,将底层相关功能绑定到脚本,脚本去执行
所有业务逻辑,需要热更新时,重新加载(reload)一次脚本代码,即完成了热更新。这种方案在游戏架构
领域时最常用的方案,它带来的好处灵活部署、开发效率高、稳定性强,但数据需要代理访问。此方案适应
99%游戏的热更新场景。
插件化热更新方案和脚本化有结构上有一点类似,也是将数据、连接、插件(模块)管理器等核心功能放入
core层,尽可能的精简core层代码,其他所有业务代码通过插件来完成。整个架构需要少量的开发规范,例
如core中全局变量不能引用插件内组件,双亲委派机制插件间隔离等。方案没有脚本化开发自由灵活,但数
据不用代理,运效率相对较高。
谈谈两种方案的利弊?
脚本型:
优势:开发效率极高,系统稳定性强,上手速度快,语法灵活,移植性强。
劣势:需要绑定core层功能,反射调用,运行效率低,调试/排错困难,虚拟机内存占用大,弱类型需要特别考
虑数字运算,代码膨胀风险极高,可维护性低。
应用场景:
1.团队由初中级开发组成,采用脚本型可以避免动不动就crash,特别是c/c++作为core开发语言。上手速度快,
心智负担小,能显著提高开发效率。
2.质量无法保证,线上bug特别多,小需求迭代特别多。
3.不需要考虑运行效率、单机容量。
插件型:
优势:开发效率较高,静态语言强类型直接访问,代码模块性强,方便调试、排错、代码追踪,可拓展性好,
运行效率高(jit、aot),可维护性高。
劣势:系统稳定性一般,上手难度高,学习周期长。
应用场景:
1.开发周期长的大需求,特别是开发中有大量需求变更。
2.需要考虑单机容量、运行效率。
实际工业产品如何应用?
在实际的游戏服务器开发中,对性能和开发效率侧重点不同,会选择不同的架构,更多时候结合两者来使用。
也就是"插件-脚本混合型架构",此架构在大需求时,可以采用插件式开发,对于一些小的需求,采用脚本。
一个完整的DEMO!
本人用java写的一个demo,地址:ifserver-gameserver-demo: 游戏服务商热部署架构demo。
前端使用html+js实现,\livereloadshower\shower.html文件,如下图所示:
后端主要有两个类,PluginManager、ScriptManager分别管理插件和脚本。
脚本修改后,输入reload script命令重新加载。
插件修改后,使用ant plugin -Dplugin action来重新生成插件(需要先ant ifserver来生成core层包)。
演示如下图:
Server类中有main启动函数。