dubbo elegantly down the principle

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/liujunzxcv/article/details/102751555

Achieve dubbo elegant downtime, first and foremost dependent on the jvm ShutdownHook hook function, for example dubbo 2.5.x version, in AbstractConfig defined:

static {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                if (logger.isInfoEnabled()) {
                    logger.info("Run shutdown hook now.");
                }
                ProtocolConfig.destroyAll();
            }
        }, "DubboShutdownHook"));
    }

It registered a shutdown hook in a static block which, when ready to close when jvm (tomcat shutdown command, kill pid, etc.), it will automatically trigger registration closed good hook, execution ProtocolConfig.destroyAll () method, which is mainly made from the registry (such as zookeeper) deregistration, closed provider, shut down consumer three things.

Here Insert Picture Description

1, the first step in de-registration, consumer and provider will be registered in the temporary node zookeeper, at first calling the shutdown of destroyAll AbstractRegistryFactory ():

public static void destroyAll() {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Close all registries " + getRegistries());
        }
        // Lock up the registry shutdown process
        LOCK.lock();
        try {
            for (Registry registry : getRegistries()) {
                try {
                    registry.destroy();
                } catch (Throwable e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
            REGISTRIES.clear();
        } finally {
            // Release the lock
            LOCK.unlock();
        }
    }

In this method, first of all the registry to get the machine (dubbo official role Description: registry is a registered service registry and discovery for ease of understanding, registry can loosely be seen as native to the overall service registration information registry. ), then calls destroy registry of () method performs de-registration. It is worth mentioning that, dubbo which uses a lot of design patterns, the logic part of the whole registry uses a template pattern:

Here Insert Picture Description

For example, we use a zookeeper, you will come ZookeeperRegistry.destroy (),

@Override
    public void destroy() {
        super.destroy();
        try {
            zkClient.close();
        } catch (Exception e) {
            logger.warn("Failed to close zookeeper client " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

Which in turn calls his father and grandfather class FailbackRegistry class AbstractRegistry.destroy (), which will be executed in

   for (URL url : new HashSet<>(getRegistered())) {
                if (url.getParameter(DYNAMIC_KEY, true)) {
                    try {
                        unregister(url);
                        if (logger.isInfoEnabled()) {
                            logger.info("Destroy unregister url " + url);
                        }
                    } catch (Throwable t) {
                        logger.warn("Failed to unregister url " + url + " to registry " + getUrl() + " on destroy, cause: " + t.getMessage(), t);
                    }
                }
            }

This is done in order to perform some common processing virtual base class, it is not dependent on the specific registry, such as the private final Set <URL> registeredregistered URL Set corresponding URL (provider and consumer) deleted.
And in ZookeeperRegistry in:

@Override
    public void doUnregister(URL url) {
        try {
            zkClient.delete(toUrlPath(url));
        } catch (Throwable e) {
            throw new RpcException("Failed to unregister " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

Delete nodes added in the zookeeper. And the aforementioned zkClient.close (); Close zk client.
De-registration process basically the same.

2, from the registry after deregistration, the unit with the connection between the registry is disconnected, the next destroy all protocol. layer protocol belongs to a remote call, RPC calls package.

private void destroyProtocols() {
		//获取Protocol的扩展点实现类
        ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
        for (String protocolName : loader.getLoadedExtensions()) {
            try {
                Protocol protocol = loader.getLoadedExtension(protocolName);
                if (protocol != null) {
                    protocol.destroy();
                }
            } catch (Throwable t) {
                logger.warn(t.getMessage(), t);
            }
        }
    }

Obtained by looping through all the protocol extension point implementations, including the actual external communication protocol (here dubbo), injvm (native communication), registry protocol, just to focus on dubbo protocol, came DubboProtocol.destroy ():

public void destroy() {
        for (String key : new ArrayList<String>(serverMap.keySet())) {
            ExchangeServer server = serverMap.remove(key);
            if (server != null) {
                try {
                    if (logger.isInfoEnabled()) {
                        logger.info("Close dubbo server: " + server.getLocalAddress());
                    }
                    server.close(getServerShutdownTimeout());
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
            }
        }

        for (String key : new ArrayList<String>(referenceClientMap.keySet())) {
            ExchangeClient client = referenceClientMap.remove(key);
            if (client != null) {
                try {
                    if (logger.isInfoEnabled()) {
                        logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress());
                    }
                    client.close(getServerShutdownTimeout());
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
            }
        }

        for (String key : new ArrayList<String>(ghostClientMap.keySet())) {
            ExchangeClient client = ghostClientMap.remove(key);
            if (client != null) {
                try {
                    if (logger.isInfoEnabled()) {
                        logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress());
                    }
                    client.close(getServerShutdownTimeout());
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
            }
        }
        stubServiceMethodsMap.clear();
        super.destroy();
    }

First of all here to do server-side closed, call ExchangeServer interface implementation class HeaderExchangeServer

Here Insert Picture Description

public void close(final int timeout) {
        startClose();
        if (timeout > 0) {
            final long max = (long) timeout;
            final long start = System.currentTimeMillis();
            if (getUrl().getParameter(Constants.CHANNEL_SEND_READONLYEVENT_KEY, true)) {
                logger.info("============getUrl():"  + getUrl());
                sendChannelReadOnlyEvent();
            }
            while (HeaderExchangeServer.this.isRunning()
                    && System.currentTimeMillis() - start < max) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    logger.warn(e.getMessage(), e);
                }
            }
        }
        doClose();
        server.close(timeout);
    }

If you send readonly event is set, the first execution sendChannelReadOnlyEvent (); this is a one-way request, sent by the service end consumer end, I want to tell the consumer channel is closed, and only read content from channle not been read in.
HeaderExchangeServer.this.isRunning () to determine whether there is a client holding connection, if any, sleep 10ms until then been trying to be able to close (here 2.5.x version exists bug, resulting in not correctly determine the client connection holds, Therefore, version 2.5 which required a shutdown protocol after deregistration sleep 10s before).

In doClose () inside:

private void doClose() {
        if (!closed.compareAndSet(false, true)) {
            return;
        }
        stopHeartbeatTimer();
        try {
            scheduled.shutdown();
        } catch (Throwable t) {
            logger.warn(t.getMessage(), t);
        }
    }

Perform a shutdown heartbeat detection between server client TCP long connections.

In server.close (timeout); Method:

Here Insert Picture Description

Still use the template mode, first AbstractServer shut down the thread pool:

public void close(int timeout) {
        ExecutorUtil.gracefulShutdown(executor, timeout);
        close();
    }


public void close() {
        if (logger.isInfoEnabled()) {
            logger.info("Close " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());
        }
        ExecutorUtil.shutdownNow(executor, 100);
        try {
            super.close();
        } catch (Throwable e) {
            logger.warn(e.getMessage(), e);
        }
        try {
            doClose();
        } catch (Throwable e) {
            logger.warn(e.getMessage(), e);
        }
    }

Then doClose (); the actual implementation class (such NettyServer) closed the connection actually established.

Here close to the completion of the server, the next closes the client, because the client and server shut down is very similar, not repeat them.

to sum up

Dubbo closed the entire service process may be summarized as follows:

  • jvm closed, shut down the service shutdown hook to call dubbo
  • Registration center deregister, delete consumer and provider node
  • Server shut down
  • protocol of cancellation
  • Send readonly
  • Connecting the client to stop long heartbeat
  • The thread pool is closed
  • NettyServer Close

Continued: There is closing hook dubbo registered jvm problems.

Guess you like

Origin blog.csdn.net/liujunzxcv/article/details/102751555