首页 > 其他分享 >一次Apollo Client升级导致的生产404 Not Found问题排查记录

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

时间:2024-08-21 17:28:07浏览次数:11  
标签:Apollo 服务 java 404 Client Found apollo com gateway

概述

本文记录一次升级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()'

在另一个服务里也看到这个WARN日志,此服务是10月23日发布,11月17日爆出此日志。

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路径规则转发呢!!

标签:Apollo,服务,java,404,Client,Found,apollo,com,gateway
From: https://www.cnblogs.com/johnny-wong/p/18372160

相关文章

  • Cloud Foundry 使用
    cfcli命令总结下经常使用到的一些命令CloudFoundrycli使用version7登录cf7login-a api.sys.***.com-uusername-ppassword部署应用,-f指定应用配置文件路径,-p指定应用jar包路径cf7push-f"myapp.yml"-p  "myapp.jar" scale修改应用内存-m,磁盘-......
  • Android开发 - BluetoothClient 类处理蓝牙全过程连接与数据解析
    BluetoothClient是什么BluetoothClient类通常用于蓝牙应用中,特别是与蓝牙设备进行通信的客户端管理。通常用于在Android应用中进行蓝牙通信。它帮助你处理与蓝牙连接、设备发现、数据传输等等任务BluetoothClient的使用环境连接到蓝牙设备:通过BluetoothClient,你可以......
  • 【VMware VCF】VMware Cloud Foundation Part 07:管理工作负载域中的主机和集群。
    一个标准VMwareCloudFoundation实例中具有管理工作负载域和VI工作负载域两种类型,管理域有且只有一个,而VI域可以创建多个,每种工作负载域中可以具有多个vSphere集群,而每个集群中可以具有多台主机,有关工作负载域所支持的集群和主机数等限制请查看VMwareConfigurationMax......
  • HttpClient、IHttpClientFactory、HttpClientHandler 和 HttpMessageHandler 的生命周
    在C#中,HttpClient、IHttpClientFactory、HttpClientHandler和HttpMessageHandler的生命周期密切相关,它们共同影响着网络请求的性能、资源管理和可靠性。以下是它们的生命周期分析:1.HttpClient的生命周期默认行为:HttpClient是线程安全的,设计为可以在应用程序的整个生命......
  • 在高并发和高负载场景下,优化 HttpClient
    在高并发和高负载场景下,优化HttpClient的使用至关重要,因为不当的资源管理可能导致性能瓶颈、资源枯竭(如端口耗尽)、和请求延迟等问题。以下是一些优化建议:1.使用IHttpClientFactory管理HttpClient实例复用HttpMessageHandler:通过IHttpClientFactory创建HttpClient实......
  • 在 C# 中处理 HttpClient 实例时,使用单例模式和 IHttpClientFactory,DNS缓存问题
    在C#中处理HttpClient实例时,使用单例模式和IHttpClientFactory都有各自的优缺点,尤其是在高并发情况下。以下是它们的对比及性能考虑:1.单例模式使用HttpClient优势:减少资源消耗:HttpClient是设计为复用的类,创建一个单例可以避免频繁创建和销毁HttpClient实例,从而减......
  • IHttpClientFactory 解决端口耗尽问题及衍生底层原理
    1.IHttpClientFactory解决端口耗尽问题问题描述:如果不使用IHttpClientFactory,而是为每个请求创建新的HttpClient实例,可能会导致端口耗尽问题。原因:每次创建新的HttpClient实例都会导致新的HttpClientHandler和底层Socket连接的创建,且这些连接在短时间内无法被回......
  • @clickhouse/client-web部署后出现ClickHose query error:crypto.randomUUID is not a
    crypto.randomUUID报错我这里是因为使用使用@clickhouse/client-web组件,在服务器部署后在浏览器访问界面导致的crypto.randomUUIDisnotafunction报错如果你用http://localhost:端口,在服务器浏览器上访问这个部署的页面,发现不会报错,这是因为,你使用localhost访问......
  • 元素偏移(offset,scroll,client)介绍,动态设置类名
    文章目录一offset,scroll,client简单介绍二、scroll系列1scrollWidth2scrollHeight3scrollTop4scrollLeft三、offset系列1.offsetHeight2.offsetWidth3.offsetTop4.offsetLeft四client系列1clientTop2clientLeft3clientWidth4clientHeight五案例1动态设置......
  • LookupError: Resource averaged_perceptron_tagger not found.解决方案
      大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学......