[英]Tomcat requires long time to recognizes the start of spring-boot application
將打包為war
的SpringBootApplication
部署到 tomcat 服務器時,我遇到了一個奇怪的問題。
有時,即使應用程序啟動成功,tomcat 服務器也無法識別(或更准確地說,需要很長時間)應用程序啟動。 - 如果我說成功,我的意思是應用程序可以執行備份作業,例如cron
作業,訪問其數據庫並通過SOAP
連接到第三方服務。
當 tomcat 服務器無法識別啟動時,問題是應用程序的REST
端點無法訪問,更糟糕的是,如果我在應用程序位於 webapps 文件夾中時重新啟動 tomcat 服務器,整個 tomcat 服務器將被凍結。
老實說,我不知道可能是什么問題,甚至不知道從哪里開始尋找。
我懷疑,不知何故,自定義ThreadPoolTaskScheduler
(見下文)觸發了這個問題。 但即使我將池大小設置為 1,也會出現此問題。
從顯示啟動時間的日志文件中提取:
Started CrewAlertApplication in 17.358 seconds (JVM running for 58.215)
Deployment of web application archive [/srv/prod/cpappp/tomcat/webapps/crew-alert##1.2.1.war] has finished in [21.691] ms
Started CrewAlertApplication in 25.161 seconds (JVM running for 75.633)
Deployment of web application archive [/srv/prod/cpappp/tomcat/webapps/crew-alert##1.2.1.war] has finished in [1.056.389] ms
以下是有關環境的一些信息:
Tomcat(在VMWare
機器上運行,有4核)
Server Version: Apache Tomcat/9.0.43
Server built: Jan 28 2021 20:25:45 UTC
Server version number: 9.0.43.0
OS Name: Linux
OS Version: 5.8.0-0.bpo.2-amd64
Architektur: amd64
Java Home: /srv/jdk-11.0.9+11
JVM Version: 11.0.9+11
JVM Hersteller: Eclipse OpenJ9
該應用程序本身基於:
ThreadPoolTaskScheduler
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("CrewAlertThreadPool");
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
return threadPoolTaskScheduler;
}
下圖顯示了 tomcat 經理。 啟動了tomcat,然后部署了應用(部署在tomcat上的其他應用全部啟動成功)。
更新 1:
正如@AndyWilkinson 指出的那樣,問題出現在我調用@EventListener
方法的JpaRepository
方法中
List<ScheduledNotification> findByScheduledTimeBetween(ZonedDateTime from, ZonedDateTime to)
它被“翻譯”成
Hibernate: select scheduledn0_.id as id1_6_, scheduledn0_.alert_id as alert_id3_6_, scheduledn0_.scheduled_time as scheduled_time2_6_
from scheduled_notification scheduledn0_
where scheduledn0_.scheduled_time between ? and ?
以下是該實體的摘錄:
@Entity(name = "SCHEDULED_NOTIFICATION")
@Table(indexes = { @Index(name = "IDX_SCHED_NOTIF_SCHEDTIME", columnList = "SCHEDULED_TIME") })
public class ScheduledNotification extends AbstractId implements Comparable<ScheduledNotification> {
@ManyToOne(optional = false)
@JoinColumn(name = "ALERT_ID", nullable = false)
private Alert alert;
@Column(name = "SCHEDULED_TIME", nullable = false, columnDefinition = "TIMESTAMP")
@Convert(converter = ZonedDateTimeConverterUtc.class)
private ZonedDateTime scheduledTime;
@OneToMany(mappedBy = "scheduledNotification", cascade = ALL, orphanRemoval = true, fetch = EAGER)
private Set<Leg> legs;
...
這個電話實際上花費了將近 18 分鍾。 這有點令人驚訝,因為該表從未包含超過 100 個條目(在本例中返回了 3 個結果)。
2021-07-14 12:53:34.506 INFO [] --- [Catalina-utility-3] c.lalacomp.alert.CrewAlertApplication : Started CrewAlertApplication in 26.577 seconds (JVM running for 108237.294)
2021-07-14 12:53:34.509 INFO [] --- [Catalina-utility-3] c.l.a.scheduler.NotificationExecutor : ApplicationReadyEvent received.
2021-07-14 12:53:34.528 DEBUG [] --- [Catalina-utility-3] c.l.a.s.ScheduledNotificationServiceImpl : findImmediate() - Looking up schedules between: 2021-07-14T10:38:34Z[UTC] and 2021-07-14T11:08:34Z[UTC]
2021-07-14 12:53:34.572 INFO [] --- [Catalina-utility-3] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
...
2021-07-14 13:11:27.637 TRACE [] --- [Catalina-utility-3] c.l.a.s.ScheduledNotificationServiceImpl : We've found: ...
2021-07-14 13:11:27.639 INFO [] --- [Catalina-utility-3] c.l.a.scheduler.NotificationExecutor : Adding 3 new ScheduledNotifications at startup.
...
瞧,時間戳確實匹配,應用程序被識別為正在運行:
14-Jul-2021 13:11:27.662 INFORMATION [Catalina-utility-3] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/srv/prod/cpappp/tomcat/webapps/crew-alert##1.2.2.war] has finished in [1.103.405] ms
所以現在我必須弄清楚,為什么這需要這么長時間? 因為針對數據庫(其他表)的其他查詢執行正常。
更新 2:
如果我直接在控制台上運行類似的sql
語句,運行時絕對沒問題。
select * from scheduled_notification sn
join leg l on sn.id = l.SCHEDULED_NOTIFICATION_ID
join alert a on sn.ALERT_ID = a.id
where scheduled_time between SYSTIMESTAMP and SYSTIMESTAMP + 2 /24;
Fetched 30 rows in 0.015 secs
我還想知道為什么上面的Hibernate
聲明(更新 1)不包括“連接關系”。
正如@AndyWilkinson 指出的那樣,問題出在ApplicationReadyEvent
中。 在連接到此事件的方法中,我從數據庫中獲取數據,由於一些昂貴的關系,這花費了很長時間。
我更新了實體並簡化了其中的一些關系。 現在該方法按預期執行。
非常感謝,所有的功勞都歸功於 Andy!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.