写点什么

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

  • 2020-12-26
  • 本文字数:2869 字

    阅读完需:约 9 分钟

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

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


注册中心的职责


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



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

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

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


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


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);    }}
复制代码


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


  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; }
复制代码


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


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


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


  • 新启动的服务下的异常

  • 运行中的服务的异常

  • 运行中且重启过的服务


1. 新启动的服务的异常


  • 服务注册


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


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


  • 服务发现


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


2. 运行中的服务的异常


  • 服务注册


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


  • 服务发现


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


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


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


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


  • 服务注册


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


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


  • 服务发现


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


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


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


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


  1. 注册中心异常。

  2. 服务调用方调用注册中心异常,则降级使用 cache 中的数据。

  3. 注册中心恢复,此时大量的节点可能还未发起定时心跳的请求,因此所有的服务节点状态都变成了不健康的状态(Consul Health Check 配置 TTL check 的场景)。

  4. 服务调用方再次从注册中心拉取新的数据,但是所有节点都是不健康的节点。

  5. 服务调用失败。


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



头图:Unsplash

作者:张艺辰

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

来源:腾讯云中间件 - 微信公众号 [ID:gh_6ea1bc2dd5fd]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2020-12-26 19:202409

评论

发布
暂无评论
发现更多内容

区块链 RWA 系统的上线

北京木奇移动技术有限公司

网易云信 x Doris:降本70%、提速11倍, 统一 ES/InfluxDB/Hive 多技术栈的落地实践

SelectDB

数据库 App ES Doris 网易云信

Cursor 如何保障「代码索引」的安全、高效

Baihai IDP

程序员 AI 智能体 cursor AI 编程

科学智能:全球顶尖学者共聚复旦,共探科研范式变革新引擎

ModelWhale

科学智能 AI4S

香港校长团探访博大数据前海智算中心,科技赋能教育共育湾区数字人才

极客天地

Java程序员的职业加速器:飞算JavaAI一键生成完整工程代码,轻松应对开发挑战

猫头虎

Java 人工智能 AI编程 idea intellij

私有化部署 IM:即时通讯软件助力团队协作

BeeWorks

即时通讯 IM 私有化部署

国资委深化“AI+”专项行动 AI法务工具AlphaGPT赋能业务升级

科技汇

领跑 AI 基础设施存储赛道!焱融科技实力登榜「AI Cloud 100 China」

焱融科技

文件存储 大模型 AI基础设施 2025 AI Cloud 100 China

鸿蒙+星闪:一场“1+1>2”的音频蝶变

脑极体

AI

大模型成今年高考志愿神器,超千万用户使用百度AI志愿助手、高考大数据服务

科技大数据

观测云产品更新 | 外部数据源、日志、监控、事件、基础设施等

观测云

如何使用龙蜥衍生版KOS,2步实现大模型训练环境部署

OpenAnolis小助手

AI 操作系统 龙蜥大讲堂

拼多多店铺订单列表,订单详情,订单物流接口指南

tbapi

拼多多API 拼多多店铺接口 拼多多店铺订单接口 拼多多店铺订单详情接口

三方系统集成(低代码)平台实践

vivo互联网技术

Java 架构 后端 低代码

模块化电商解决方案

微擎应用市场

Zenlayer 推出 AI 模型全球调用解决方案,破局企业部署三大挑战

极客天地

WebGL 软件外包开发流程

北京木奇移动技术有限公司

区块链开发 软件外包公司 RWA开发

MyEMS开源能源管理系统v5.6.0发布通知

开源能源管理系统

开源 能源管理 开源能源管理

7月1日19点,ModelWhale 大模型应用平台全新升级!

ModelWhale

大模型 modelwhale

CST软件如何设置分布式计算(Distributed Computing)的 TCP-IP子网

思茂信息

cst操作 CST软件 CST Studio Suite

【FAQ】HarmonyOS SDK 闭源开放能力 —Account Kit (6)

HarmonyOS SDK

harmoyos

卓正医疗如何用 NocoBase 搭建“家庭医生式”服务体系?

NocoBase

开源 低代码 数字化转型 零代码 医疗行业

多端一体化教育解决方案

微擎应用市场

龙蜥衍生技术助力清华登顶TPC物联网数据性能榜首 | 干货推荐

OpenAnolis小助手

操作系统 龙蜥社区 龙蜥操作系统 tpc

MES与ERP深度融合:数据报表、可视化大屏及系统集成技术详解

万界星空科技

制造业 mes ERP系统 万界星空科技mes AI低代码MES

区块链 Web3 项目的上线

北京木奇移动技术有限公司

区块链开发 软件外包公司 web3开发

建筑矿山设备工厂与 MyEMS 能源管理系统深度应用白皮书

开源能源管理系统

开源 能源管理 节能减排 工厂安全生产

咕泡AI课程专家团全拆解 | 技术答疑助你全周期通关!

咕泡科技

人工智能 AI 咕泡人工智能 咕泡ai

20~30K * 15薪,可惜挂了

王中阳Go

Java 面试

多行业活动管理

微擎应用市场

踩坑总结:鹅厂小哥教你注册中心宕机后正确的处理姿势_语言 & 开发_腾讯云中间件_InfoQ精选文章