Java热更新的几种方式:
- 基于类加载实现
- 类加载有诸多限制, 比如新的Class虽然被加载了,但是旧class创建出来的对象是无法感知新Class
- forkAndExec
- 可以使用Runtime.getRuntime().exec()实现,但是由于JVM的设置,子进程不会继承父进程的文件描述符。
- 连接迁移
- 启动两个独立的Java进程,然后进行文件描述符迁移,Java原生并不支持迁移文件描述符的系统调用,但好在Netty对该系统内调用进行了封装。
- Old Server启动的时候bind到指定端口,并开启reuse_port。
- New Server启动以后bind到相同端口,开始接收调用端的连接(此时有两个Server在接收调用端的连接)。
- Old Server关闭监听,此后所有新建立的连接将由New Server接管。
- Old Server迁移已经跟调用端建立好的连接到New Server。
- Old Server迁移存量连接各自对应的存量数据(包括部分读进来的数据以及还没有写出去的数据)给New Server。
- New Server拿到迁移连接的存量数据以后开始接管后续的读写事件。
- 为什么在两个新老服务之间可以通过同一个socket文件fid,就能做连接迁移并继承老服务的socket数据,不同进程之间的fid不应该是相互独立的吗?
- 套接字就是一个数字,调用socket函数时,就能够生成(返回)这样一个数字。该数字 具有唯一性,操作系统保证,该数字一旦被某个程序调用socket函数返回,就一直给这个程 序用,直到该程序调用close函数关闭对该数字的调用,该数字才被系统回收(回收后如果 该程序或其他程序又调用了socket函数,该数字可以给该程序或者其他程序复用)。只要 该数字没有被系统回收,不管哪个程序调用'socket函数,都不可能返回一个和该数字一样 的数字,这就是唯一性。