IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    跨服Lua调用

    金庆发表于 2017-03-02 09:12:00
    love 0
    跨服Lua调用

    (金庆的专栏 2017.3)

    跨服Lua调用是指服务器集群内部A服调用B服上的脚本。

    服务器之间已经实现RPC调用,Lua调用是Rpc调用的简化方式。

    示例:
        -- Tell remote server svr_id that game_clt_id is disconnected.
        local arguments = { "Remote.ClientDisconnected", game_clt_id }
        remote_runner.run_mfa(svr_id, "event.dispatcher",
            "dispatch", arguments)

    以上例子相当于调用了其他服务器上的代码:
        require("event.dispatcher").dispatch("Remote.ClientDisconnected", game_clt_id)

    需要参数为:
    * 远程服务器ID
    * Lua模块名
    * Lua模块中的函数名
    * 调用参数列表

    remote_runner这样实现:

    -- 运行另一服务器上的Lua代码
    -- 也支持本服运行(本服RPC调用)

    local M = {}

    local log = require("log"):new("remote_runner")
    local pb = require("protobuf")
    local serpent = require("serpent")

    -- on_result(result) 生成 rpc 回调函数 cb(resp_str)
    local function get_mfa_cb(on_result)
        if (not on_result) then return nil end
        assert("function" == type(on_result))

        local cb = function(resp_str)
            assert("string" == type(resp_str))
            local resp = pb.decode("svr.RunLuaMfaResponse", resp_str)
            local ok, copy = serpent.load(resp.returned_dump)
            assert(ok, "Run mfa returns invalid value.")
            log:debug("RunLuaMfaResponse: %s", serpent.line(copy))
            on_result(table.unpack(copy)) -- 回调时执行
        end  -- cb

        return cb
    end  -- get_mfa_cb()

    -- Run module function with arguments on remote server.
    -- 示例 rum_mfa(123, "event.dispatcher", "dispatch", {"EventName", 1,2,3}, nil)
    function M.run_mfa(svr_id, module_name, function_name, arguments, on_result)
        assert("number" == type(svr_id))
        assert("string" == type(module_name))
        assert("string" == type(function_name))
        assert("table" == type(arguments))
        assert(nil == on_result or "function" == type(on_result))
        log:debug("Request to call Svr_%s %s.%s()", svr_id, module_name, function_name)
        local req = {
            module_name = module_name,
            function_name = function_name,
            arguments_dump = serpent.dump(arguments)
        }
        local req_str = pb.encode("svr.RunLuaMfaRequest", req)
        local cb = get_mfa_cb(on_result)
        c_rpc.request_svr(svr_id, "svr.RunLua", "RunMfa", req_str, cb)
    end  -- run()

    return M

    通过Rpc服务RunLua.RunMfa实现。run_lua.proto如下定义

    syntax = "proto3";
    package svr;

    // 服务器内部跨服调用Lua
    service RunLua {
        // 运行 module.function(...arguments...)
        rpc RunMfa(RunLuaMfaRequest) returns (RunLuaMfaResponse);
    }

    message RunLuaMfaRequest {
        string module_name = 1;
        string function_name = 2;
        // arguments_dump = serpent.dump({1,2,3})
        string arguments_dump = 3;
    }

    message RunLuaMfaResponse {
        // Get returned table copy:
        // local ok, copy = serpent.load(returned_dump)
        string returned_dump = 1;
    }

    服务这样实现:

    -- svc_run_lua.lua
    -- Run lua by other servers.

    local M = {}

    local log = require("log"):new("svc_run_lua")
    local pb = require("protobuf")

    -- Run module.function(...arguments...)
    function M.RunMfa(ctx, content)
        local req = pb.decode("svr.RunLuaMfaRequest", content)
        log:debug("RunMfa %s.%s", req.module_name, req.function_name)  -- todo: from where?
        local mod = require(req.module_name)
        local fun = mod[req.function_name]
        local ok, arguments = serpent.load(serpent.dump(req.arguments_dump))
        assert(ok, "Illegal arguments.")
        local result_table = table.pack(fun(table.unpack(arguments)))
        local resp = { returned_dump = serpent.dump(result_table) }
        local resp_str = pb.encode("svr.RunLuaMfaResponse", resp)
        c_rpc.reply_to(ctx, resp_str)
    end  -- Run()

    return M


    金庆 2017-03-02 17:12 发表评论


沪ICP备19023445号-2号
友情链接