最近写了一个项目,也是两三年没写后端的我再次尝试后端项目,在开发和部署的过程中,都遇到了许多奇奇怪怪的问题,
记录下来,也算是对这段时间惊心动魄经历的一次总结吧。
K8s容器内部时间错误
项目上线后,是使用Docker+K8s进行运维和部署的,但是测试环境是普通ECS主机。测试环境一切正常,
但是在生产环境出现了订单时间出现了错误,起初是认为自己项目时间没有做"UTC+8"处理,或者是mysql连接时
未指定时区。不过这两点检查之后,都没有问题。最后把目光放到了容器里。
在测试机使用命令date
出现的时间是这样的:
1
| Fri Apr 30 04:53:38 UTC 2021
|
但是在K8s那边检查时间,出来的时间是:
1
| Fri Apr 30 04:53:38 EDT 2021
|
如果容器的时间出现问题,那么就很好解释为什么存到数据库里的时间出现问题了。因为运维的同学不在国内,所以他的时区也不是UTC+8,就没有发现这个问题。
时间调整好后,问题消失。
最后补充一下常见的几个时区吧:
- GMT,即格林尼治标准时间,也就是世界时。
- UTC,即协调世界时。现在用的最多的也是UTC。
- CST,中国标准时间(China Standard Time) GMT + 8 = UTC + 8 = CST
提示:前提系统的区域设置为Asia/Shanghai,CST还有其他释义,是与区域有关。
- EDT,美国东部夏令时间,波士顿、纽约市、华盛顿哥伦比亚特区,都在这个时区内,跟北京时间有12小时的时差,晚12小时。
关联问题:
由于容器时间错误,所以导致微信支付SDK SSL异常,报错401。如果有集成微信支付项目启动时报错401,就需要检查下系统时间和时区是否正确了。
ApplicationRunner里面不允许执行死循环操作,需要独立线程
由于使用Redis的Zset来做订单超时队列(轻量实现),在启动项目的时候,需要启动一个死循环线程来执行zRangeWithScores()
但是发现不是所有继承ApplicationRunner
的类都会被启动,这是什么原因呢,难道是没有指定顺序么?
经查阅,找到了控制顺序的注解@Order(1)
里面的数字则为具体启动的顺序。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11
| @Component @Order(3) public class ApplicationRunnerImpl implements ApplicationRunner {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override public void run(ApplicationArguments args) throws Exception { logger.info("====== Service All Init Complete ======"); } }
|
经过调整将死循环任务放在最后一个执行可以解决此问题,但是治标不治本,查看下源码实现可以看到:
他是通过foreach遍历每一个实现ApplicationRunner的类,执行每一个类的内容来实现的,那么不可以在ApplicationRunner
里面出现死循环就很好理解了,我们创建一个线程就可以解决此问题了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); Iterator var4 = (new LinkedHashSet(runners)).iterator();
while(var4.hasNext()) { Object runner = var4.next(); if (runner instanceof ApplicationRunner) { this.callRunner((ApplicationRunner)runner, args); }
if (runner instanceof CommandLineRunner) { this.callRunner((CommandLineRunner)runner, args); } }
}
|
Maven镜像源地址可以配阿里的
由于K8s每次构建镜像速度都是纯净环境从零构建的,每次都需要重新拉取一遍依赖,但是由于网速限制,拉取占用了太多时间。
于是将镜像源配置为阿里的源,这样使用阿里的K8s服务时,构建速度会快很多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <repositories> <repository> <id>maven-ali</id> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>fail</checksumPolicy> </snapshots> </repository> </repositories>
|
JSON变成了XML
由于微信的SDK接入比较复杂,所以使用了一个简单的库来解决这个问题payment-spring-boot-starter
但是引入之后,返回的内容都默认变成了XML格式。
经过排查,是由于这个库引入了jackson-dataformat-xml
导致的,那么我们直接移除它就可以了。
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>cn.felord</groupId> <artifactId>payment-spring-boot-starter</artifactId> <version>1.0.8.RELEASE</version> <exclusions> <exclusion> <artifactId>jackson-dataformat-xml</artifactId> <groupId>com.fasterxml.jackson.dataformat</groupId> </exclusion> </exclusions> </dependency>
|