Linux FIX: Когато изтрити файлове заемат дисково пространство

Здравейте, колеги,
Колко от вас са се сблъсквали със следния сценарий? Получавате предупреждение за пълен диск, но когато проверите с df -h, изведената употреба е огромна. Обаче, когато анализирате папките с du -sh, сборът не съвпада. Това е класическа загадка в Linux света, и отговорът често се крие в изтрити файлове, които все още се държат от отворени процеси.
Този проблем е един от най-подвеждащите и често срещани проблеми, които администраторите срещат. Разбирането му не само оправя незабавния ви проблем, но и задълбочава познанията ви за това как Linux управлява файловете и паметта. В тази статия ще разгледаме в детайли защо това се случва и как да го оправим.
Защо това се случва? Механиката на изтриването в Linux
За да разберем проблема, първо трябва да си припомним едно фундаментално отличие в Linux: връзката между име на файл и самия файл.
- Имената на файлове и inodes: В Linux файловата система съхранява данните в структури, наречени
inodes. Inode съдържа метаданни за файла (размер, разрешения, собственик) и указатели към действителните данни на диска. Самото име на файла е просто запис в директория, която сочи към конкретен inode. - Какво прави командата
rm: Когато изпълнитеrm myfile.txt, вие не изтривате самите данни на файла веднага. Вместо това, вие премахвате името на файла от директорията. Операционната система след това намалява „брояча на връзки“ (link count) в inode с единица. - Ключовият момент: Данните на диска се освобождават (т.е. пространството се връща за ползване) само когато броячът на връзки стане нула. Това е решаващо.
Сега, представете си следното: някоя програма отваря myfile.log за писане. След това, вие или скрипт изтривате този файл с rm myfile.log. За програмата обаче това не е проблем. Тя вече е отворила файла и има директен указател към неговия inode. Тя може спокойно да продължава да чете от него и да пише в него. Тъй като програмата все още държи отворен указател към inode, броячът на връзки не пада до нула. Следователно, дисковото пространство не е освободено.
Този файл, който вече няма име в никаква директория, но все още е отворен от процес, се нарича "изтрит, но все още отворен файл" (deleted but open file). Linux го съхранява, докато процесът, който го държи, не бъде прекратен или затвори файла.
Проста аналогия: Представете си, че файлът е стая в хотел, а името на файла е номерът на вратата. Процесът (програмата) е госта, който е наел стаята. Командата rm е еквивалентна на премахване на номера от вратата. Но ако гостът все още е вътре в стаята (файлът е отворен), стаята все още е заета. Управителят на хотела (Linux) няма да я почисти и да я освободи за нов гост, докато настоящият гост не напусне.
Как да открием виновника: Използване на lsof
Най-мощният инструмент за разкриване на тези "зомби" файлове е lsof (List Open Files). Той извежда списък на всички файлове, отворени от всички процеси в системата.
За да намерите конкретно изтрити файлове, които все още се държат от процеси, използвайте следната команда:
sudo lsof +L1Нека разбием командата:
sudo: Изисква се, за да видите файлове, отворени от всички процеси, включително тези, собственост на root.lsof: Самият инструмент.+L1: Това е филтър, който казва наlsofда покаже само файлове с "link count" по-малък от 1. Тъй като изтрити файлове нямат имена (link count = 0), те ще бъдат показани.
Пример за изход:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
java 1234 appuser 1w REG 8,16 5.2G 0 123456 /var/log/myapp.log (deleted)
nginx 5678 www-data 5w REG 8,16 1.8G 0 789012 /var/log/nginx/access.log (deleted)Какво виждаме тук:
COMMAND: Името на командата, която държи файла отворен (java, nginx).PID: Идентификаторът на процеса. Това е изключително важно за следващата стъпка.USER: Потребителят, под чието име работи процесът.FD: File Descriptor – как процесът се отнася към файла (1w е стандартен изход за писане, 5w е друг файлов дескриптор за писане).TYPE: Типът на файла (REG означава обикновен файл).SIZE/OFF: Размерът на файла. Това е количеството дисково пространство, което все още е заето!NLINK: Броячът на връзки. 0 е индикаторът за изтрит файл.NAME: Името на файла, следвано от думата (deleted).
Ако искате да се фокусирате върху конкретен диск или раздел (например този, който е почти пълен, /var), можете да използвате:
sudo lsof +L1 /varРешения: Как да си върнем обратно ценностното дисково пространство
След като идентифицирахме виновните процеси, има няколко начина да освободим пространството.
1. Рестартиране на процеса (Най-често срещано и безопасно решение)
Това е най-простият и най-безопасен метод. Ако рестартирате процеса (или услугата), който държи файла отворен, той ще затвори всички свои файлови дескриптори по време на изключването. Когато последният дескриптор, сочещ към inode, бъде затворен, Linux ще освободи дисковото пространство.
Използвайки примера по-горе с PID 1234:
# Ако знаете името на услугата:
sudo systemctl restart myapp-service
# Или, ако трябва да използвате PID:
sudo kill 1234
# След това стартирайте приложението/услугата отново по подходящия начин.Плюсове: Лесно и чисто.
Минуси: Кратка пауза в услугата. Уверете се, че това е приемливо за вашата система.
2. Затваряне на файловия дескриптор (За напреднали)
В някои критични производствени среди не можете да рестартирате целия процес. В този случай можете директно да затворите файловия дескриптор. Внимание: Това може да има неочаквани странични ефекти, ако процесът очаква, че файлът все още е отворен.
Linux предоставя лесен начин за това чрез /proc файловата система. За всеки процес с PID, има виртуална директория /proc/PID/fd/, която съдържа всички негови отворени файлови дескриптори.
За да затворите файловия дескриптор:
# Първо, намерете FD номера от изхода на lsof (колоната FD).
# В нашия пример за Java процеса, FD е '1w'. Числото е 1.
# След това изпълнете:
sudo bash -c "echo > /proc/1234/fd/1"ази команда пренасочва празен изход към файловия дескриптор номер 1, ефективно го "изпразва" и кара ядрото да го затвори. Пространството на диска трябва да бъде освободено веднага.
Предупреждение: Ако процесът активно пише в този файлов дескриптор, това може да причини грешки. Използвайте този метод само ако разбирате последствията.
3. Изчистване на файловете (По-добрият път напред)
Рестартирането на процеса решава незабавния проблем, но не предотвратява повторението му. Най-доброто решение е да конфигурирате правилно вашите приложения и услуги.
- Лог ротация: Повечето приложения, които пишат логове (като Apache, Nginx, Java приложения с logback/log4j), поддържат механизъм за "ротация на логове". Това означава, че те автоматично ще преименуват текущия лог файл (напр.
app.log->app.log.1) и ще създадат новapp.logна определено време или при определен размер. - Използвайте
logrotate: Това е стандартната помощна програма в Linux за управление на логове. Конфигурирайте я да ротира логовете на вашето приложение и, най-важното, да изпраща сигнал на процеса да преотвори своите лог файлове. Обикновено това се постига с директиватаcopytruncateили със сигнал (катоpostrotateскрипт). Това гарантира, че старите, ротирани файлове ще бъдат напълно изтрити и освободени, тъй като процесът вече не ги държи отворени.
Примерна конфигурация на /etc/logrotate.d/myapp:
/var/log/myapp.log {
daily
rotate 7
compress
delaycompress
copytruncate
missingok
}Директивата copytruncate е особено полезна за приложения, които не могат да бъдат сигнализирани да преотворят файловете си. Тя копира текущия лог файл и след това го изпразва (truncate), позволявайки на процеса да продължи да пише в същия файлов дескриптор, но вече в празен файл.
Често срещани сценарии и как да ги предотвратите
- Лог файлове на приложения: Това е най-честият виновник. Java приложения (Tomcat, Elasticsearch), уеб сървъри (Nginx, Apache) и системни демони могат да пишат в логове години наред, без да бъдат ротирани. Решение: Винаги конфигурирайте
logrotateза вашите приложения. - Временни файлове: Някои програми създават временни файлове, които изтриват веднага след отваряне, но продължават да ги използват. Решение: Това обикновено е правилно поведение, но ако програмата "зависне", тези файлове могат да останат. Проследяването с
lsofбързо ги идентифицира. - Бази данни: Някои системи за управление на бази данни могат да имат подобно поведение. Винаги използвайте предоставените от тях инструменти за поддръжка (като
VACUUMв PostgreSQL) и не изтривайте файлове на базата данни ръчно.
Заключение
Проблемът с изтритите, но все още отворени файлове, е фундаментален аспект от работата на Linux. Разбирането на връзката между имена на файлове, inodes и файлови дескриптори е от съществено значение за всеки, който сериозно се занимава с администриране на системи.
Вашият ментален модел за отстраняване на неизправности трябва да включва тази стъпка:
df -hпоказва пълен диск.du -sh /път/показва много по-малко използвано пространство.- След това веднага изпълнете
sudo lsof +L1, за да намерите изтрити файлове. - Рестартирайте услугата или, за постоянно решение, конфигурирайте правилно ротацията на логове.
Надявам се, че тази статия е изчистила един често срещан и объркващ проблем. Споделете вашите собствени истории и въпроси в коментарите по-долу! Какво най-голямо "зомби" файлове.
Благодарим ви за прочитането на статията! Ако намерихте информацията за полезна, можете да дарите посредством бутоните по-долу:
Donate ☕️ Дарете с PayPalDonate 💳 Дарете с Revolut








Един коментар
Коментарите са изключени.