Nacos 1.0.1 Config客户端重连机制优化

https://developer.aliyun.com/article/706613

Nacos Config模块通过一个长轮询任务LongPollingRunnable不断向 Config Server询问自己感兴趣的配置是否更新,无论本次任务执行成功还是出现异常,都是直接再次放回Executor中再次执行;因此如果当 Config Server 出现无法服务时,会导致LongPollingRunnable打印大量的错误日志。

为了改善 Config 客户端与 Config Server 出现连接异常时的大量错误日志打印以及频繁的请求重试,我们在1.0.1版本对 Config 客户端重连机制做了两方面的优化,第一个优化是当任务LongPollingRunnable在执行时出现异常,将对任务采取延迟执行的惩罚策略,推迟该任务的下一次被调度执行的时间,主要逻辑代码如下

class LongPollingRunnable implements Runnable {
    private int taskId;

    public LongPollingRunnable(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {

        List<CacheData> cacheDatas = new ArrayList<CacheData>();
        List<String> inInitializingCacheList = new ArrayList<String>();
    try {
            ...
            // check server config
            List<String> changedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);

            ...
            inInitializingCacheList.clear();

            executorService.execute(this);

        } catch (Throwable e) {

            // If the rotation training task is abnormal, the next execution time of the task will be punished
            LOGGER.error("longPolling error : ", e);
            executorService.schedule(this, taskPenaltyTime, TimeUnit.MILLISECONDS);
        }
    }
}

第二个优化是ServerHttpAgent中执行 Http 请求的重试机制优化,在1.0.1版本中,加入了 Config Server 地址列表轮训次数的限制;在1.0.1版本之前,认为 Http 请求遇到ConnectException或者SocketTimeoutException时,应在 timeout 时间内进行重试;但是可能会导致一个问题,如果 Config Server 不可用(宕机或者无法响应客户端请求),会导致在 timeout 时间内Config客户端因为重试发送大量的请求给 Config Server,但是这些请求其实都是无法成功的;因此为了避免此情况,加入了 Config Server 轮训次数限制,如果对 Config Server 地址列表轮训次数达到maxRetry,则默认请求失败,抛出异常,主要逻辑代码如下

@Override
public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
    final long endTime = System.currentTimeMillis() + readTimeoutMs;
    boolean isSSL = false;

    String currentServerAddr = serverListMgr.getCurrentServerAddr();
    int maxRetry = this.maxRetry;

    do {

        try {
            List<String> newHeaders = getSpasHeaders(paramValues);
            if (headers != null) {
                newHeaders.addAll(headers);
            }

            ...
            } else {
                // Update the currently available server addr
                serverListMgr.updateCurrentServerAddr(currentServerAddr);
                return result;
            }
        } catch (ConnectException ce) {
            LOGGER.error("[NACOS ConnectException httpPost] currentServerAddr: {}", currentServerAddr);
        } catch (SocketTimeoutException stoe) {
            LOGGER.error("[NACOS SocketTimeoutException httpPost] currentServerAddr: {}, err : {}", currentServerAddr, stoe.getMessage());
        } catch (IOException ioe) {
            LOGGER.error("[NACOS IOException httpPost] currentServerAddr: " + currentServerAddr, ioe);
            throw ioe;
        }

        if (serverListMgr.getIterator().hasNext()) {
            currentServerAddr = serverListMgr.getIterator().next();
        } else {
            maxRetry --;
            if (maxRetry < 0) {
                throw new ConnectException("[NACOS HTTP-POST] The maximum number of tolerable server reconnection errors has been reached");
            }
            serverListMgr.refreshCurrentServerAddr();
        }

    } while (System.currentTimeMillis() <= endTime);

    ...
}

同时,为了方便使用者,以上优化点涉及的几个参数:taskPenaltyTime——任务惩罚执行时间、timeout——请求超时时间、maxRetry——最大重试次数,都可以有使用者自行设置,配置的方法很简单,代码如下

Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:" + port);
// 设置长轮询请求超时时间(最小为10s)
properties.put(PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT, "20000");
// 设置任务惩罚时间
properties.put(PropertyKeyConst.CONFIG_RETRY_TIME, 3000);
// 设置最大重试次数
properties.put(PropertyKeyConst.MAX_RETRY, 5);
configService = NacosFactory.createConfigService(properties);

具体的优化效果可以参考代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值