apollo客户端长连接实现

/** 单线程池 */
m_longPollingService = Executors.newSingleThreadExecutor(
    ApolloThreadFactory.create("RemoteConfigLongPollService", true));
/** 使用google令牌桶算法实现限制请求量,默认每秒生产2个令牌(即每秒最多只有两个请求) */
m_longPollRateLimiter = RateLimiter.create(m_configUtil.getLongPollQPS());
 
private void startLongPolling() {
  /** 进入长论询之前 设置m_longPollStarted为true,以防提交重复的长链接任务*/
  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 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);
      }
    });
  } 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));
  }
}
 
 
private void doLongPollingRefresh(String appId, String cluster, String dataCenter) {
  final Random random = new Random();
  ServiceDTO lastServiceDto = null;
  /** 长轮询没有停止、当前线程没有调Interrupted*/
  while (!m_longPollingStopped.get() && !Thread.currentThread().isInterrupted()) {
   /** 等待取一个令牌,最多等待5秒 */
    if (!m_longPollRateLimiter.tryAcquire(5, TimeUnit.SECONDS)) {
      try {
        TimeUnit.SECONDS.sleep(5);
      } catch (InterruptedException e) {
      }
    }
    /** 调用栈记录,但pollNotification其实还没有实现(调用链路监控简单就是这样实现的)*/
    Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "pollNotification");
    String url = null;
    try {
      if (lastServiceDto == null) {
        List<ServiceDTO> configServices = getConfigServices();
        lastServiceDto = configServices.get(random.nextInt(configServices.size()));
      }
      /** 使用google Escape对url特殊字符进行转义*/
      url =
          assembleLongPollRefreshUrl(lastServiceDto.getHomepageUrl(), appId, cluster, dataCenter,
              m_notifications);
 
      logger.debug("Long polling from {}", url);
      HttpRequest request = new HttpRequest(url);
      request.setReadTimeout(LONG_POLLING_READ_TIMEOUT);
 
      transaction.addData("Url", url);
 
      /** 里面实现就是使用java原生的HttpURLConnection */
      final HttpResponse<List<ApolloConfigNotification>> response =
          m_httpUtil.doGet(request, m_responseType);
 
      logger.debug("Long polling response: {}, url: {}", response.getStatusCode(), url);
      if (response.getStatusCode() == 200 && response.getBody() != null) {
        /** 更新请求命名空间通知id*/
        updateNotifications(response.getBody());
        /** 封装配置信息,主要确保每次下发的配置通知id最新的*/
        updateRemoteNotifications(response.getBody());
        transaction.addData("Result", response.getBody().toString());
        /** 同步本地的远程配置仓库*/
        notify(lastServiceDto, response.getBody());
      }
 
      //try to load balance
      if (response.getStatusCode() == 304 && random.nextBoolean()) {
        lastServiceDto = null;
      }
 
      m_longPollFailSchedulePolicyInSecond.success();
      transaction.addData("StatusCode", response.getStatusCode());
      transaction.setStatus(Transaction.SUCCESS);
    } catch (Throwable ex) {
      lastServiceDto = null;
      Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
      transaction.setStatus(ex);
      long sleepTimeInSecond = m_longPollFailSchedulePolicyInSecond.fail();
      logger.warn(
          "Long polling failed, will retry in {} seconds. appId: {}, cluster: {}, namespaces: {}, long polling url: {}, reason: {}",
          sleepTimeInSecond, appId, cluster, assembleNamespaces(), url, ExceptionUtil.getDetailMessage(ex));
      try {
        TimeUnit.SECONDS.sleep(sleepTimeInSecond);
      } catch (InterruptedException ie) {
        //ignore
      }
    } finally {
      transaction.complete();
    }
  }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值