在Linux環境上創建、拷貝文件或者vi編輯文件保存時經常會遇到系統提示"No space left on device"提示空間不足的問題。這種問題通常是由於磁盤空間不足或者inodes節點不足導致。解決辦法也很簡單就是刪除不需要的文件進行磁盤空間或者inode節點釋放。本文主要描述出現該問題時的分析方法和刪除文件方法,包括:
(1)"No space left on device"問題分析,通過df -h查看是否磁盤空間不足,df -i查看是否inode節點不足。
(2)如何快速查找磁盤空間不足對應文件系統中的超大文件並進行刪除。
(3)介紹使用find指令或者腳本快速刪除無用文件。
問題現象
在創建文件或者vi編輯保存文件時linux系統提示"No space left on device"。
問題分析
出現"No space left on device"提示信息導致操作失敗的原因通常有3種:
(1)文件系統中文件占用空間總量即將或超過100%。通過df -h可以查看是否有文件系統空間使用率快達到100%或已達到100%。
(2)文件已經刪除但是存在占用文件的進程導致空間未釋放。可以通過df和lsof指令查看。df查看文件系統空間充足,lsof查看存在已刪除文件占用的進程。
(3)inodes節點不足導致。這種情況通常是系統上有非常多的單個文件占用空間很小但是數量很多導致。常見於linux服務器上安裝有oracle數據庫的場景。oracle數據庫會生成很多的日志文件。
問題解決
(1)文件系統中文件占用空間總量即將或超過100%問題解決
Step1、利用df命令確定將磁盤空間即將耗盡的文件系統對應的目錄。
linux~ # df 文件系統 1K-塊 已用 可用 已用% 掛載點 /dev/sda2 146294492 28244432 110498708 21% /
/dev/sda1 1019208 62360 904240 7% /boot tmpfs 1032204 0 1032204 0% /dev/shm /dev/sdb1 2884284108 2884284108 0 100% /home
根據上述結果可知,/dev/sdb1磁盤空間即將達到100%,對應的掛載點為/home目錄。進入/home目錄進行查找刪除操作即可 。
Step2、利用du命令逐級查找占用磁盤空間較大的文件或者文件夾。
linux~ # du -sm /home
Step3、刪除查找到的無用的安裝包、備份包文件或者長期未清理的debug日志。如果查找確認之后發現並無占用較大空間的文件,需確認該文件系統掛載點/home目錄下是否已被使用並且存在占用空間較大的文件。使用umout /home卸載掛載點查看。具體查找刪除文件方法可以查看FAQ。
Step4、重新執行df命令查看/dev/sdb1磁盤空間使用率是否降低。如果磁盤空間釋放大小與已刪除文件大小不一致,參考"df與du顯示磁盤空間不一致問題解決"
2、df與du顯示磁盤空間不一致問題解決
使用df命令查看文件系統空(/home)間不足,刪除大文件后執行df重新查看,文件系統空間卻並未增加。可能是刪除文件時仍有進程在使用,刪除時只是對刪除文件做deleted標記並未真正釋放。空間未釋放。
分析解決方法如下:
Step1、du -sm /home查看對應文件系統文件占用大小。發現文件占用空間遠遠小於df查看占用的空間。
Step2、使用lsof指令查看被標記deleted但未真正釋放的文件
linux~ # lsof /home | grep 'deleted'
或者
linux~ # ls -ald /proc/*/fd/* | grep 'deleted' | grep -v 'pts'
根據上述結果發現確實有進程占用剛刪除的大文件。
Step3、kill掉占用刪除文件的進程
linux~ # lsof /home | grep 'deleted' | grep -v grep | awk '{print $2}' | sort|xargs kill -9
或者手工獲取占用文件的進程ID,執行kill -9 ${ID}
Step4、重新執行df查看,問題解決。
3、df -i顯示inodes使用率即將100%
Step1、df -i查看inodes使用率即將達到100%。獲取對應的文件系統掛載目錄。如/home
Step2、使用find命令查找文件,刪除不需要使用的文件。通常為業務日志文件、oracle數據庫日志文件、審計文件等等。大文件很少會出現這種情況,因為有大量大文件的話,首先應該是會把磁盤空間占滿。具體查找刪除文件方法可以參考FAQ。
Step3、刪除文件,重新執行df -i查看,問題解決。
4、FAQs
1、如何實現自動刪除服務器垃圾文件?
需求描述
(1)假設業務運行產生的日志文件生成路徑位於$HOME/log目錄下,文件名為'用戶名_[debug|run|warn].log'或者'用戶名_[debug|run|warn].log.n',n為數字,常為備份名。
(2)假設業務運行產生的臨時文件生成路徑位於$HOME/temp目錄,文件名為'用戶名_[debug|run|warn].tmp'或者'用戶名_[debug|run|warn].tmp.n',n為數字,常為備份名。
(3)查找Linux服務器超過指定大小(如100M)的安裝包、備份包文件,供用戶人工判斷是否可以刪除。
(4)不能誤刪系統文件,特別是oracle用戶的重做日志文件(redoN.log)。
代碼實現
#!/bin/bash #******************************************************** #*** Author : lion #*** Create Date : 2017/09/18 #*** Modify Date : NA #*** Function : Delete the server logs and temp files #******************************************************** function Usage() { echo "NAME" echo " clearlogs.sh" echo "SYNOPSIS" echo " clearlogs.sh" echo "DESCRIPTION" echo " clear the server logs and temp files" exit 0 } function writelog() { local logfile=$1 local debug_level=$2 local messages=$3 echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${debug_level}] ${messages}" echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${debug_level}] ${messages}" >> ${logfile} } function find_logs() { local user=$1 local user_home=$2 if [ -d ${user_home}/log ];then find ${user_home}/log -maxdepth 2 -type f -name "${user}*.log*" -mtime +${KEEP_DAYS} -print >> "${DELETE_LOGS_LIST}" fi if [ -d ${user_home}/temp ];then find ${user_home}/temp -maxdepth 2 -type f -name "${user}*.tmp*" -mtime +${KEEP_DAYS} -print >> "${DELETE_LOGS_LIST}" fi } if [ "X$1" == "X--help" ];then Usage fi if [ $(whoami) != 'root' ];then printf "Please use root to execute\n" exit 1 fi ##global Var CURRENT_PATH=$(pwd) CURRENT_DATE=$(date '+%Y%m%d') SCRIPT_NAME="clearlogs" CLEARLOGS_DIR="${CURRENT_PATH}/${SCRIPT_NAME}_${CURRENT_DATE}" SEARCH_FILE_SIZE='100M' LOG_FILE="${CLEARLOGS_DIR}/${SCRIPT_NAME}.log" DELETE_LOGS_LIST="${CLEARLOGS_DIR}/${SCRIPT_NAME}_delete_files.log" USER_LIST="${CLEARLOGS_DIR}/user.lst" BIG_FILES_LIST="${CLEARLOGS_DIR}/${SCRIPT_NAME}_bigfile.lst" KEEP_DAYS=3 if [ ! -d ${CLEARLOGS_DIR} ];then mkdir ${CLEARLOGS_DIR} fi rm "${DELETE_LOGS_LIST}" "${USER_LIST}" "${BIG_FILES_LIST}" &> /dev/null touch "${DELETE_LOGS_LIST}" "${USER_LIST}" "${BIG_FILES_LIST}" awk -F':' '{if($0 !~ /var/)print $1,$6}' /etc/passwd > "${USER_LIST}" writelog "${LOG_FILE}" "INFO" "Begin find logs and temp files,wait a moment....." while read user user_home do find_logs ${user} ${user_home} & done < "${USER_LIST}" wait writelog "${LOG_FILE}" "INFO" "End find logs and temp files" writelog "${LOG_FILE}" "INFO" "Begin delete logs and temp files at ${DELETE_LOGS_LIST}" while read line do if [ -f ${line} ];then rm ${line} &> /dev/null if [ $? -eq 0 ];then writelog "${LOG_FILE}" "INFO" "File[ ${line} ] delete success" else writelog "${LOG_FILE}" "INFO" "File[ ${line} ] delete failed" fi fi done < "${DELETE_LOGS_LIST}" writelog "${LOG_FILE}" "INFO" "End delete logs and temp files at ${DELETE_LOGS_LIST}" writelog "${LOG_FILE}" "INFO" "Begin find larger than ${SEARCH_FILE_SIZE} files,wait a moment....." find / \( -path '/proc' -o -path '/var' \) -prune -o -type f -size "+${SEARCH_FILE_SIZE}" -print > "${BIG_FILES_LIST}" writelog "${LOG_FILE}" "INFO" "End find larger than ${SEARCH_FILE_SIZE} files" writelog "${LOG_FILE}" "INFO" "The files at [ ${BIG_FILES_LIST} ] are larger than ${SEARCH_FILE_SIZE},please check and delete by manual"
使用方法
(1)上述代碼已上傳至github,下載路徑:clearlogs.sh,上傳到root用戶目錄下,任意目錄。
(2)執行chmod +x clearlogs.sh賦可執行權限。
(3)執行./clearlogs.sh。查看相關日志即可。
說明:1、腳本可以根據實際情況進行修改以適用當前產品;2、腳本多次運行測試正常后可配置定時任務進行定期清理刪除。
2、Linux下如何快速查找占磁盤空間大的文件
需求背景
清理服務器文件系統空間時經常需要查找大文件以進行分析刪除,從而釋放空間。
設計思路
快速查找服務器上所有超過指定大小的文件並顯示。第一列顯示文件大小,第二列顯示文件絕對路徑。通常可以直接如下命令進行查找:
find / -type f -size +100M -print
考慮加快查找速度,分成多個目錄在后台並發查找並顯示。獲取目錄方法如下
find / -maxdepth 2 \( -path '/proc' -o -path '/var' \) -prune -o -type d -print | grep '^/.*/'
假設文件名為linux.tar.gz,第一列顯示文件大小,第二列顯示文件路徑如下:
awk -v filename="linux.tar.gz" -v filesize=$(stat -c %s "linux.tar.gz" ) 'BEGIN{print filesize/1024/1024"M",filename}'
代碼實現
#!/bin/bash SEARCH_DIR_LIST="search_directory.txt" SEARCH_TEMP_FILES="search_temp_files.txt" SEARCH_FILES="search_files.txt" file_size="100M" if [ $(whoami) != 'root' ];then printf "Please Use root to execute\n" exit 1 fi rm "${SEARCH_DIR_LIST}" "${SEARCH_TEMP_FILES}" "${SEARCH_FILES}" &> /dev/null find / -maxdepth 2 \( -path '/proc' -o -path '/var' \) -prune -o -type d -print | grep '^/.*/'> "${SEARCH_DIR_LIST}" printf "Begin search larger than ${file_size}M files,wait a moment....\n" while read line do ( find ${line} -type f -size +${file_size} -print >> "${SEARCH_TEMP_FILES}" ) & done < "${SEARCH_DIR_LIST}" wait printf "End search larger than ${file_size}M files.\n" printf "Begin Compute each files detail size,please wait...\n" while read line do awk -v filename=${line} -v filesize=$(stat -c %s ${line}) 'BEGIN{print filesize/1024/1024"M",filename}' >> ${SEARCH_FILES} done < "${SEARCH_TEMP_FILES}" wait printf "End Compute each files detail size.\n" printf "Please Check below files..\n" cat ${SEARCH_FILES} | sort -rn rm "${SEARCH_DIR_LIST}" "${SEARCH_TEMP_FILES}" printf "Script execute end!\n"
