Apollo 客户端日志抛异常 c.c.f.a.i.RemoteConfigLongPollService : Long polling failed, will retry ...
目录问题背景解决办法根因分析问题背景微服务依赖 apollo-client 并完成配置、启动微服务之后,会每隔两分钟在控制台输出内容 “ c.c.f.a.i.RemoteConfigLongPollService : Long polling failed, will retry in 120 seconds.” ,虽然在理论上没什么影响,但是看着抛异常就很烦!解决办法1、如果是配置了域名转发、网
目录
问题背景
微服务依赖 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
更多推荐




所有评论(0)