Eureka服務下線(Cancel)源碼分析


Cancel(服務下線)

在Service Provider服務shut down的時候,需要及時通知Eureka Server把自己剔除,從而避免其它客戶端調用已經下線的服務,導致服務不可用。

com.netflix.discovery.DiscoveryClient中shutdown()的867行。

/**
    * Shuts down Eureka Client. Also sends a deregistration request to the
    * eureka server.
    */
   @PreDestroy
   @Override
   public synchronized void shutdown() {
       if (isShutdown.compareAndSet(false, true)) {
           logger.info("Shutting down DiscoveryClient ...");
           if (statusChangeListener != null && applicationInfoManager != null) {
               applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId());
           }
           cancelScheduledTasks();
           // If APPINFO was registered
           if (applicationInfoManager != null && clientConfig.shouldRegisterWithEureka()) {
               applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
               //調用下線接口
               unregister();
           }
           if (eurekaTransport != null) {
               eurekaTransport.shutdown();
           }
           heartbeatStalenessMonitor.shutdown();
           registryStalenessMonitor.shutdown();
           logger.info("Completed shut down of DiscoveryClient");
       }
  }

 

 

@PreDestroy注解或shutdown()的方法是服務下線的入口

com.netflix.discovery.DiscoveryClientunregister()897

void unregister() {
        // It can be null if shouldRegisterWithEureka == false
  if(eurekaTransport != null && eurekaTransport.registrationClient != null) {
    try {
         logger.info("Unregistering ...");
         //發送服務下線請求
         EurekaHttpResponse<Void> httpResponse = eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId());
         logger.info(PREFIX + appPathIdentifier + " - deregister  status: " + httpResponse.getStatusCode());
      } catch (Exception e) {
                logger.error(PREFIX + appPathIdentifier + " - de-registration failed" + e.getMessage(), e);
      }
 }
}

 

 

Eureka Server服務下線實現細節

  1. com.netflix.eureka.resources.InstanceResource中的280行中的cancelLease()方法

@DELETE
public Response cancelLease(
 @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
   //調用cancel
   boolean isSuccess = registry.cancel(app.getName(), id,
                "true".equals(isReplication));
  if (isSuccess) {
     logger.debug("Found (Cancel): " + app.getName() + " - " + id);
            return Response.ok().build();
   } else {
     logger.info("Not Found (Cancel): " + app.getName() + " - " + id);
            return Response.status(Status.NOT_FOUND).build();
       }
}

 

 

com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl中的376

@Override
    public boolean cancel(final String appName, final String id,
                          final boolean isReplication) {
     if (super.cancel(appName, id, isReplication)) {
            //服務下線成功后,同步更新信息到其它Eureka Server節點
            replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
            synchronized (lock) {
                if (this.expectedNumberOfRenewsPerMin > 0) {
                    // Since the client wants to cancel it, reduce the threshold (1 for 30 seconds, 2 for a minute)
                    this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;
                    this.numberOfRenewsPerMinThreshold =
                            (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
                }
            }
            return true;
     }
        return false;
}

 

 

在com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl中的618行,主要接口實現方式和register基本一致:首先更新自身Eureka Server中服務的狀態,再同步到其它Eureka Server中。

private void replicateToPeers(Action action, String appName, String id,
                                  InstanceInfo info /* optional */,
                                  InstanceStatus newStatus /* optional */, boolean isReplication) {
        Stopwatch tracer = action.getTimer().start();
        try {
            if (isReplication) {
                numberOfReplicationsLastMin.increment();
            }
            // If it is a replication already, do not replicate again as this will create a poison replication
            if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
                return;
            }
            // 同步把服務信息同步到其它的Eureka Server中
            for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
                // If the url represents this host, do not replicate to yourself.
                if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
                    continue;
                }
                //根據action做相應操作的同步
                replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
            }
        } finally {
            tracer.stop();
        }
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM