Skip to content

Latest commit

 

History

History
139 lines (104 loc) · 6.37 KB

0.1.3-gracefully-优雅关闭.md

File metadata and controls

139 lines (104 loc) · 6.37 KB

优雅摘除服务

说明

我觉得这可以说是 rpc 最需要的一个功能。

因为他的实际意义非常重大,就是可以任意时间发布应用,而对业务无损。

以前发布应用都要等到半夜,很累也容易出问题。

思路

结合 java 的 ShutdownHook 以及 linux 的 kill PID 来达到这个目的。

ShutdownHook 讲解

服务提供方

停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。

然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。

服务消费方

停止时,不再发起新的调用请求,所有新的调用在客户端即报错。

然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。

钩子函数的默认实现

代码实现

当然这里也结合了服务的状态管理和资源管理。

一个负责控制状态,一个负责关闭资源。

    /**
     * (1)设置 status 状态为等待关闭
     * (2)查看是否 {@link InvokeManager#remainsRequest()} 是否包含请求
     * (3)超时检测-可以不添加,如果难以关闭成功,直接强制关闭即可。
     * (4)关闭所有线程池资源信息
     * (5)设置状态为成功关闭
     */
    @Override
    protected void doHook() {
        // 设置状态为等待关闭
        statusManager.status(StatusEnum.WAIT_SHUTDOWN.code());
        LOG.info("[Shutdown] set status to wait for shutdown.");

        // 循环等待当前执行的请求执行完成
        while (invokeManager.remainsRequest()) {
            LOG.info("[Shutdown] still remains request, wait for a while.");
            Waits.waits(10);
        }

        // 销毁所有资源
        LOG.info("[Shutdown] resourceManager start destroy all resources.");
        this.resourceManager.destroyAll();
        LOG.info("[Shutdown] resourceManager finish destroy all resources.");

        // 设置状态为关闭成功
        statusManager.status(StatusEnum.SHUTDOWN_SUCCESS.code());
        LOG.info("[Shutdown] set status to shutdown success.");
    }

调用

钩子函数的使用也比较简单,如下:

/**
 * 添加 rpc shutdown hook
 * @param rpcShutdownHook 钩子函数实现
 * @since 0.1.3
 */
public static void rpcShutdownHook(final RpcShutdownHook rpcShutdownHook) {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            rpcShutdownHook.hook();
        }
    });
}

测试代码

注册中心

正常启动

服务端

正常启动

客户端

正常启动

shutdown

  • 客户端
[INFO] [2019-11-01 23:10:51.709] [Thread-1] [c.g.h.r.c.s.h.AbstractShutdownHook.hook] - [Shutdown Hook] start
[INFO] [2019-11-01 23:10:51.710] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] set status to wait for shutdown.
[INFO] [2019-11-01 23:10:51.711] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] resourceManager start destroy all resources.
[INFO] [2019-11-01 23:10:51.711] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] destroyableList.size(): 1
[INFO] [2019-11-01 23:10:51.712] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] destroy destroyable: com.github.houbb.rpc.common.remote.netty.impl.DefaultNettyClient@10736d9
[INFO] [2019-11-01 23:10:51.713] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] start close future.
[INFO] [2019-11-01 23:10:51.715] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] 关闭完成
[INFO] [2019-11-01 23:10:51.727] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] 线程池关闭完成
[INFO] [2019-11-01 23:10:51.728] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] clear destroyableList
[INFO] [2019-11-01 23:10:51.729] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] resourceManager finish destroy all resources.
[INFO] [2019-11-01 23:10:51.729] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] set status to shutdown success.
[INFO] [2019-11-01 23:10:51.730] [Thread-1] [c.g.h.r.c.s.h.AbstractShutdownHook.hook] - [Shutdown Hook] end
  • 服务端
[INFO] [2019-11-01 23:11:11.433] [Thread-1] [c.g.h.r.c.s.h.AbstractShutdownHook.hook] - [Shutdown Hook] start
[INFO] [2019-11-01 23:11:11.434] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] set status to wait for shutdown.
[INFO] [2019-11-01 23:11:11.435] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] resourceManager start destroy all resources.
[INFO] [2019-11-01 23:11:11.436] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] destroyableList.size(): 2
[INFO] [2019-11-01 23:11:11.437] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] destroy destroyable: com.github.houbb.rpc.common.remote.netty.impl.DefaultNettyServer@2c41f4
[INFO] [2019-11-01 23:11:11.437] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyServer.destroy] - [Netty Server] 开始关闭
[INFO] [2019-11-01 23:11:11.439] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyServer.destroy] - [Netty Server] 完成关闭
[INFO] [2019-11-01 23:11:11.469] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] destroy destroyable: com.github.houbb.rpc.common.remote.netty.impl.DefaultNettyClient@12cbfa
[INFO] [2019-11-01 23:11:11.470] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] start close future.
[INFO] [2019-11-01 23:11:11.471] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] 关闭完成
[INFO] [2019-11-01 23:11:11.481] [Thread-1] [c.g.h.r.c.r.n.i.DefaultNettyClient.destroy] - [Netty Client] 线程池关闭完成
[INFO] [2019-11-01 23:11:11.481] [Thread-1] [c.g.h.r.c.s.r.i.DefaultResourceManager.destroyAll] - [Resource] clear destroyableList
[INFO] [2019-11-01 23:11:11.481] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] resourceManager finish destroy all resources.
[INFO] [2019-11-01 23:11:11.482] [Thread-1] [c.g.h.r.c.s.h.DefaultShutdownHook.doHook] - [Shutdown] set status to shutdown success.
[INFO] [2019-11-01 23:11:11.482] [Thread-1] [c.g.h.r.c.s.h.AbstractShutdownHook.hook] - [Shutdown Hook] end