1. 程式人生 > >Spring boot內建Tomcat的臨時目錄被刪除導致檔案上傳不了-問題解析

Spring boot內建Tomcat的臨時目錄被刪除導致檔案上傳不了-問題解析

目錄

  • 1、問題
    • 2.1、 為什麼需要使用這個/tmp/tomcat*?
    • 2.2、那個 /tmp/tomcat* 目錄為什麼不存在?
  • 三、解決辦法
    • 修改 springboot 配置,不要在/tmp 下建立目錄
    • 修改 清理 /tmp 下面的檔案的機制
  • 四、spring boot 官方解答

1、問題

在過年後,部分運營人員反應說運營後臺上傳不了圖片,然後檢視日誌,發現報錯內容是/tmp/tomcat* 目錄不存在

環境:

  • spring boot 1.5.15
  • Centos7.6(aliyun)

    2、 問題解析

  1. 為什麼需要使用這個/tmp/tomcat*?
  2. 那個 /tmp/tomcat* 目錄為什麼不存在?

2.1、 為什麼需要使用這個/tmp/tomcat*?

預設情況下,spring boot 的內建 Tomcat ,會在/tmp建立兩個目錄 /tmp/tomcat*,這個目錄用於儲存編譯的JSP 和 上傳的檔案。

2.2、那個 /tmp/tomcat* 目錄為什麼不存在?

不存在是因為被Linux 的機制進行清除了。

這個機制是什麼原理:
首先我們得從服務 systemd-tmpfiles-clean 說起。

[root@djx ~]# systemctl  status  systemd-tmpfiles-clean
● systemd-tmpfiles-clean.service - Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.service; static; vendor preset: disabled)
   Active: inactive (dead) since Tue 2020-02-25 09:10:36 CST; 12h ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 21819 ExecStart=/usr/bin/systemd-tmpfiles --clean (code=exited, status=0/SUCCESS)
 Main PID: 21819 (code=exited, status=0/SUCCESS)

Feb 25 09:10:36 djx systemd[1]: Starting Cleanup of Temporary Directories...
Feb 25 09:10:36 djx systemd[1]: Started Cleanup of Temporary Directories.

我們可以看到這個服務今天上午 9點執行了一次,我們繼續看看這個服務對應的執行命令是什麼?

cat  /usr/lib/systemd/system/systemd-tmpfiles-clean.service
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target time-sync.target
Before=shutdown.target

[Service]
Type=oneshot
ExecStart=/usr/bin/systemd-tmpfiles --clean
IOSchedulingClass=idle

我們先記住這個執行命令是/usr/bin/systemd-tmpfiles --clean,我們再來關心下,與這個服務相關的定時器 /usr/lib/systemd/system/systemd-tmpfiles-clean.timer

cat  /usr/lib/systemd/system/systemd-tmpfiles-clean.timer 
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Daily Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d

我們從這知道在啟動後的15分鐘或者距離上一次執行一天 會執行我們上面的命令/usr/bin/systemd-tmpfiles --clean

那麼上面這個命令具體又執行了什麼? 我們在 man systemd-tmpfiles中找到了一些東西。

DESCRIPTION
       systemd-tmpfiles creates, deletes, and cleans up volatile and temporary files and directories, based on the configuration file format and location
       specified in tmpfiles.d(5).

       If invoked with no arguments, it applies all directives from all configuration files. If one or more filenames are passed on the command line, only
       the directives in these files are applied. If only the basename of a configuration file is specified, all configuration directories as specified in
       tmpfiles.d(5) are searched for a matching file.

從上面這個描述我得到了兩個資訊:

  1. 就是 systemd-tmpfiles 用來建立和清理臨時性的目錄和檔案。
  2. systemd-tmpfiles 會從 tmpfiles.d 中獲取配置檔案。

當然我們在 man systemd-tmpfiles 中還可以瞭解到一些引數命令。

我們接著去看 tmpfiles.d, 我們在 man tmpfiles.d中可以看到 tmpfiles.d 的作用就是用於清理臨時檔案和目錄的配置。 我們還可以看到它的配置儲存於

/etc/tmpfiles.d/*.conf
/run/tmpfiles.d/*.conf
/usr/lib/tmpfiles.d/*.conf

在這裡我們還可以看到配置檔案裡面的相關注解。

接下來我們去上面列出的三個目錄裡面找找看有沒有相關清理/tmp的東西。
最後在 /usr/lib/tmpfiles.d/tmp.conf 裡面找到了,

cat /usr/lib/tmpfiles.d/tmp.conf 
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

# See tmpfiles.d(5) for details

# Clear tmp directories separately, to make them easier to override
v /tmp 1777 root root 10d
v /var/tmp 1777 root root 30d

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

我們可以看其中的兩個配置

v /tmp 1777 root root 10d  # 就是當 /tmp 目錄不存在的時間進行建立(許可權為777,使用者和使用者組為root),並清理/tmp下超過10天的檔案。
x /tmp/systemd-private-%b-*  # 忽略清理的目錄
X /tmp/systemd-private-%b-*/tmp # 這個只忽略目錄,但不忽略該目錄下面的內容

意思就是 清理/tmp 目錄下超過10天沒有變化的檔案,但不清理/tmp/systemd-private-%b-*/tmp/systemd-private-%b-*/tmp.
總結 系統會自動進行清理 /tmp 目錄下10天沒有變化的檔案和目錄

過年期間我們的 Tomcat 生成的目錄如果10天沒有發生變化,也就會被刪除。

三、解決辦法

修改 springboot 配置,不要在/tmp 下建立目錄

配置引數 :server.tomcat.basedir

修改 清理 /tmp 下面的檔案的機制

/usr/lib/tmpfiles.d/tmp.conf 下面增加一個 x /tmp/tomcat*

四、spring boot 官方解答

官方相關的 issue :

  • https://github.com/spring-projects/spring-boot/issues/5009
  • https://github.com/spring-projects/spring-boot/issues/9616

在 https://github.com/spring-projects/spring-boot/issues/9616,
在最底部我們可以

You can see the list of releases that contain the fix in the commit that closed this issue. In the 2.1.x line it was fixed in 2.1.4.

看到 2.1.4 版本已經解決了該問題。在 1系列的版本中,我們可以看到在 1.5.20 中也修復了,github對應的提交記錄

參考:https://www.cnblogs.com/samtech/p/9490166.