Tomcat 非正常關閉後重啟,常見嚴重錯誤:Exception loading sessions from persistent storage。本文解析根因、提供標準關閉方案與禁用持久化配置,徹底消除啟動報錯。
嚴重: Exception loading sessions from persistent storage
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2738)
...
根因:Tomcat 預設啟用 Session 持久化(StandardManager),關閉時將內存 Session 序列化到 work/Catalina/localhost/。非正常關閉(kill -9、崩潰、斷電)導致文件寫入不完整或損壞,啟動時反序列化失敗拋出 EOFException/StreamCorruptedException。
影響:僅影響 Session 恢復,用戶需重新登錄,**不影響應用業務功能**。
LifecycleListener 正常持久化 Session。KillSignal=SIGTERM、TimeoutStopSec=60 確保優雅停機。修改 conf/server.xml 或 conf/context.xml,在 <Context> 節點添加 <Manager> 配置:
<Context ...>
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="false" />
</Context>
<Context ...>
<Manager className="org.apache.catalina.session.StandardManager"
pathname="" />
</Context>
pathname="" 表示不生成 SESSIONS.ser 文件。
<!-- 需引入 tomcat-redis-session-manager 依賴 -->
<Context ...>
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="redis-host" port="6379"
database="0" maxInactiveInterval="1800" />
</Context>
Exception loading sessions。rm -rf work/Catalina/localhost/*/SESSIONS.ser。若業務強依賴 Session 恢復,可繼承 StandardManager 重寫 load() 方法,捕獲異常時記錄警告並返回空 Session 集合,而非拋出異常中斷啟動:
public class RobustManager extends StandardManager {
@Override
public void load() throws ClassNotFoundException, IOException {
try {
super.load();
} catch (Exception e) {
log.warn("Session 持久化文件損壞,忽略並啟動空 Session 池", e);
sessions.clear();
}
}
}
在 context.xml 中指定 className="com.example.RobustManager"。
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 標準關閉 | 所有環境 | 保留 Session、零配置 | 依賴運維規範,不可控 |
| 禁用持久化 | 無狀態服務、可接受重新登錄 | 簡單徹底、零報錯 | 重啟 Session 丟失 |
| Redis Session | 生產集群、高可用要求 | Session 不丟、跨實例共享 | 引入外部依賴、增加複雜度 |
| 自定義 Manager | 需保留 Session 但容忍損壞 | 啟動不阻塞、兼容現有邏輯 | 需開發維護、邊界情況需測試 |
推薦策略:開發/測試環境禁用持久化,生產環境上 Redis Session,徹底告別啟動報錯與 Session 丟失困擾。