• 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();
            }
     }
  • 相关阅读:
    Node(十一)mongoose配合Node实现注册登录(注册上传头像,登录成功后显示用户信息)
    JS案例:购物车操作(简单实现)
    JS案例:Jq中的fadeOut和fadeIn实现简单轮播(没完善,简单实现)
    JS案例:小球拖动,记录轨迹,并原路返回
    html框架frame iframe
    单元测试
    软件测试计划、依据、规范
    软件测试
    html表单
    html块 布局
  • 原文地址:https://www.cnblogs.com/zhangjianbin/p/6617069.html
Copyright © 2020-2023  润新知