可热更服务,热更脚本支持
前言
对于有状态的服务,利用新服务替换旧服务的方式,旧服务我们一直会维持到没有状态存在为止,当有简单逻辑bug的时候,旧服务没法立即更新,没法完美的解决问题,这时候可能就需要用到热更脚本来解决突发的一些简单逻辑bug。
限制
热更脚本对比滚服更新的最大区别就是:
热更脚本
是在旧的lua服务中完成滚服更新
启动新lua服务,流量切入新的lua服务
使用滚服更新的好处是,我们不需要考虑热更后对于服务内部状态的影响,编码方式可以随意使用,闭包,函数式编程,随便用。
想安全可靠的使用热更脚本更新,我们必须要限制我们的编码行为,才能做到功能按照预期完成更新。
限制一 匿名函数生成
假设我们需要热更模块如下:
1 |
|
1 |
|
如果我们想把a = a + 1
改成 a = a + 2
,那么main
函数中的count是热更不到的,所以可热更脚本模块,不能使用返回闭包函数。
限制二 修改全局变量
改动全局变量本身就是非常危险的行为,需要禁止。
限制三 模块返回值必须是table,并且其他模块引用时都需要从表根部开始引用
假设如下例子
1 |
|
1 |
|
热更后脚本
1 |
|
这样热更后,main
中的hello是用的旧版本,而 mode1.hello
是新版本。
限制四 模块 key 对应的value 类型不能变
突然改变类型,大概率是非常危险的行为。
实现方案
实现之前,有仔细的研究下云大的snax中实现的热更方案。
云大的方案是通过注入的方式,刷更新脚本。热更流程会把热更到的旧版函数的upvalue挂到新版函数的upvalue,主要考虑的是引用之前的状态数据。
而我觉得不想被热更的状态数据完成可以挂到一个不热更的模块中,这样热更并不会重置它,所以我的做法是把M中的key value,替换到旧版的。不处理upvalue,再新增一个挂载状态数据的模块即可。
具体实现
云大的热更方式,需要写额外的热更脚本,并不是在原文件直接热更,但是实际项目中,我们并不想额外写一个热更脚本,就想在原文件上修改,然后一键热更。
实际项目中,大多时候我们只需要热更经常改动的业务逻辑代码,所以我的做法是区分可热更脚本和不可热更脚本,可热更脚本用一个特殊的require加载,这样也能方便记录到哪些脚本文件是需要检测热更的,启动之后,就能把信息记录到文件中,方便利用shell脚本检测热更。
如何使用
hotfix_require 引入
想热更的脚本,需要使用hotfix_require加载。
make/script/check_hotfix.sh make/script/hotfix.sh
make_server.sh
增加了这2个脚本的生成。
make/script/check_hotfix.sh
检测并执行热更make/script/hotfix.sh
手动指定热更脚本
state_data.lua
用于挂载状态数据。
1 |
|
需要记录状态数据的,在可热更脚本中这样写即可,热更后state_map还是之前的table
。
热更完成的回调
1 |
|
可热更脚本中可以实现hotfix
函数,热更成功后调用。
使用限制
只有可热更服务中可以使用。
不要热更服务之间调用的CMD命令
假设有2个服务 A B
1 |
|
1 |
|
由于AB是2个服务,热更过程并不是串行的,就可能出现
旧B调用新A
调用之后 A肯定要报错,c参数不存在。新B调用旧A
结果不符合预期,c参数没加上。
尽量不要在模块中改写其他模块的内容
1 |
|
像这种,如果热更失败了,cccc.xxxx的函数也成新版了。