Hello,我是大都督周瑜,最近在公司做微服务启动速度的优化,我们有些微服务启动要花「5-6分钟」(就问你夸不夸张),直接导致打工人们有了更多的划水时间,领导表示不开心,要求我将微服务的启动速度控制在30秒以内,而那些特殊的微服务控制在1分钟以内,怎么办,请看我的表演。
第一步,肉眼看启动日志,先看启动时哪些类型的日志长时间频繁打印,经过我的火眼金睛,找到了以下几个憨憨怪。
第一个,Shardingsphere
我们用的Shardingsphere 5.x的版本,在微服务启动时,ShardingShpere需要获取数据库中的每张表的元数据信息,比如字段信息、索引信息,这些查询日志在启动时会频繁打印,比如以下日志会频繁打印:
因此,表越多,这个步骤消耗的时间就越多,好在我们开发环境的表不多,只有2000多张,是的,「2000多」张表!!!当然啦,毕竟是开发库,没怎么做过清理,并且我们有业务是动态创建表的,所以表很多,BUT,就算删掉那些没用的表,也还有600多张,而且是一个库下面有600多张表,我都不好意思说我们是微服务架构了。
咋搞,我的办法是多线程+多数据连接,通过自定义Shardingsphere的元数据加载器MetaDataLoader,改造为内部通过线程池异步开启多个数据库连接来获取表的元数据信息,伪代码如下:
for (List<String> each : Lists.partition(tables, tables.size() / 4)) {
// 创建连接
Connection connection = 获取数据库连接;
// 获取元数据
futures.add(EXECUTOR_SERVICE.submit(() -> loadColumnMetaDataMap(connection, each)));
}
for (Future<Map<String, Collection<ColumnMetaData>>> each : futures) {
columnMetaDataMap.putAll(each.get());
}
第二个,还是ShardingShpere
前面Shardingsphere只是在查询表的元数据,可恶的是,它查出来之后还会存到H2数据库中(我们用的单机模式),我是怎么发现的呢?是因为上面查询元数据的日志频繁打印后,会突然暂停,控制台突然就不打印任何日志了,最开始,我还以为是应用启动结束了,后来才发现这只是中场休息,两分钟后就开始继续打印其他日志了。
为什么会中场休息?经过看源码发现,是Shardingsphere需要将查到的元数据信息存到H2数据库中,所以,如果表越多,表的元数据就越多,存H2的时间就越久(尽管是存内存中),关键是这个过程Shardingsphere还不打info日志,所以不研究一下就不知道应用在干嘛。
那么解决思路是一样的,多线程并发将元数据存入H2数据库,只不过这就得改Shardingsphere的源码了,不过我们本来就改了Shardingsphere的源码了,将错就错,直接在现有的源码的基础上,通过线程池并发将元数据存入H2数据库。
别说,经过以上两个措施优化之后,成功将启动时间从5-6分钟缩短到了2分钟左右,效果很不错,领导很满意(领导们别光看,记得点赞三连哦),但是距离1分钟的目标还差1分钟,怎么办?
第三个,Bean扫描
我相信大部分SpringBoot应用的启动类都是这么写的:
/**
* 大都督周瑜(微信: dadudu6789)
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这么写,SpringBoot会扫描Application类所在的包路径,假如包路径为com.zhouyu
,那么SpringBoot启动时就会扫描com.zhouyu
这个包下的所有类,因为Spring需要去判断每个类是不是Bean,比如一个类加了@Component注解就是Bean,没加就不是Bean,但是不管怎样都需要去解析类,因此,如果com.zhouyu
包下的类特别特别多,就会很影响扫描的速度,从而影响应用的启动速度,解决办法就是:
@SpringBootApplication(scanBasePackages = {"com.zhouyu.controller", "com.zhouyu.service",...})
通过@SpringBootApplication注解的「scanBasePackages」属性明确指定那些「真正定义了Bean的包路径」,这样SpringBoot启动时就只会扫描指定的包路径,这样Bean扫描的效率就会高很多,从而提高应用的启动速度,经过我测试,应用的启动速度又缩短了50秒左右,现在距离目标1分钟只有10秒左右了,开心。另外告诉大家一个秘密,我测试的这个微服务中总共有2000多个Bean对象,300个多@Service,200个@RestController~~~~
第四个,日志打印
通过观察日志发现,启动过程中,Spring Fox会打印1000条日志,这是因为我们Controller接口比较多,Spring Fox会对大部分Controller接口中的@RequestMapping都打印一条日志,这种日志其实没有太大的意义,一条日志打印需要几百毫秒,那么所有1000条日志加起来也是一比不少的开销,所以就直接关掉,同样还找了一些其他没有太大作用的日志,通过SpringBoot的配置文件都关掉了,比如:
logging:
level:
springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator: OFF
这样,又节省了一些启动时间,最终成功达到了领导预期的目标,可以开心过五一了。
其实这个过程中,除开通过肉眼观察日志,还利用了一些工具,比如开源项目「spring-startup-analyzer」,它可以分析启动过程中每个Bean的创建时间,还有「IntelliJ Profiler」,它可以分析启动过程中某个线程或某个方法的执行时间,都是非常有用的,感谢这些工具和背后的大佬。
广告时间
熟悉我的应该知道,最近其实一直在公司做机器学习、大模型智能客服相关的工作,所以积累了一些经验,再加上做了这么多年的讲师,所以一直有个想法:「按自己的想法和要求做课程」。
现在这个课程正式出炉了,名字叫做《面向未来的AI精品课》,「课程的核心是大模型,包括」大模型企业开发实战、「大模型前沿技术追踪」、「大模型底层原理分析」等专题,课程每更新一个专题,价格就会上涨,所以早买早享受,越早越便宜。
目前「大模型企业开发实战」相关内容已经全部更新完毕,该专题的重点内容是「Langchain4j」和「Spring AI」,我在公司做技术选型时,选择的就是「Langchain4j」,它是Java版本的Langchain,功能上不比Python版本的Langchain少,而Spring AI还处于萌芽阶段,功能没有Langchain4j丰富,但是不排除后来居上,所以在课程中这两个「大模型应用开发框架」我都做了深入的解析和实战。
课程充分考虑了Java程序员的感受,因为我本人就是做Java出身的,所以Java同学们通过这个课程就能「跟上AI时代的脚步」,不被AI所淘汰。同时,对于想要跳槽的同学,通过课程「让AI技能成为你的技能亮点」,从而被更多企业选中,升职加薪更容易。
另外,现在加入课程的同学,可以「免费加入《大都督的朋友圈》知识星球」,已经在知识星球的同学也可以私聊我,我会给你相应的优惠券,想了解课程详情的同学可以加我微信,备注【大都督AI】,将给你惊喜内容惊喜价哦!




