NutzCN Logo
问答 nutz 和 dubbo集成配置问题
发布于 2629天前 作者 qq_e25320ed 2538 次浏览 复制 上一个帖子 下一个帖子
标签:

在dubbo的用户指南里面提到优雅停机,配置以下能设置优雅停机超时时间。
<dubbo:application ...>
<dubbo:parameter key="shutdown.timeout" value="60000" />
</dubbo:application>

 问题是:
    1) 这个参数是不是假设一个线程或一个事务没执行完,执行kill pid 的最大等待超时时间?
    2) 如果duubo与nutz集成,如何配置这个参数?
13 回复

用的是nutzmore里面的插件?

没有使用插件,nutz用的是nutz-1.b.51 ,dubbo自己集成。集成用到您之前提到的nutz和dubbo集成project类似。
https://nutz.cn/yvr/t/q5o92h13niha9o02vr6jis1lsc
但是这个parameter配置比较特别,暂时没想到配置方式。
shutdown.timeout 在ProtocolConfig配置不起作用。10秒后强制关闭JVM。
配在ApplicationConfig 则会报错,没有这个属性可配。

以下是配置示例:
provider.application : {
type : 'com.alibaba.dubbo.config.ApplicationConfig',
fields : {
name : 'P2P',
logger: 'log4j'
}
},
protocol : {
type : 'com.alibaba.dubbo.config.ProtocolConfig',
fields : {
name : 'dubbo',
port:'8010',
contextpath:'FrameServer',
accesslog:'true',
parameters:{"shutdown.timeout" :"60000"}
},
},
reference :{
type :'com.alibaba.dubbo.config.ReferenceConfig',
singleton : false,
fields :{
cluster:"failfast",
loadbalance:"leastactive",
timeout:30000,
application : {
refer : 'provider.application'
},
registry : {
refer : 'registry',
}
}
},

http://dubbo.io/Graceful+Shutdown-zh.htm

附上dubbo用户指南里面优雅停机说明:

优雅停机
(+) (#)

Dubbo是通过JDK的ShutdownHook来完成优雅停机的,所以如果用户使用"kill -9 PID"等强制关闭指令,是不会执行优雅停机的,只有通过"kill PID"时,才会执行。

原理:

服务提供方
停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。
然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
服务消费方
停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
设置优雅停机超时时间,缺省超时时间是10秒:(超时则强制关闭)

<dubbo:application ...>
<dubbo:parameter key="shutdown.timeout" value="60000" />
</dubbo:application>
如果ShutdownHook不能生效,可以自行调用:

ProtocolConfig.destroyAll();

可以翻一下dubbo-spring里面是怎么解析这个参数的

dubbo-spring 调这个方法来解析<dubbo*>标签。
com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser.parse()
解析出parameter后调用。
其中beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
但是nutz应该怎么处理呢?

ApplicationConfig也有paramters参数吗?看看有啥可供设置

ApplicationConfig 没有paramters。看了属性和方法也没有可以设置的。
ApplicationConfig继承AbstractConfig,AbstractConfig也没有合适的配置。

那是时候全文搜索"shutdown.timeout了,dubbo源码里面

在com.alibaba.dubbo.common.Constants 定义:
public static final String SHUTDOWN_TIMEOUT_KEY = "shutdown.timeout";
public static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 60 * 15;
( ps: 我很好奇这里的默认时间并不是10秒,实际优雅停机超时时间确实是10秒。)
在com.alibaba.dubbo.remoting.transport.AbstractClient 中使用到:

 public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
        super(url, handler);
        
        send_reconnect = url.getParameter(Constants.SEND_RECONNECT_KEY, false);
        
        shutdown_timeout = url.getParameter(Constants.SHUTDOWN_TIMEOUT_KEY, Constants.DEFAULT_SHUTDOWN_TIMEOUT);
        
        //默认重连间隔2s,1800表示1小时warning一次.
        reconnect_warning_period = url.getParameter("reconnect.waring.period", 1800);
        
        try {
            doOpen();
        } catch (Throwable t) {
            close();
            throw new RemotingException(url.toInetSocketAddress(), null, 
                                        "Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() 
                                        + " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t);
        }
        try {
            // connect.
            connect();
            if (logger.isInfoEnabled()) {
                logger.info("Start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() + " connect to the server " + getRemoteAddress());
            }
        } catch (RemotingException t) {
            if (url.getParameter(Constants.CHECK_KEY, true)) {
                close();
                throw t;
            } else {
                logger.warn("Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress()
                             + " connect to the server " + getRemoteAddress() + " (check == false, ignore and retry later!), cause: " + t.getMessage(), t);
            }
        } catch (Throwable t){
            close();
            throw new RemotingException(url.toInetSocketAddress(), null, 
                    "Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() 
                    + " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t);
        }
        
        executor = (ExecutorService) ExtensionLoader.getExtensionLoader(DataStore.class)
            .getDefaultExtension().get(Constants.CONSUMER_SIDE, Integer.toString(url.getPort()));
        ExtensionLoader.getExtensionLoader(DataStore.class)
            .getDefaultExtension().remove(Constants.CONSUMER_SIDE, Integer.toString(url.getPort()));
    }

额,url里面,看看构造方法谁调用吧,顺藤摸瓜。。。

查看源码,该构造方法有三处调用。
com.alibaba.dubbo.remoting.transport.AbstractClient.AbstractClient(URL, ChannelHandler)
--> com.alibaba.dubbo.remoting.transport.grizzly.GrizzlyClient.GrizzlyClient(URL, ChannelHandler)
--> com.alibaba.dubbo.remoting.transport.mina.MinaClient.MinaClient(URL, ChannelHandler)
--> com.alibaba.dubbo.remoting.transport.netty.NettyClient.NettyClient(URL, ChannelHandler)

我在这个构造方法打了断点,正常启动--》kill pid。
整个过程并没有进到此断点,是否证明这个参数根本没用到?

@qq_e25320ed 额

那么跳出这个配置来考虑,还有别的方法可以设置优雅停止超时时间吗?
最重要我是想在我执行停机的时候,保证我的数据库事务或者线程执行结束。这个时间起码要需要60秒才合适,10秒确实太短。
AbstractConfig中这段代码设置了优雅停机hook。但是没有地方超时设置,而且证明了这个destroyAll是释放dubbo资源,向zookeeper和客户端推送下机通知。一般只需要1,2秒。

。。。
综上,还是没有找到可以设置优雅超时的方法?

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

添加回复
请先登陆
回到顶部