采坑总结:鹅厂小哥教你注册中心宕机后正确的处理姿势


导语:微服务化是当前的一大趋势,注册中心既是微服务最基础的组件,也是最核心的组件,它为客户端提供所有可调用的服务列表。也正因如此,注册中心的可用性在微服务架构中要求极高。在实际开发中,虽然我们可以通过一些手段不断的在提高注册中心的可用性,但也无法保证注册中心SLA (Service Level Agreement,服务级别协议)100%的可用性。既然这样,那么当注册中心宕机不可用时,我们应该如何做才能减轻影响呢?



01
注册中心的职责




在分析注册中心宕机带来的影响前,我们先来看下注册中心的职责,下面一张图就可以解释注册中心的主要职责。




  • 注册中心:用于服务端注册远程服务以及客户端发现服务。

  • 服务端:对外提供后台服务,将自己的服务信息注册到注册中心。

  • 客户端:从注册中心获取远程服务的注册信息,然后进行远程过程调用。

 

可以很清晰的看到,在注册中心宕机时,服务注册以及服务发现和服务节点推送都会受到影响,在没有任何缓存的情况下,服务之间的调用都会受到影响。



02
Spring Cloud的服务注册与发现




为了更好的阐述注册中心不可用带来的问题,我们先看看 Spring Cloud 的服务注册发现是怎么做的。这里我们以 Spring Cloud Consul 的代码为例。


服务注册


public void register(ConsulRegistration reg) {
    log.info("Registering service with consul: " + reg.getService());
    try {
      client.agentServiceRegister(reg.getService(), properties.getAclToken());
      if (heartbeatProperties.isEnabled() && ttlScheduler != null) {
        ttlScheduler.add(reg.getInstanceId());
      }
    }
    catch (ConsulException e) {
      if (this.properties.isFailFast()) {
        log.error("Error registering service with consul: " + reg.getService(), e);
        ReflectionUtils.rethrowRuntimeException(e);
      }
      log.warn("Failfast is false. Error registering service with consul: " + reg.getService(), e);
    }
}

org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistry#register


 服务注册的源码在注册的过程中做了三件事情:

 

  1. 使用 Consul Client SDK 发起服务注册的操作。
  2. 使用定时任务定时发起心跳。
  3. 服务注册发生异常时,会根据配置 FailFast 的取值抛出异常。


服务发现


private List<ConsulServer> getServers() {
    if (this.client == null) {
      return Collections.emptyList();
    }
    String tag = getTag(); // null is ok
    Response<List<HealthService>> response = this.client.getHealthServices(
        this.serviceId, tag, this.properties.isQueryPassing(),
        createQueryParamsForClientRequest(), this.properties.getAclToken());
    if (response.getValue() == null || response.getValue().isEmpty()) {
      return Collections.emptyList();
    }
    return transformResponse(response.getValue());
  }

/**
 * Transforms the response from Consul in to a list of usable {@link ConsulServer}s.
 *
 * @param healthServices the initial list of servers from Consul. Guaranteed to be non-empty list
 * @return ConsulServer instances
 * @see ConsulServer#ConsulServer(HealthService)
 */

protected List<ConsulServer> transformResponse(List<HealthService> healthServices) {
    List<ConsulServer> servers = new ArrayList<>();
    for (HealthService service : healthServices) {
      ConsulServer server = new ConsulServer(service);
      if (server.getMetadata().containsKey(this.properties.getDefaultZoneMetadataName())) {
        server.setZone(server.getMetadata().get(this.properties.getDefaultZoneMetadataName()));
      }
      servers.add(server);
    }
    return servers;
  }


org.springframework.cloud.consul.discovery.ConsulServerList#getServers


服务发现的部分则更加简单,使用 Consul Client 获取服务名节点。我们已经清楚服务注册和发现的处理流程,再来看看宕机场景下的服务注册和发现。

 


03
注册中心宕机下的服务注册和发现



 

这里我们分3种场景来阐述注册中心宕机下服务的异常情况:

 

  • 新启动的服务下的异常
  • 运行中的服务的异常
  • 运行中且重启过的服务

 

1. 新启动的服务的异常

 

  • 服务注册

 

在注册中心宕机的情况下,用户可能有服务扩容或者需要启动新服务的诉求,服务在启动的时候会在Consul Client 发起服务注册调用时异常,在 FailFast 开启的情况下(默认开启),服务会抛出异常,同时服务会启动失败,而当 FailFast 没有被打开的情况下,服务仅输出一段 warn 日志,不影响服务的启动。

 

那么在注册中心宕机的情况下,针对服务扩容或者新启动的服务,可以通过关闭 FailFast 让应用启动,后续通过心跳进行自动注册,来减轻对服务的影响。

 

  • 服务发现

 

由于注册中心连接不上,且新启动的服务没有任何调用方的服务节点的数据源可以读取数据,因此服务发现不可用。

 

2. 运行中的服务的异常

 

  • 服务注册

 

对于运行中的服务,服务已经注册成功,但宕机期间所有的心跳请求都会失败。

 

  • 服务发现

 

注册中心宕机期间,服务发现的请求会失败。

 

这里我们可以通过建立cache的方式来做降级处理,建立内存cache+文件cache的方式。在发现注册中心不可用时使用内存cache中的数据,内存cache无数据则访问文件cache。通过缓存的降级逻辑,当前运行中的服务节点间的调用不受影响,但对于新启动的节点以及宕机或者下线的节点存在无法感知的情况。

 

3. 运行中且重启过的服务

 

运行中且重启过的服务,这里指的是注册中心宕机期间,正常的服务被重启。

 

  • 服务注册

 

宕机期间所有的HeartBeat 请求以及服务注册的请求都会失败。

 

服务重启时可以通过关闭fail fast进行服务的启动。这样这个节点能正常处理上游的流量。

 

  • 服务发现

 

注册中心宕机期间,服务发现的请求会失败。

 

通过内存cache+文件cache的方式来进行降级处理。服务发现过程中,发现注册中心不可用,则尝试使用内存cache的数据,但内存cache中的数据为空,则尝试使用本地文件数据进行恢复。

 


04
注册中心恢复中服务发现的异常



 

通过上述的一些降级方法,能够有效的降低注册中心异常对业务的影响。那么这样就够了吗?我们再来看一个注册中心恢复时的异常case:

 

  1. 注册中心异常。
  2. 服务调用方调用注册中心异常,则降级使用cache中的数据。
  3. 注册中心恢复,此时大量的节点可能还未发起定时心跳的请求,因此所有的服务节点状态都变成了不健康的状态(Consul Health Check 配置 TTL check 的场景)。
  4. 服务调用方再次从注册中心拉取新的数据,但是所有节点都是不健康的节点。
  5. 服务调用失败。

 

针对这种场景,应该如何做呢?我们可以通过设置一个冷静期,在 Consul Client 发起拉取服务节点成功时,从以前使用 Cache 的降级数据到使用真实的服务节点数据前,等待两个心跳周期,等待期间都使用Cache 数据,等被调方能正常完成心跳,更新其节点的健康状态后在使用真实的数据。





关于微服务拆分,听听一位微服务架构师的肺腑之言


《聊一聊微服务架构中的服务发现系统》


探寻繁杂定时任务的解决方案:分布式任务调度系统


腾讯云中间件团队在Service Mesh中的实践与探索


《Kafka集群突破百万partition 的技术探索》


《服务治理最佳实践:如何快速依据请求参数值进行服务路由、鉴权、限流?》


扫描下方二维码关注本公众号

了解更多微服务、消息队列的相关信息


戳原文,了解微服务平台TSF的更多信息

点亮在看,你最好看

本文分享自微信公众号 - 腾讯云中间件(gh_6ea1bc2dd5fd)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/u/4587289/blog/4521348

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。