问题记录
Truman
Posted on October 17, 2024
Question 1
web 版本 1.0.1 不可以,1.0.2 就可以访问
Question 2
1/18 日用户模块用户添加和登陆出现问题,手机号没有查询到,导致重复添加的失败:「数据库主从同步出现问题」
Question 3
Nacos 2.2.3 服务注册不上的问题,最后通过查看 nacos 的源码,发现配置中的 namespace 已经不是旧版本的命名空间了,需要是命名空间的 ID。在 nacos 的控制台显示中,把 namespace 归为 Namespace ID, namespace showname 归为 namespaces。所以配置文件中的 namespace 要和 nacos 命名中对应的 Namespace ID 一致
Question 4
发现一个问题, 当方法添加 @Cacheable 和@TimeToLive。缓存注解的时候, 如果方法抛出 businessexception,之前的切面无法捕获并正常返回异常信息。
异常触发点:WarmReplayCacheInterceptorPostProcessor.class -> in.getMethod().invoke(advice, in.getArguments());
异常被捕获,此时的异常为 InvocationTargetException,包裹着 BusinessException。
异常中间流转的过程还没看,最后一次流转在 CglibAopProxy.class ->throw new UndeclaredThrowableException(ex);
到达项目中的异常统一处理方法 handleException,进入方法的异常为 UndeclaredThrowableException,在目前的方法处理中,是没有对 UndeclaredThrowableException 进行处理的,对此异常进行处理就行。
UndeclaredThrowableExceptione.getCause()这是 InvocationTargetException
UndeclaredThrowableExceptione.getCause().getCause()取出 BusinessException
然后按照 BusinessException 正常处理就行了
目前的问题是:1 没有加 else,返回 500;2:Throwable cause = e.getCause().getCause();
这个 cause 的值会随机出现两种样态
1:class com.qis.base.exception.BusinessException
2:class com.qis.base.exception.BusinessException message: 报错信息
在最新的测试中,不使用 instanceof 判断异常的类型,使用 cause.getClass().equals(BusinessException.class)进行判断,判断为 BusinessException 更加准确
Question 5
live_room_online_user 表,非查询操作非常频繁。执行清除直播间过期用户数据时,容易出现死锁问题。具体的操作是删除最后更新时间在 3 分钟前的数据。
解决办法 1: 使用 FOR UPDATE 语句,这将为要删除的行获取排它锁,防止其他事务在删除过程中修改它们。
解决办法 2: 分段删除,先查出主键数据,例如 ID 的值,再根据 ID 进行删除操作。如果删除的数据量太大,可以分段进行,从而降低死锁的可能性。
解决办法 3: 使用乐观锁的变体;如果有类似 version 的字段,可以用 version 确定更精确的范围,这里可以使用最后更新时间实现乐观锁的变体,删除条件除了最后更新时间大于当前时间三分钟,且最后更新时间等于期望时间。如果最后更新时间在删除过程中被其他事务修改,删除语句将会失败,我们可以在应用程序逻辑中处理此失败并重试操作。
只是偶尔删除数据的情况下,使用 FOR UPDATE 子句就可以了。
需要频繁删除的情况下,分段删除或者使用乐观锁的变体可以提高性能。不过使用乐观锁要确保应用程序逻辑能够正确冲突。
在已有条件下,选择解决办法 2 是最好的选择,先查询要删除数据的 ID 集合,再根据 ID 进行分段删除。
额外优化:原有的定时任务有很多个,并且同时执行,人为导致并发问题;把多个定时任务的时间区隔开,同时执行的任务量尽量减少,并发导致的死锁后续不再发生。
Question 6
Kubernetes 网关出现问题,经运维修复后,部分前端服务调用后端服务还是会出现 499 httpcode,导致前端服务无法正常提供。后端排查后所有服务无异常,可以使用 postman 调用,在 pod 的控制台中调用其他服务的测试接口,正常返回,可以确认后端服务无异常。解决办法是把前端有问题的服务重启,这样服务就恢复了。推测原因可能是网关问题修复后,Kubernetes 中的服务需要重启,在网关中重新注册,才能恢复正常。
Question 7
Kubernetes prometheus 容器挂掉,无法提供服务。原因是什么?集群进行压力测试,导致资源被占用,prometheus 容器无法获取到足够的资源,服务失败,只能运维人员手动重启
Question 8
查询当天足篮类型一级联赛的所有比赛,查询超时。原因是在 WHERE 语句中使用了 TO_DAYS 函数,导致索引失效,全表扫描。比赛时间本身是有索引的,所以将函数去除,改为传值比较,恢复索引。
并不是所有情况下在 WHERE 子句中使用函数都会导致索引失效。是否失效取决于函数的类型、函数的作用对象以及数据库引擎的优化能力。
- 会导致索引失效的情况 对列进行转换或计算的函数:如果在 WHERE 子句中对索引列使用了改变其原始值的函数,那么通常会导致索引失效。例如: TO_DAYS(column):将日期时间转换为天数。 UPPER(column):将字符串转换为大写。 ABS(column):求绝对值。 这些函数都改变了列的原始值,数据库无法直接利用原始值上的索引,因此会导致索引失效,可能导致全表扫描。
- 不会导致索引失效的情况 不改变列值的函数:有些函数不会改变列的实际值或可以被数据库优化器识别,从而不会导致索引失效。例如: 范围查询:使用范围运算符(>、<、BETWEEN)通常不会导致索引失效 函数作用在常量或表达式上 如果函数只作用在常量或表达式上,而不是列上,索引仍然可以有效 数据库优化器的特殊优化 在一些数据库引擎中,某些函数或操作符经过优化后,仍然可以使用索引。例如在 MySQL 中,LIKE 'abc%' 可以利用索引,而 LIKE '%abc' 则不行。
- 数据库支持的函数索引 支持基于函数结果的索引(称为函数索引或表达式索引)
Question 9
安卓安装包文件体积 100 多 MB,文件使用分片上传的方式传到华为云的 OBS 服务器。在分片上传的请求中,有些请求会出现 504 Gateway Time-out 。
在不使用 VPN 的情况下,请求链路从本地网络到达香港的华为云,从华为云到达项目的 kubernetes 环境,从 Kubernetes 集群进入,到达前端的管理后台服务,前端的管理后台服务在集群内调用后端的 backend 服务,backend 服务再调用 support 服务,在 support 服务中将文件上传到华为的 OBS 服务器。
第一次解决:推测是 backend 和 support 远程调用服务请求用时太长,导致请求中断连接。在项目通用配置中,设置 backend 和 support 远程调用服务的 FeignHttpClientProperties,将请求超时时间设置为 8 秒。需要设置 @primary ,不然会报错 KubernetesFeignClientConfiguration required a single bean, but 2 were found,一个是默认的(org.springframework.cloud.openfeign.support.FeignHttpClientProperties),一个是自己定义的。
@Bean
@Primary
@ConditionalOnExpression("'${spring.application.name:undefined}'=='backend' or '${spring.application.name:undefined}'=='support-rpc'")
@ConfigurationProperties(prefix = "feign.httpclient")
public FeignHttpClientProperties feignHttpClientProperties() {
FeignHttpClientProperties properties = new FeignHttpClientProperties();
properties.setConnectionTimeout(8000); // Set connection timeout to 8000 ms
return properties;
}
第二次解决:在将配置发布到生产环境后,依旧会发生问题,说明问题没有真的解决,于是开启日志的逐行分析。在出现 504 请求后,推测分片上传的文件的 ID,根据文件 ID 查询后端的日志,将请求达到时间与上传成功时间记录,正常的请求和异常的请求分别记录三条。经过分析后,正常的请求用时一般在 2 秒以内,异常的请求在 62 到 63 秒之间。可以确定是异常的请求用时太长,客户端主动断开链接。为什么请求用时太长的问题,这个很难排查出一个确定的原因,可以推测是在香港华为云上的项目 kubernetes 环境与华为云 OBS 之间网络会偶尔出现一点问题,导致上传时间用时 62 到 63 秒。不过问题的直接原因是前端的管理后台服务中断了用时超长的请求,具体还是要前段同事去解决问题。
Question 10
项目优化的方式
API 请求分析,GC 信息记录,Kubernetes 服务实例的信息记录,比如内存使用记录和 CPU 使用记录
ZGC jdk 21.0.4: ZGC Major Collection (Proactive) 日志详解,ZGC 的两种主要的垃圾收集类型
ParallelGC jdk 1.8: ParallelGC 日志详解
FullGCListener: FullGCListener
SQL 耗时跟踪: SQL 耗时跟踪
Question 11
Kubernetes 中,流水线正常启动,但是容器无法正常启动,一闪而过 OOMKILLED,然后变成启动失败的重启状态。
原因是容器初始限制最多 2G 内存,但是 JAVA 启动命令请求 4G,年轻代设置 2G,内存请求达到限制门槛,但是还不够正常启动,于是发生 OOMKILLED,容器启动失败。
Question 12
线上服务报错,错误信息 java.lang.StackOverflowError
,已知设置的运行内存和 metaspace 空间大小都是充足的,查看报错日志,大量的阿里巴巴 fastjson
报错。 fastjson
版本为 1.2.60
,最近的代码变动是使用 fastjson
中的 JSON.toJSONString
方法,推测是 JSON.toJSONString
方法的循环递归调用遇见未知问题,导致发生 java.lang.StackOverflowError
,将代码变动回滚,重新发布,错误消除。
Posted on October 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024