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

概述

本文记录一次升级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;@Beanpublic 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:8080bootstrap:enabled: truenamespaces: 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.mzph.cn/news/182962.shtml

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

相关文章

45、Flink 的指标体系介绍及验证(3)- 完整版

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

从源代码出发,Jenkins 任务排队时间过长问题的解决过程

最近开发了一个部署相关的工具&#xff0c;使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时&#xff0c;通过 Jenkins API 来触发构建任务。在线上运行时发现&#xff0c;通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的…

Node.js案例 - 记账本

目录 项目效果 项目的搭建 ​编辑 响应静态网页 ​编辑 ​编辑 结合MongoDB数据库 结合API接口 进行会话控制 项目效果 该案例实现账单的添加删除查看&#xff0c;用户的登录注册。功能比较简单&#xff0c;但是案例主要是使用前段时间学习的知识进行实现的&#xff0c…

C++ AVL 树

AVL树的概念 当数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;此时二叉搜索树的搜索效率低下 解决方法&#xff1a;AVL树&#xff08;降低树的高度&#xff0c;从而减少平均搜索长度) 一棵AVL树或者是空树&#xff0c;或者是具有以下性质的二叉搜索树&#xff1…

JavaScript基础—函数、参数、返回值、作用域、变量、匿名函数、综合案例—转换时间,逻辑中断,转换为Boolean型

版本说明 当前版本号[20231129]。 版本修改说明20231126初版20231129完善部分内容 目录 文章目录 版本说明目录JavaScript 基础 - 第4天笔记函数声明和调用声明&#xff08;定义&#xff09;调用细节补充 参数形参和实参函数默认值 返回值作用域全局作用域局部作用域 变量全…

laraval6.0 GatewayWorker 交互通信

laravel 6.0 GatewayWorker 通讯 开发前准备下载 GatewayWorker 及操作方式前端demo测试效果项目中安装GatewayClient 开发前准备 GatewayClient 官网&#xff1a;https://www.workerman.net/ 当前使用的是宝塔操作 下载 GatewayWorker 及操作方式 前端demo 测试效果 项目中安…

纹理烘焙:原理及实现

纹理烘焙是计算机图形学中常见的技术&#xff0c;用于将着色器的细节传输到纹理中。 如果你的着色器计算量很大&#xff0c;但会产生静态结果&#xff0c;例如&#xff0c;这非常有用。 复杂的噪音。 NSDT在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器…

Ajax的使用方法

1,什么是Ajax&#xff1f; Ajax&#xff08;异步Javascript和XML&#xff09;&#xff0c;是指一种创建交互式网页应用的网页开发技术。 2&#xff0c;Ajax的作用 Ajax可以使网页实现异步更新----即在不更新整个页面的情况下实现对某一部分进行更新。 简单来说Ajax就是用于连接…

【Python】yaml.safe_load()函数详解和示例

在Python中&#xff0c;PyYAML库提供了对YAML&#xff08;YAML Ain’t Markup Language&#xff09;文件的强大支持。YAML是一种直观的数据序列化标准&#xff0c;可以方便地存储和加载配置文件、数据日志等。 yaml.safe_load和yaml.load是Python的PyYAML库提供的两个函数&…

从零搭建AlibabaCloud微服务项目

1&#xff0c;创建maven项目工程如下 equipment-admin 后台equipment-applet 前台或小程序端或app、h5equipment-common 公共模块equipment-gateway 网关equipment-mapper mapper层操作数据库equipment-model 实体类对应数据库表 2&#xff0c;在父pom文件引入依赖 <proper…

基于Java SSM框架实现美食推荐管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现美食推荐管理系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…

国内首个农业开源鸿蒙操作系统联合华为正式发布

2023年11月29日&#xff0c;在中国国际供应链促进博览会上&#xff0c;中信农业科技股份有限公司&#xff08;简称“中信农业”&#xff09;与深圳开鸿数字产业发展有限公司&#xff08;简称“深开鸿”&#xff09;以及华为技术有限公司&#xff08;简称“华为”&#xff09;联…

UniWebView 版本3 版本4 版本5介绍

一、介绍 UniWebView是iOS/Android上的web视图组件的包装器&#xff0c;所以运行时拥有与原生web相似性能。是针对Unity所写的插件&#xff0c;节省了项目的开发时间。 官网地址&#xff1a;UniWebView 二、下载&使用 1、下载 &#xff08;1&#xff09;、Unity Asset …

GAN:PacGAN-生成对抗网络中两个样本的威力

论文&#xff1a;https://arxiv.org/pdf/1712.04086.pdf 代码&#xff1a;GitHub - fjxmlzn/PacGAN: [NeurIPS 2018] [JSAIT] PacGAN: The power of two samples in generative adversarial networks 发表&#xff1a;2016 一、摘要 1&#xff1a;GAN最重大的缺陷是&#xf…

自己动手写 chatgpt: Attention 机制的原理与实现

chatgpt等大模型之所以成功都有赖于一种算法突破&#xff0c;那就是 attention 机制。这种机制能让神经网络更有效的从语言中抽取识别其内含的规律&#xff0c;同时它支持多路并行运算&#xff0c;因此相比于原来的自然语言处理算法&#xff0c;它能够通过并发的方式将训练的速…

leetcode 11. 盛最多水的容器(优质解法)

代码&#xff1a; class Solution {public int maxArea(int[] height) {int nheight.length;int left0;int rightn-1;int max0;while (left<right){//计算当前 left 和 right 所在位置的面积int areaMath.min(height[left],height[right])*(right-left);//重置最大值if(are…

进程间通信基础知识【Linux】——上篇

目录 一&#xff0c;理解进程之间的通信 1. 进程间通信目的 2. 进程间通信的技术背景 3&#xff0c;常见的进程间通信 二&#xff0c;管道 1. 尝试建立一个管道 管道的特点&#xff1a; 管道提供的访问控制&#xff1a; 2. 扩展&#xff1a;进程池 阶段一&#xff1a…

sqli-labs靶场详解(less32-less37)

宽字节注入 原理在下方 目录 less-32 less-33 less-34 less-35 less-36 less-37 less-32 正常页面 ?id1 下面有提示 获取到了Hint: The Query String you input is escaped as : 1\ ?id1 看来是把参数中的非法字符就加上了转义 从而在数据库中只能把单引号当成普通的字…

asla四大开源组件应用示例(alsa-lib、alsa-utils、alsa-tools、alsa-plugins)

文章目录 alsa设备文件/dev/snd//sys/class/sound/proc/asoundalsa-lib示例1alsa-utilsalsa-toolsalsa-plugins参考alsa设备文件 /dev/snd/ alsa设备文件目录位于,/dev/snd,如下所示 root@xboard:~#ls /dev/snd -l total 0 drwxr-xr-x 2 root root 60 Nov 6 2023 …

springboot基础配置及maven运行

目录 1、spring快速开始&#xff1a; 2、通过idea工具打开导入包 3、maven打包 1、springboot快速开始&#xff1a; 环境依赖&#xff1a;jdk17 Spring | Quickstart spring初始化包下载&#xff1a; 点击generate&#xff0c;下载包 2、通过idea工具打开导入包 我之前写了…