目录

问题背景

解决办法

根因分析


问题背景

微服务依赖 apollo-client 并完成配置、启动微服务之后,会每隔两分钟在控制台输出内容 “ c.c.f.a.i.RemoteConfigLongPollService : Long polling failed, will retry in 120 seconds. ” ,虽然在理论上没什么影响,但是看着抛异常就很烦!

解决办法

1、如果是配置了域名转发、网关等,就把域名对应的网关超时时间修改成 大于 65s 

2、取消 绕开 configserver 的服务发现,即大概率是因为直接通过变量设置 meta,例如在启动命令中加以下内容。这样就不会通过注册中心的服务发现去请求。

-Dapollo.configService=https://xxxx.xxx.com/configserver

根因分析

作为客户端,是通过请求 apollo config server 的 /notifications/v2 接口获取配置的,/notifications/v2 接口不会立即返回结果,而是把请求挂起。考虑到会有数万客户端向服务端发起长连,因此在服务端使用了 Spring DeferredResult 来提供 Http Long Polling 请求。如果在60秒内没有该客户端关心的配置发布,那么会返回Http状态码304给客户端。如果有该客户端关心的配置发布,/notifications/v2 会调用 DeferredResult 的 setResult 方法,传入有配置变化的 namespace 信息,同时该请求会立即返回。客户端从返回的结果中获取到配置变化的namespace后,会立即请求Config Service获取该namespace的最新配置。

开始扒代码!

客户端发送请求的类路径 “ com\ctrip\framework\apollo\internals\RemoteConfigLongPollService.java ”

  private void startLongPolling() {
    if (!m_longPollStarted.compareAndSet(false, true)) {
      //already started
      return;
    }
    try {
      final String appId = m_configUtil.getAppId();
      final String cluster = m_configUtil.getCluster();
      final String dataCenter = m_configUtil.getDataCenter();
      final String secret = m_configUtil.getAccessKeySecret();
      final long longPollingInitialDelayInMills = m_configUtil.getLongPollingInitialDelayInMills();
      m_longPollingService.submit(new Runnable() {
        @Override
        public void run() {
          if (longPollingInitialDelayInMills > 0) {
            try {
              logger.debug("Long polling will start in {} ms.", longPollingInitialDelayInMills);
              TimeUnit.MILLISECONDS.sleep(longPollingInitialDelayInMills);
            } catch (InterruptedException e) {
              //ignore
            }
          }
          doLongPollingRefresh(appId, cluster, dataCenter, secret);
        }
      });
    } catch (Throwable ex) {
      m_longPollStarted.set(false);
      ApolloConfigException exception =
          new ApolloConfigException("Schedule long polling refresh failed", ex);
      Tracer.logError(exception);
      logger.warn(ExceptionUtil.getDetailMessage(exception));
    }
  }

config server 服务端接受请求的类路径 “ com\ctrip\framework\apollo\configservice\controller\NotificationControllerV2.java ”

@GetMapping
  public DeferredResult<ResponseEntity<List<ApolloConfigNotification>>> pollNotification(
      @RequestParam(value = "appId") String appId,
      @RequestParam(value = "cluster") String cluster,
      @RequestParam(value = "notifications") String notificationsAsString,
      @RequestParam(value = "dataCenter", required = false) String dataCenter,
      @RequestParam(value = "ip", required = false) String clientIp) {
...
}

这个 60s 是可以通过改源码修改的,类路径 “ com\ctrip\framework\apollo\biz\config\BizConfig.java ”

  private static final int DEFAULT_ITEM_KEY_LENGTH = 128;
  private static final int DEFAULT_ITEM_VALUE_LENGTH = 20000;
  private static final int DEFAULT_APPNAMESPACE_CACHE_REBUILD_INTERVAL = 60; //60s
  private static final int DEFAULT_GRAY_RELEASE_RULE_SCAN_INTERVAL = 60; //60s
  private static final int DEFAULT_APPNAMESPACE_CACHE_SCAN_INTERVAL = 1; //1s
  private static final int DEFAULT_ACCESSKEY_CACHE_SCAN_INTERVAL = 1; //1s
  private static final int DEFAULT_ACCESSKEY_CACHE_REBUILD_INTERVAL = 60; //60s
  private static final int DEFAULT_RELEASE_MESSAGE_CACHE_SCAN_INTERVAL = 1; //1s
  private static final int DEFAULT_RELEASE_MESSAGE_SCAN_INTERVAL_IN_MS = 1000; //1000ms
  private static final int DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH = 100;
  private static final int DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH_INTERVAL_IN_MILLI = 100;//100ms
  private static final int DEFAULT_LONG_POLLING_TIMEOUT = 60; //60s

 

Logo

一站式 AI 云服务平台

更多推荐