【基于skyent的热更思考】

基于skyent的热更思考

skynet-inject热更原理

inject是一个用于动态加载 Lua 代码文件并执行其中定义的函数的功能。可以在运行时动态加载 Lua 代码文件,然后调用其中定义的函数,通过修改模块及其函数的upvalue,实现代码的动态注入和执行。热更实现的大概思路:通过向指定服务注入cmd实现热更

参考wiki https://blog.codingnow.com/2016/11/lua_update.html

关键源码分析

lua 复制代码
-- debug_console.lua

local function adjust_address(address)
    local prefix = address:sub(1,1)
    if prefix == '.' then
        return assert(skynet.localname(address), "Not a valid name")
    elseif prefix ~= ':' then
        address = assert(tonumber("0x" .. address), "Need an address") | (skynet.harbor(skynet.self()) << 24)
    end
    return address
end


function COMMAND.inject(address, filename, ...)
    address = adjust_address(address)
    local f = io.open(filename, "rb")
    if not f then
        return "Can't open " .. filename
    end
    local source = f:read "*a"
    f:close()
    local ok, output = skynet.call(address, "debug", "RUN", source, filename, ...)
    if ok == false then
        error(output)
    end
    return output
end

adjust_address: 用于调整传入的地址参数,对传入的地址参数进行转换,以保证将热更脚本注入到正确的服务地址
io.open(filename, "rb"): 以二进制只读的方式读取文件内容
source: 存放读取到的热更脚本内容
skynet.call(address, "debug", "RUN", ...): 通过skynet的debug消息类型,将读取的热更脚本内容注入到目标服务地址(debug.RUN内部实现)

lua 复制代码
-- skynet.debug.lua

function dbgcmd.RUN(source, filename, ...)
    local inject = require "skynet.inject"
    local args = table.pack(...)
    local ok, output = inject(skynet, source, filename, args, export.dispatch, skynet.register_protocol)
    collectgarbage "collect"
    skynet.ret(skynet.pack(ok, table.concat(output, "\n")))
end
lua 复制代码
-- skynet.inject.lua

return function(skynet, source, filename, args, ...)
    if filename then
        filename = "@" .. filename
    else
        filename = "=(load)"
    end
    local output = {}

    local function print(...)
        local value = { ... }
        for k,v in ipairs(value) do
            value[k] = tostring(v)
        end
        table.insert(output, table.concat(value, "\t"))
    end
    local u = {}
    local unique = {}
    local funcs = { ... }
    for k, func in ipairs(funcs) do
        getupvaluetable(u, func, unique)
    end
    local p = {}
    local proto = u.proto
    if proto then
        for k,v in pairs(proto) do
            local name, dispatch = v.name, v.dispatch
            if name and dispatch and not p[name] then
                local pp = {}
                p[name] = pp
                getupvaluetable(pp, dispatch, unique)
            end
        end
    end
    local env = setmetatable( { print = print , _U = u, _P = p}, { __index = _ENV })
    local func, err = load(source, filename, "bt", env)
    if not func then
        return false, { err }
    end
    local ok, err = skynet.pcall(func, table.unpack(args, 1, args.n))
    if not ok then
        table.insert(output, err)
        return false, output
    end

    return true, output
end

这两段核心代码实现了一个动态加载和执行 Lua 代码的功能,通过构建环境表、加载代码并执行,最终返回执行结果。这个函数是实现动态注入功能的关键部分,能够实现在 Skynet 框架中动态加载并执行 Lua代码,完成注入热更脚本

热更方式

  1. 可以直接在debug控制台通过调用inject将指定代码注入到指定地址实现,但对于同类型的服务需要手动依次执行,效率较低
  2. 可通过实现sh脚本获取到指定服务地址(例如hotfix服),然后在框架中的hotfix服内实现对框架类型服务的热更lua脚本
  3. 实现sh脚本,用于启动debug控制台,执行热更逻辑
  4. 添加hotcfg,用于配置需要热更的服务与要执行lua脚本路径,并定义lua脚本
  5. 根据框架架构(单点 or 集群),在hotfix服务中实现获取指定服务组的addr
  6. 通过配置的hotcfg实现将lua热更脚本依次注入到目标服务中

拓扑图

方案1:

方案2:

注意事项

  1. 要注意新代码与原有代码的兼容性,避免因为接口变更或依赖关系导致运行时错误
  2. 要注意避免对全局环境造成非预期的影响,尽量将修改限制在局部代码范围内
  3. 需要加入足够的异常处理机制,以在热更新过程中出现异常情况时能够及时捕获并处理,以保证系统的稳定性
  4. 在进行热更新前最好制定好回滚策略,以便在更新失败时能够及时恢复到原有的稳定状态
  5. 尽量避免热更新过程对系统性能造成过大影响,可以在适当的时机进行优化,减少更新对系统性能的影响
  6. 在进行热更新时建议增加详细的日志记录和监控机制,以便随时监测更新过程中的各种信息并进行分析
相关推荐
用户962377954484 天前
VulnHub DC-3 靶机渗透测试笔记
安全
叶落阁主5 天前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
用户962377954487 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机7 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机7 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954488 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star8 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954488 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher9 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
郑州光合科技余经理12 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php