eureka 源码分析三--InstanceInfo 中OverriddenStatus的作用

1. eureka server端实例存储结构

ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>
其中key = appName,value = ConcurrentHashMap

//存储覆盖状态
protected final ConcurrentMap<String, InstanceStatus> overriddenInstanceStatusMap = CacheBuilder
        .newBuilder().initialCapacity(500)
        .expireAfterAccess(1, TimeUnit.HOURS)
        .<String, InstanceStatus>build().asMap();

1.1 eureka server status

状态 描述
starting 实例初始化状态,此状态主要给实例预留初始化时间
down 当健康检查失败时,实例的状态转变到down
up 正常服务状态
out_of_service 不参与接收服务 。但是服务正常
unknown 未知状态

1.2 与server status有关的方法

方法 描述 调用场景
register 注册实例 1.实例启动的时候开始注册;2.心跳404时开始注册实例
cancel 取消server注册的某一实例 客户端shutdown实例后,调用cancel
renew 续租请求 客户端定时心跳时调用该方法。deleteStatusOvrride方法调用后会触发renew续租失败,触发重新注册实例。
statusUpdate 状态更新方法 主要调用的时机时让此service下线,不在接收请求。或者让下线的服务重新上线。
deleteStatusOverride 移除实例的覆盖状态 实例的覆盖状态移除后,覆盖状态将变成unknown

2.假如InstanceInfo中只有status状态

  1. client端调用updateStatus更新实例状态到out_of_service 。即status = out_of_service。此时client的状态是up状态
  2. server端此实例的状态现在是out_of_service。并且标记responseCache无效。
  3. 客户端等待定时器定时更新实例的状态。但是由于时间间隔没有更新,所以client的状态还是up状态。
  4. client端发送续租renew,由于此时客户端的状态是up状态,server端的状态是out_of_service。因此此前客户端调用的实例下线状态有被改回到原来的状态up.

3.eureka引入overriddenstatus用来解决状态被覆盖问题


  1. 客户端调用updateStatus方法时,同时更新server端实例的status和overriddenStatus状态。
  2. 客户端调用renew方法时,也要更新server端实例的status和overriddenstatus状态,但是有一下规则的

(1):如果客户端上传的实例状态是down或者starting,表明客户端是重启或者healthCheck失败。此时这个实例不能作为服务提供服务。因此即使客户端调用updateStatus把实例状态更新为up,也是没用的。此时客户端实例的准确状态就是down或者starting。
(2):如果客户端的实例是up或者out_of_service,此时是不可信的。就像第二大节介绍的那样。有可能client端的实例状态已被改变,此时要使用overriddenstatus状态作为当前实例的状态,避免被覆盖。
(3):(2)中的overriddenstatus有可能不存在,缓存失效,此时要使用server端已经存在的实例的状态。

4. 覆盖状态规则的源码实现

源码实现中使用了:组合模式Composite

/**
* 首先检查 这个实例是starting 还是down的。然后在检查已知明确的override
   * 最后我们检查已经存在续租实例潜在的状态
   */
this.instanceStatusOverrideRule = new FirstMatchWinsCompositeRule(new DownOrStartingRule(),
       new OverrideExistsRule(overriddenInstanceStatusMap), new LeaseExistsRule());

4.1 组合模式实现FirstMatchWinsCompositeRule

/**
* This rule takes an ordered list of rules and returns the result of the first match or the
* result of the {@link AlwaysMatchInstanceStatusRule}.
*
* 这个规则包含一个有序的规则集合,如果有匹配的则返回第一个匹配的结果
* Created by Nikos Michalakis on 7/13/16.
*/
public class FirstMatchWinsCompositeRule implements InstanceStatusOverrideRule {

   /**实例匹配规则集合*/
   private final InstanceStatusOverrideRule[] rules;
   private final InstanceStatusOverrideRule defaultRule;
   private final String compositeRuleName;

   public FirstMatchWinsCompositeRule(InstanceStatusOverrideRule... rules) {
       this.rules = rules;
       this.defaultRule = new AlwaysMatchInstanceStatusRule();
       // Let's build up and "cache" the rule name to be used by toString();
       List<String> ruleNames = new ArrayList<>(rules.length+1);
       for (int i = 0; i < rules.length; ++i) {
           ruleNames.add(rules[i].toString());
       }
       ruleNames.add(defaultRule.toString());
       compositeRuleName = ruleNames.toString();
   }

   /**获取第一个匹配的状态*/
   @Override
   public StatusOverrideResult apply(InstanceInfo instanceInfo,
                                     Lease<InstanceInfo> existingLease,
                                     boolean isReplication) {
       for (int i = 0; i < this.rules.length; ++i) {
           StatusOverrideResult result = this.rules[i].apply(instanceInfo, existingLease, isReplication);
           if (result.matches()) {
               return result;
           }
       }
       return defaultRule.apply(instanceInfo, existingLease, isReplication);
   }

   @Override
   public String toString() {
       return this.compositeRuleName;
   }
}

4.2 单个规则源码介绍

本文只介绍DownOrStartingRule,其余的不做详细介绍

/**
* This rule matches if the instance is DOWN or STARTING.
*
* 这个规则匹配 实例是 DOWN的还是starting
* Created by Nikos Michalakis on 7/13/16.
*/
public class DownOrStartingRule implements InstanceStatusOverrideRule {
   private static final Logger logger = LoggerFactory.getLogger(DownOrStartingRule.class);

   @Override
   public StatusOverrideResult apply(InstanceInfo instanceInfo,
                                     Lease<InstanceInfo> existingLease,
                                     boolean isReplication) {
       // ReplicationInstance is DOWN or STARTING - believe that, but when the instance says UP, question that
       // The client instance sends STARTING or DOWN (because of heartbeat failures), then we accept what
       // the client says. The same is the case with replica as well.
       // The OUT_OF_SERVICE from the client or replica needs to be confirmed as well since the service may be
       // currently in SERVICE

       /**
        * 同步实例是down或者starting的时候是可信的。因为只有在心跳失败时,客户端才会发送down或者starting
        *
        * 但是当实例的状态是UP 或者OUT_OF_SERVICE时。需要再次确认。
        */
       if ((!InstanceInfo.InstanceStatus.UP.equals(instanceInfo.getStatus()))
               && (!InstanceInfo.InstanceStatus.OUT_OF_SERVICE.equals(instanceInfo.getStatus()))) {
           logger.debug("Trusting the instance status {} from replica or instance for instance {}",
                   instanceInfo.getStatus(), instanceInfo.getId());
           return StatusOverrideResult.matchingStatus(instanceInfo.getStatus());
       }
       return StatusOverrideResult.NO_MATCH;
   }

   @Override
   public String toString() {
       return DownOrStartingRule.class.getName();
   }
}

猜你喜欢

转载自blog.csdn.net/ai_xiangjuan/article/details/80344491