问题
最近做了一个新项目上线了,同事配置了shardingsphere-jdbc的版本为5.2.0
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.0</version>
</dependency>
但是服务上线后,前端请求服务第一次服务总是报超时,耗时最长的请求处理时间大概在7s左右,但是就只是一个简单分页查表得sql。问题是只会在第一次查询sql时超级慢,后面sql的执行就正常了。然后断点跟了一下源码shardingsphere,发现其中一些不涉及i/o的操作方法执行时间偏长,但是在第二次执行时时间就变得极短。
推测
因为不涉及I/O操作,那么耗时较长的问题怀疑是程序在运行时加载大量的类导致的耗时较长,根据类的加载机制,程序在启动时不会立刻加载所有的类,而是在程序运行给过程中使用到了某个类,才会进行加载,这也解释了第一次执行sql查询时即使是很简单的一个查询,由于需要加载shardingsphere用到的所有类,而导致耗时较长;第二次执行时由于类都已经加载了,所以执行的速度恢复了正常
解决方案
在应用程序启动后手动执行一次数据库查询,这样sql执行所需要的类都会加载,这样后续接收到上游流量时,不会因为再需要加载类而浪费时间
public class ComponentWarmer implements ApplicationRunner{
public void run(ApplicationArguments args) {
log.info("数据库预热开始");
//执行sql查询
log.info("数据库预热结束 {}ms");
}
}
结论
因此对于流量较大的系统,预热服务尤为重要,当然除了mysql数据库的预热,redis,调用第三方服务,dubbo服务,等等都可以进行预热。同样如果dubbo服务的可以设置预热启动,设置预热时长,从缓慢的接收流量到正常提供服务