Java游戏服务器开发2--上线项目出Bug之热更代码

    技术2022-07-11  84

    本来想着今天要更新Java游戏开发中的架构设计,但是中午前老板问突然问题java项目怎么实现热更新,我想想了,现在很多java开发人员都对热更这个比较陌生,那我今天就来更新一篇关于java热更的文章。文章中有讲的不对的地方请大佬指出。

    热更概述

    对于一个游戏来说,停服一分就会流失很多用户。所以因为一个小bug就停服是不能够被接受的。幸好JVM给我们提供了一些接口,可以简单做一些热更新。修复一些小Bug而不用重启服务。

    JVM可以给运行中的服务器绑定一个代理,在这个代理中可以拿到Instrumentation 这个类的实例,它可以让用户手动修改jvm中的class类,对它进行热更新,但是有一点,用于热更新的新类和老的类方法签名必须一样,即不能修改方法的名字,参数类型,还有修改声明的字段。只能修改方法体里面的代码。一般的小bug都是方法体内的逻辑漏洞,不会做很多大的修改,所以这种方式还是能满足我们的需要求的。

    热更的方式

    JDK代理的两种方式

    premain方式是Java SE5开始就提供的代理方式,但其必须在命令行指定代理jar,并且代理类必须在main方法前启动,它要求开发者在应用启动前就必须确认代理的处理逻辑和参数内容等等

    java – javaagent:LoadAgent.jar -jar GameServer.Jar

    agentmain方式是JavaSE6开始提供,它可以在应用程序的VM启动后再动态添加代理的方式

    在正常的生产环境中是不会开启代理功能的,但是在发生小bug的时候,我们也希望能够在不停服的时候去修改,因此我们使用agentmain的方式来实现热更。

    实现的方式

    仅限我们项目的热更方式

    两个项目: WindListServer服务器列表项目 WindDeployer部署项目 WindGame游戏服项目

    上面是一个网页中对应的热更的方式 其中有三种热更

    配置表热更日志级别热更代码热更

    我们来讲解代码的热更 热更需要用到的参数

    前提是将热更的代码以及jar包都放入到Linux 选择热更的class以及热更的文件夹后点击热更按钮–>触发后台操作如下步骤

    //第一步:保存操作 HotSwapPack hotSwapPack = hotSwapPackService.getOne(packName);//存入数据库 //第二步:更新游戏服后台数据 String url = "http://" + ip + ":" + hport + "/WindGame/background/reloadDataBaseV2"; ErrorResult errorResult = JsonUtil.toJava(HttpUtil.sendPost(url, params), ErrorResult.class); //第三步:删除热更文件 Map<String, String> dParams = new HashMap<>(); dParams.put("packPath", hotSwapPack.getDirName()); String dUrl = "http://" + ip + "/WindDeployer/deletePack"; Message message = JsonUtil.toJava(HttpUtil.sendPost(dUrl, dParams), Message.class); //第四步:从热更文件夹中复制热更文件 String command = "sshpass -p " + config.getPassword() + " " + "scp -r " + hotSwapPack.getDirName() + " " + config.getUserName() + "@" + config.getIp() + ":" + hotRoute; CommandUtil.run(command); //第五步:热更class文件 StringBuilder classes = new StringBuilder(); classes.append(hotSwapPack.getDirName()).append("/classes/@").append(sqlClasses); Map<String, String> reloadParam = new HashMap<>(); reloadParam.put("classes", classes.toString()); reloadParam.put("jarPath", jarRoute);//包路径 String reloadUrl = "http://" + ip + ":" + hport + "/WindGame/background/hotSwap"; Message reloadMessage = JsonUtil.toJava(HttpUtil.sendPost(reloadUrl, reloadParam), Message.class);

    其中第二步的操作是刷新游戏服WindGame的数据

    ConfigDataManager.refresh(dbName + "ConfigContainer");

    第三步删除热更文件是在WindDeployer中进行

    String cmd = "rm -rf " + fileName; log.info("执行指令:" + cmd); String[] cmds = new String[] { "sh", "-c", cmd }; String deleteInfo = CommandUtil.run(cmds);

    第五步:最重要的一步就是热更代码(在WIndGame中操作)

    //热更的类 String classes = request.getParameter("classes"); //热更的jar包位置 String jarPath = request.getParameter("jarPath"); RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); log.info(" runtimeMXBean Name :{} , processId : {}", runtimeMXBean.getName(), runtimeMXBean.getName().split("@")[0]); VirtualMachine virtualMachine = VirtualMachine.attach(runtimeMXBean.getName().split("@")[0]); virtualMachine.loadAgent(jarPath, classes);//"E:\\HotSwap.jar ,E:\\@className1|className2" virtualMachine.detach(); log.info("热更代码:{}成功!", classes);

    经过上面的一顿操作之后,一个热更代码的方式就完成了。

    总结

    热更代码的方式其实很简单,不要想得那么复杂,而且在实际的项目中我们只需要热更一些小的bug的文件,而这些文件一般都是在方法体类的,因此用上面所说的那种方式即可,而且实现起来也方便。

    参考资料

    https://www.infoq.cn/article/javaagent-illustrated/

    下一节预告:Java游戏后台开发中的多线程

    Processed: 0.018, SQL: 12