iohao / ioGame

无锁异步化、事件驱动架构设计的 java netty 网络编程框架; 轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式; 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络服务器;FXGL、Unity、UE、Cocos Creator、Godot、Netty、Protobuf、webSocket、tcp、socket;java Netty 游戏服务器框架;
http://game.iohao.com
GNU Affero General Public License v3.0
904 stars 201 forks source link

多服单进程同一个请求有时正常有时报错 #168

Closed zglbig closed 1 year ago

zglbig commented 1 year ago

我使用多服务单进程启动之后使用unity客户端demo链接,但是同一个请求又是能拿到参数有时拿不到

 // 启动 spring boot
        SpringApplication.run(GameApplication.class, args);
        ExternalGlobalConfig.accessAuthenticationHook.setVerifyIdentity(false);
        // 游戏逻辑服列表
        List<AbstractBrokerClientStartup> logicList = List.of(
                new GameLoginServer(),
                new GameHallServer()
        );

        // 对外开放的端口
        int externalPort = 10100;
        // 游戏对外服
        ExternalServer externalServer = new GameExternal().createExternalServer(externalPort);

        // broker (游戏网关)
        BrokerServer brokerServer = new GameBrokerBoot().createBrokerServer();

        // 多服单进程的方式部署(类似单体应用)
        new SimpleRunOne()
                // broker (游戏网关)
                .setBrokerServer(brokerServer)
                // 游戏对外服
                .setExternalServer(externalServer)
                // 游戏逻辑服列表
                .setLogicServerList(logicList)
                // 启动 游戏对外服、游戏网关、游戏逻辑服
                .startup();

拿不到参数

13:10:26.388 [RequestMessage-8-8] ERROR CommonStdout.handler \(ActionCommandTryHandler.java:47\java.lang.NullPointerException: Cannot invoke "com.iohao.game.action.skeleton.core.ActionCommand.isMethodHasParam()" because "actionCommand" is null
    at com.iohao.game.action.skeleton.core.flow.interal.DefaultActionMethodParamParser.listParam(DefaultActionMethodParamParser.java:45)
    at com.iohao.game.action.skeleton.core.ActionCommandHandler.settingFlowContext(ActionCommandHandler.java:60)
    at com.iohao.game.action.skeleton.core.ActionCommandHandler.handler(ActionCommandHandler.java:37)
    at com.iohao.game.action.skeleton.core.ActionCommandTryHandler.handler(ActionCommandTryHandler.java:45)
    at com.iohao.game.action.skeleton.core.BarSkeleton.handle(BarSkeleton.java:107)
    at com.iohao.game.bolt.broker.core.common.processor.hook.DefaultRequestMessageClientProcessorHook.lambda$processLogic$0(DefaultRequestMessageClientProcessorHook.java:77)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

正常的

┏━━━━━ Debug. [(HallAction.java:19).test0] ━━━━━ [cmd:3-1 196609] ━━━━━ [逻辑服 [登录逻辑服] - id:[85945927-34d6-409d-be1c-3d70aaf0719e]]
┣ userId: 0
┣ 参数: arg0 : LoginVerify(age=273676, jwt=luoyi, loginBizCode=1, time=null, time2=0)
┣ 响应: void
┣ 时间: 0 ms (业务方法总耗时)
┗━━━━━ [ioGame:17.1.46] ━━━━━ [线程:RequestMessage-8-1] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
iohao commented 1 year ago

可以提供复现步骤吗,我在示例代码 https://github.com/iohao/ioGame-example 中没有能复现此错误。

  1. SpringGameOneApplication (启动服务器)
  2. SpringClient (启动模拟客户端);会自动登录。
iohao commented 1 year ago
image image
zglbig commented 1 year ago

你好 这是我刚刚搭的工程 https://gitee.com/zglbk/iogame-test.git

iohao commented 1 year ago

你好 这是我刚刚搭的工程 https://gitee.com/zglbk/iogame-test.git

image
zglbig commented 1 year ago

可以访问了 刚刚设置成私有 然后unity客户端就添加了这个

private void Update() {
        if (Input.GetKeyDown("x")) {
            var loginVerify = new LoginVerify{
                Age = 273676,
                Jwt = "luoyi",
                LoginBizCode = 1
            };
            var myExternalMessage = new MyExternalMessage{
                CmdMerge = CmdMgr.getMergeCmd(3, 1),
                DataContent = loginVerify.ToByteString(),
                ProtocolSwitch = 0,
                CmdCode = 1,
            };
            socket.SendAsync(myExternalMessage.ToByteArray());
        }
    }
iohao commented 1 year ago

造成这个问题原因是,两个不同的游戏逻辑服使用了相同的 name。

image image

默认情况下,

模块名(逻辑服名) 注意,如果没设置 tag,此名也会是 tag 名

而 tag 是可以理解为同类型的游戏逻辑服的一个标识。 在 GameHallServer 中,你提供了 [3-1] 的 action 在 GameLoginServer 中,你提供了 [1-1] 的 action

由于使用了相同的 tag,框架会认为这是同一类型的逻辑服,那么在随机的负载均衡策略中会任选一个逻辑服来处理。比如客户端请求为 [3-1] ,当负载到 GameLoginServer 就找不到了,因为 GameLoginServer 中没有 [3-1] 的 action。

同样的,你在发送 1-1 时,有时也会找不到对应的 action ,因为有可能会将请求负载到 GameHallServer 来处理。

解决方法: 不同的游戏逻辑服类型不要使用相同的 tag。

zglbig commented 1 year ago

感谢抽空回答