一次Apollo Client升级导致的生产404 Not Found问题排查记录

news2024/11/20 8:31:36

概述

本文记录一次升级Apollo Client组件到1.7.0后遇到的重大生产事故。只想看结论的,可直接快进到文末。实际上,第一句话就是一个结论。

另,本文行文思路事后看起来可行略显思路清晰,实际上排查生产问题时如无头苍蝇,各种猜想各种否定猜想,各种排除各种验证。

另另,回滚服务有时候是一个法宝。

此时已经0点54分,明天醒来再好好整理一下。

事故

某次生产上线一次性发布6个微服务。应用发布后,并没有第一时间收到Prometheus (ERROR类型日志)告警,以为一切正常。

随后在打开某个小程序时,发现小程序打不开。第一时间把问题抛到技术群,随后去生产查看ELK ERROR(再次提到)日志,看到如下日志:

- status 500 reading RemoteOAuthService#smsCodeLogin(SmsCodeLoginDto)
feign.FeignException: status 500 reading RemoteOAuthService#smsCodeLogin(SmsCodeLoginDto)
at feign.FeignException.errorStatus(FeignException.java:78)
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.aba.enduser.service.impl.UserLoginServiceImpl.smsCodeLogin(UserLoginServiceImpl.java:181)
at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
at com.aba.enduser.controller.LoginController.smsCodeLogin(LoginController.java)

事实上后来的排查证明与上面的报错无关。

与此同时,技术群前端同学排查到如下截图 404 NOT_FOUND异常:
在这里插入图片描述
看接口,以及上面报错日志,第一时间怀疑是OAuth服务(在此次发布清单6个服务中)有问题,于是回滚此服务。

但是,在回滚此服务后,小程序依旧有问题,404 NOT_FOUND异常依旧存在。

继续排查剩余5个发布应用清单,将其余4个服务排除后,回滚gateway-open服务。小程序打开正常。

反思

通过GitLab提供的Repository-Compare功能,即代码对比,本次发布版本Tag和发布前线上运行的版本Tag,并没有什么显著性问题(因为此次发布有2个问题,事后结论)看这个版本对比,也看不出啥问题。

在这里插入图片描述

排查

在这里插入图片描述

在这里插入图片描述

为何某些服务需要额外引入apollo-openapi?
因为如下代码:

@SpringBootApplication
@EnableApolloConfig(value = {"commons"})
public class OpenGatewayApplication {
    @Value("${apollo.portalUrl:http://172.111.222.33:8070}")
    private String portalUrl;
    @Value("${apollo.portal.token:717376485f69df0d}")
    private String token;

    @Bean
    public ApolloOpenApiClient apolloOpenApiClient() {
        return ApolloOpenApiClient.newBuilder()
                .withPortalUrl(portalUrl)
                .withToken(token)
                .build();
    }
}

在这里插入图片描述
为什么apollo-core版本有区别,得看pom文件里先引入apollo-client还是先引入apollo-openapi

c.ctrip.framework.apollo.internals.AbstractConfigRepository | trySync | 29 | - Sync config failed, will retry. Repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository, reason: 'java.lang.String com.ctrip.framework.foundation.spi.provider.ApplicationProvider.getAccessKeySecret()'
Schedule long polling refresh failed [Cause: com.ctrip.framework.foundation.spi.provider.ApplicationProvider.getAccessKeySecret()Ljava/lang/String;]
Sync config from upstream repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository failed, reason: com.ctrip.framework.foundation.spi.provider.ApplicationProvider.getAccessKeySecret()Ljava/lang/String;
Init Apollo Local Config failed - namespace: commons, reason: Load config from local config failed! [Cause: Cannot read from local cache file /opt/data/App/config-cache/App+default+commons.properties].
Could not load config for namespace commons from Apollo, please check whether the configs are released in Apollo! Return default value now!

借助于开源组件KubernetesFileBrowser,我们可以拿到kubernetes环境下pod里的文件。

有问题的版本Tag:
在这里插入图片描述
没有问题的版本Tag:
在这里插入图片描述

@EnableApolloConfig

这个看一下EnableApolloConfig.java源码就明白:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({ApolloConfigRegistrar.class})
public @interface EnableApolloConfig {
    String[] value() default {"application"};
    int order() default Integer.MAX_VALUE;
}

也就意味着,除了在本地配置文件里指定需要引用的namespace,我还可以在@注解里指定namespace,像这样:

@EnableApolloConfig(value = {"commons", "gateway-open"})

配置文件:

#apollo
app:
  id: App
apollo:
  meta: http://apollo.aaabbbccc.com:8080
  bootstrap:
    enabled: true
    namespaces: commons,gateway-open

升级Apollo Client背景

后端微服务架构体系里将近30个微服务,所有的请求流量转发都是由gateway服务来承载。另外,考虑到我们的产品有不同的用户体系,比如C端用户,三方对接平台或商户等。基于这两点,我们有2个gateway网关服务,一个是gateway-c服务,用于服务C端用户的绝大多数请求。另一个是gateway-open服务,用于服务三方等渠道或商户的请求。

另外,作为一个背景知识,gateway网关服务里面的配置几乎都是路由转发规则配置,类似于:

spring.cloud.gateway.routes[22].id = enduser-provider
spring.cloud.gateway.routes[22].uri = lb://enduser-provider
spring.cloud.gateway.routes[22].predicates[0] = Path=/api/open/user/**
spring.cloud.gateway.routes[22].filters[0] = StripPrefix=1
spring.cloud.gateway.routes[22].filters[1] = RequestLogFilter
spring.cloud.gateway.routes[22].filters[2] = BlockListFilter
spring.cloud.gateway.routes[22].filters[3] = TokenFilter
spring.cloud.gateway.routes[22].filters[4] = SignVerifyFilter
spring.cloud.gateway.routes[22].filters[5] = HeaderCheckNullFilter

当业务场景变得越来越复杂,微服务数量越来越多,或随着一个个接口的上线或下线,或者某个符合predicates断言规则接口前端(含H5、小程序、iOS、Android等,即所谓大前端概念),适配增加各种不同场景的Filter,等等原因,导致gateway网关服务的路由转发规则变得臃肿复杂难以理解。

此为背景。

某次在优化gateway-c服务的配置后,从Sublime Text复制配置到Apollo,准备发布更改时,才发现不对劲,这次调整怎么有这么多啊。立马发现,好家伙,手残点错namespace。把本来应该变更到gateway-c的配置复制到gateway-open。

ok。我要回滚,我当然不可能点发布。但是,当我点击回滚时,弹窗提示的版本号明显不对,一个是目前生产的版本,一个是上一次的版本,类似于下图(非事发时截图):
在这里插入图片描述
仔细分析,我想要的其实并不是【回滚】功能,因为我的配置变更还未提交(发布)。再想了想,模模糊糊有了点头绪(虽然此处行文可能看起来显得思路清晰得一逼),此处Apollo版本发布概念实际上就是Git的版本控制概念。

配置有变更,等价于Git里的modified;
配置发布,相当于Git里的commit;
配置回滚,可类比于Git里的revert;
配置撤销,可类比于Git里的restore。
在这里插入图片描述
带着Apollo、回滚、撤销等关键词找到官方GitHub issue,看到:
在这里插入图片描述
点击Apollo-PR-2952,发现对应着Milestone 1.7.0。

因为之前了解过我们使用的生产环境Apollo UI(配置可视化管理端)版本号为:1.4.0,测试环境Apollo UI版本号为:1.7.0。

版本号正好匹配,于是打开测试环境Apollo UI,发现确实有这个【撤销配置】的入口:
在这里插入图片描述
作为对比,放一张生产环境的截图:
在这里插入图片描述
另外我们在pom文件里使用的apollo-client版本号为1.5.0,这个当然不区分测试和生产环境。

也就是说,apollo-client-1.5.0版本与apollo server(UI)1.7.0版本可以兼容,即测试环境就是这种情况,没有(发现)问题。

于是:升级生产Apollo Server版本到1.7.0!

PS:Apollo Server端成功升级后,我们应用侧,apollo-client还是1.5.0,两者完美兼容运行一段时间后。

结论

应用pom.xml文件先引入apollo-openapi-1.5.0,后引入apollo-client-1.7.0。先删除本地缓存下来的Apollo配置properties文件,应用启动时会有很多WARN日志,即上面提到的5类WARN日志,不影响应用启动成功。

<dependency>
	<groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-openapi</artifactId>
    <version>1.5.0</version>
</dependency>
<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>1.7.0</version>
</dependency>

事实上,请求http://localhost:8848/health/check
在这里插入图片描述
正好对应着健康健康endpoint端点:

@GetMapping({"/health/check"})
public String heathCheck() {
    return "OK";
}

但是,后面还是会持续打印WARN日志。

并且!
本地并没有缓存此应用需要的几个Apollo配置文件!!
后面如果要通过此服务做请求转发,拿不到配置路由规则,更谈何URL路径规则转发呢!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1269557.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初学者如何入门深度学习:以手写数字字符识别为例看AI 的学习路径,一图胜千言!

文章大纲 深度神经网络机器学习,深度学习,数据发掘之间的关系理解深度神经网络最好的可视化工具深度学习基础概念能解决神马种类的问题?卷积池化以手写字符识别为例讲述深度学习的分类问题MNIST 数据集简介初学者入门 :生成式 AI -- generative-ai-for-beginners参考文献与…

【Web端CAD/CAE文字标注】webgl+canvas 2d实现文字标注功能

一、需求背景 在CAD/CAE领域经常会遇到显示节点编号这种需求&#xff0c;效果如下图&#xff1a; 本文介绍如何在WebGL中实现文字的显示&#xff0c;对于如何在OpenGL中实现请绕路。 二、实现原理 Canvas是HTML5提供的元素&#xff0c;用于在网页上绘制图形&#xff0c;其支…

计算机网络(超详解!) 第二节 物理层(上)

1.物理层的基本概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层的作用是要尽可能地屏蔽掉不同传输媒体和通信手段的差异。 用于物理层的协议也常称为物理层规程(procedure)。 2.物理层的主要任务 主要…

Unity版本使用情况统计(更新至2023年10月)

本期UWA发布的内容是第十三期Unity版本使用统计&#xff0c;统计周期为2023年5月至2023年10月&#xff0c;数据来源于UWA网站&#xff08;www.uwa4d.com&#xff09;性能诊断提测的项目。希望给Unity开发者提供相关的行业趋势&#xff0c;了解近半年来哪些Unity版本的使用概率更…

Steps步骤条(antd-design组件库)简单用法

1.Steps步骤条 引导用户按照流程完成任务的导航条。 2.何时使用 当任务复杂或者存在先后关系时&#xff0c;将其分解成一系列步骤&#xff0c;从而简化任务。 组件代码来自&#xff1a; 步骤条 Steps - Ant Design 3.本地验证前的准备 参考文章【react项目antd组件-demo:hello-…

11.兔子生崽问题【2023.11.26】

1.问题描述 有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问 第二十个月的兔子对数为多少对&#xff1f; 2.解决思路 3.代码实现 #include<stdio.h> int mai…

单相直流电表和单相智能电表有哪些区别?

在众多的智能电表中&#xff0c;单相智能电表已成为家庭用电、工业用电等领域的重要组成部分。与此同时&#xff0c;单相直流电表也因其特性在某些特定场合受到关注。下面就来讲讲两者都有哪些区别&#xff0c;一起来看下吧&#xff01; 一、工作原理及性能差异 1.单相直流电表…

微信小程序本地和真机调试文件上传成功但体验版不成功

可能是微信小程序ip白名单的问题&#xff0c;去微信公众平台&#xff08;小程序&#xff09;上设置小程序的ip白名单 1、在本地中取消不校验 然后在本地去上传文件&#xff0c;就会发现控制台报错了&#xff0c;会提示一个https什么不在ip白名单&#xff0c;复制那个网址 2、…

5 面试题--redis

伪客户端&#xff1a; 伪客户端的 fd 属性值为 -1&#xff1b;伪客户端处理的命令请求来源于 AOF ⽂件或者 Lua 脚本&#xff0c;⽽不是⽹络&#xff0c;所以这种客户端不需要套接字连接&#xff0c;⾃然也不需要记录套接字描述符。⽬前 Redis 服务器会在两个地⽅ ⽤到伪客户端…

西工大网络空间安全学院计算机系统基础实验一(9, 10, 11, 12, 13)

还是那句话&#xff0c;专心做好你自己的&#xff0c;老老实实把基础打好&#xff0c;不要被其他人带跑节奏&#xff0c;不要跟他打&#xff0c;跟着这系列博客&#xff0c;稳扎稳打一步一步来。即使你VMware workstation没下载好&#xff0c;即使你Ubuntu虚拟机没配好&#xf…

nacos配置变更导致logback日志异常

问题背景: 线上的服务突然内存爆满&#xff0c;查服务器突然发现&#xff0c;日志全部打印到了/tmp/tomcat.xxx.port目录下&#xff0c;后来对应操作时间&#xff0c;和nacos修改配置是同一时间发生的&#xff0c;但是疑惑的点是&#xff0c;nacos配置变更为什么会引起logback的…

MySQL与其他数据库产品的比较,优势在哪里?

作为数据库管理领域的博主作家&#xff0c;我深知数据库在软件开发和数据管理中的重要性。在当今众多的数据库产品中&#xff0c;MySQL作为一种流行的开源关系型数据库管理系统&#xff0c;具有许多优势和特点。下面&#xff0c;我将通过对与其他数据库产品的比较以及MySQL的优…

【华为数通HCIP | 网络工程师】821刷题日记-IS-IS(2)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

mac截图Snagit 中文介绍

1.超越普通的屏幕截图 TechSmith Snagit 是唯一具有内置高级图像编辑和屏幕录制功能的屏幕捕获软件。因此&#xff0c;您可以在一个程序中轻松创建高质量的图像和视频。 2.最后&#xff0c;屏幕捕获软件可以完成您所做的一切 快速解释一个过程如果您正在努力清楚地沟通&…

电子学会C/C++编程等级考试2022年12月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:鸡兔同笼 一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。 时间限制:1000 内存限制:65536输入 一行,一个正整数a (a < 327…

HarmonyOS——UI开展前的阶段总结

当足够的了解了HarmonyOS的相关特性之后&#xff0c;再去介入UI&#xff0c;你会发现无比的轻松&#xff0c;特别当你有着其他的声明式UI开发的经验时&#xff0c;对于HarmonyOS的UI&#xff0c;大致一扫&#xff0c;也就会了。 如何把UI阐述的简单易懂&#xff0c;又能方便大…

全局异常处理类

全局异常处理类 创建步骤 定义一个自己的全局错误处理类GlobalExceptionHandler创建一个ExceptionHandler类&#xff0c;主要是用ControllerAdvice和 ExceptionHandler处理错误信息 以下说明各个注解的作用&#xff1a; ControllerAdvice(annotations {RestController.class…

【C++】单链表——单链表的基本操作

1、单链表的定义 由于顺序表的插入删除操作需要移动大量的元素&#xff0c;影响了运行效率&#xff0c;因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素&#xff0c;不需要使用地址连续的存储单元&#xff0c;因此它不要求在逻辑…

Mysq8l在Centos上安装后忘记root密码如何重新设置

场景 Mysql8在Windows上离线安装时忘记root密码&#xff1a; Mysql8在Windows上离线安装时忘记root密码-CSDN博客 如果是在Windows上忘记密码可以参考上面。 如果在Centos中安装mysql可以参考下面。 CentOS7中安装Mysql8并配置远程连接和修改密码等&#xff1a; CentOS7中…

【知识】稀疏矩阵是否比密集矩阵更高效?

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 问题提出 有些地方说&#xff0c;稀疏图比密集图的计算效率更高&#xff0c;真的吗&#xff1f; 原因猜想 这里的效率高&#xff0c;应该是有前提的&#xff1a;当使用稀疏矩阵的存储格式(如CSR)时&#xff0c;计…