Lua 脚本的热更新是快速开发和不停服修复 bug 的重要功能,基本上每个基于 Lua 的框架都会提供。但是因为 skynet 开启了众多的 LuaState 的特殊性,所以它的脚本热更新会跟别的框架有很大区别。本文会尝试讲解 skynet 中热更新的操作。
clearcache
通过 debug 后台的 clearcache 指令可以清空进程的 CodeCache 缓存。更新本地文件,并且清空 CodeCache 的操作有时会被用来作为 skynet 热更新的方法。但是由于 CodeCache 清空时并不会修改旧的引用,所以旧的服务并不能用到更新,只有新启动的服务可以用到新的内容。
因为这样的特性,导致了这种方法使用范围比较窄。如果服务本身就是不断创建和销毁的,那就可以直接用,旧的服务会按照以前的逻辑执行完毕,新的服务会直接用新的逻辑。比如像一些副本之类的功能可能就会这样设计,每个副本都对应了一个为它提供支持的服务,副本开始时创建服务,结束时销毁服务。
还有一类服务也可以用这种方法热更新,就是无状态的服务。虽然旧的服务没办法被更新,但是因为是无状态服务,所以可以直接启动等量的新服务,然后让别的服务都把消息发送到新服务,旧的服务销毁即可。但是 skynet 并不提供相关的支持,要自己实现这类功能。
sharetable
sharetable 是 skynet 提供的一种可以在不同 LuaState 中共享只读数据的操作,一般在项目中用于共享策划配置表数据。
sharetable 中的数据可以进行热更新,针对同一份文件再次执行 loadfile 即可重新加载该文件,然后要在所有需要更新数据的服务里执行 sharetable.update 实现数据更新。
inject
inject 是 skynet 提供的可以用于热更新的后台指令,它的特点比较鲜明,用起来比较麻烦,但是理论上可以覆盖所有情况。
inject 会把该服务的 skynet.dispatch_message 和 skynet.register_protocol 这两个函数所有的 upvalue 作为 env 传给通过 load 加载的注入脚本,_U 是这两个函数的 upvalue,_P 是按协议类型分类的分发函数的 upvalue,想要替换任何函数或者是 upvalue 都需要自己在脚本中处理。
这里给出一个尽量简单的例子,用来修改 example 里的 simpledb 服务,将 GET 改为每获取一次为原 value 后面追加一个 “A” 字母。
|
|
首先使用任意 telnet 程序连上 skynet 的 debug 后台,这里要注意一下如果在启动 debug_console 时不指定监听地址的话,debug_console 默认监听的地址是 127.0.0.1,这样的话不能从远端连接该端口。
输入 list,让 skynet 列出当前进程所有服务的地址。然后使用 inject 命令,指定目标服务的地址和要注入的脚本地址即可。
|
|
成功注入以后,启动客户端,向 simpledb 发送 GET 命令。可以看到成功返回,并且每次返回的值都在原来的值后面追加了一个 “A” 字母。
|
|