rpc - changnet/MServer GitHub Wiki

rpc

为了简化服务器间的交互,提供了rpc。与协议交互相比,rpc不用编写schema文件,不用定义协议号。具体的使用方式,参考rpc.lua的实现。

底层编码

自定义的kv打包方式

设计

很长一段时间,rpc模块的设计是这样的

Rpc.call(addr, Remote.func, p1, p2, p3, ...)

通过传入函数指针,获取函数名。然后把函数名和参数一起打包发出去。这样做的原因是Remote.func是一个函数指针,IDE是可以直接跳转的,这样写代码和跟踪调试都很方便。

但它有个问题,就是需要获得函数指针。这在以前旧框架上没啥问题,因为线程不多,每个线程所有脚本都加载,所以是能取得到函数指针的。现在拆分成多线程后,会开启多个worker,要获得函数指针就必须每个worker都加载这些脚本。但worker的数量太多这显然不现实,因此取不到指针了。

考虑过注册函数的方式。即每个worker启动时,收集rpc函数,同步到其他worker,这样就能获得函数指针了。但这有个问题,热更的时候。worker A热更了,需要调用worker B中的函数,但worker B数据还没同步过来,这时候就取不到函数指针。

解决的办法是用工具或者服务器本身在开发时自动生成一个rpc定义文件。热更时,就不需要同步函数了,直接从定义文件读取。但我还是觉得这个不太可靠,开发过程中略显繁琐。

另一种方式,则是类似于python的

Rpc.Remote.func(addr, p1, p2, p3, ...)

利用lua的元表,可以获取Remote.func的名字。这种调用方式较为舒服,不过有个问题是现在所有的IDE都不支持代码提示了。所以除非修改插件,不然对开发影响很大。

再来看下java的方式,它是通过@DubboReference这个注解来引入一个对象,如果有多个服务提供同一个接口,需要用group等引入不同对象,如@DubboReference(version = "1.0.0", group = "group1")

public class Consumer implements CommandLineRunner {
    @DubboReference
    private DemoService demoService;

    @Override
    public void run(String... args) throws Exception {
        String result = demoService.sayHello("world");
        System.out.println("Receive result ======> " + result);
    }
}

翻译为lua差不多就是

local Remote = Rpc.Remote(addr)
Remote.func(p1, p2, p3, ...)

这是可行的,但调用略繁琐,并且IDE也识别不出来。

而skynet的skynet.call(addr, "lua", "CMD", ...)则是纯字符串了,更不用说识别模块和函数指针了

设计rpc模块,希望有几点

  1. 不需要像java那种注册,不然热更会很麻烦
  2. 不需要额外定义函数
  3. 能在IDE直接跳转,方便开发。(哪怕是修改插件)
⚠️ **GitHub.com Fallback** ⚠️