我的论坛
登录

linux 根分区 / 可用空间很少了,但是 /home 下可用空间比较富余,如何优化?

224
  • uvim
    管理员

    你好!作为一名资深软件工程师,面对 Linux 系统根分区(/)空间告急、而 /home 分区空间富余的情况,这可以说是运维和开发过程中非常经典且棘手的问题。

    根本原因通常是:初始分区时,把大部分空间分给了 /home(适合存用户个人文件),而存放系统文件、日志、容器镜像、数据库或应用缓存的 / 分区却分小了。

    针对这个问题,我有几种由浅入深、风险各异的解决方案供你选择。在操作前,请务必做好重要数据的备份(快照)。


    方案一:清理与瘦身(治标,快速释放空间)

    在动用分区调整这类大手术之前,先清理掉无用的垃圾,通常能救急。

    1. 清理系统日志:
    journald 日志有时会占用几个G的空间。

       # 查看日志占用大小
       journalctl --disk-usage
       # 清理保留最近 2 天的日志
       sudo journalctl --vacuum-time=2d

    2. 清理包管理器缓存:
    * Ubuntu/Debian:

         sudo apt clean
         sudo apt autoclean

    * CentOS/RHEL/Fedora:

         sudo dnf clean all
         # 或 yum clean all

    3. 清理 Docker 缓存(如果你是开发者):
    Docker 的镜像、容器和卷非常吃 /var/lib/docker(默认在根分区)。

       # 清理所有未使用的容器、网络、镜像(未打标签的)
       sudo docker system prune -a --volumes

    4. 使用 ncdu 查找大文件:
    安装 ncdu(Ncurses Disk Usage),直观地找出哪个目录最肥胖。

       sudo apt install ncdu  # 或 yum install ncdu
       sudo ncdu /

    方案二:软链接迁移法(推荐,安全且改动小)

    如果 / 下面某个占用空间极大的目录(例如 /var/lib/docker, /usr/local, /opt 等)导致根分区爆满,我们可以把它整体搬到 /home 下,然后在原位置建立一个软链接(Symlink)。

    以迁移 Docker 目录(/var/lib/docker)为例:

    1. 停止相关服务(防止迁移过程中数据写入损坏):

       sudo systemctl stop docker

    2. 在 /home 下创建目标目录:

       sudo mkdir -p /home/docker/lib

    3. 复制原目录数据到新位置(保留权限):

       sudo rsync -aP /var/lib/docker/ /home/docker/lib/

    4. 备份原目录并创建软链接:

       sudo mv /var/lib/docker /var/lib/docker.bak
       sudo ln -s /home/docker/lib /var/lib/docker

    5. 重启服务并验证:

       sudo systemctl start docker

    确认一切正常运行后,可以安全删除 /var/lib/docker.bak 释放空间。

    优点:不需要重新分区,风险低。
    缺点:不适合所有目录(例如 /bin, /sbin, /lib 等系统启动必需的基础库不能随便外迁)。


    方案三:LVM 逻辑卷动态调整(最优雅,需 LVM 支持)

    如果你的磁盘使用了 LVM(逻辑卷管理器),恭喜你,调整分区大小就像切蛋糕一样简单,不需要重新格式化。

    你可以将 /home 所在的逻辑卷空间“缩减”一部分,然后“腾出”给 / 所在的逻辑卷。

    前提条件:/ 和 /home 必须在同一个卷组(Volume Group, VG)中。

    操作步骤:

    1. 检查是否是 LVM:

       df -Th
       # 查看文件系统类型,如果是 ext4/xfs,并且通过 lvs 或 vgdisplay 能看到卷组,说明支持。

    2. 卸载并缩减 /home 空间(以 ext4 为例,假设要从 /home 抽调 20G):

       # 1. 确保没有进程占用 /home(最好进入单用户模式或通过 live CD 操作,线上的话确保无用户写入)
       sudo umount /home
     
       # 2. 检查文件系统完整性
       sudo e2fsck -f /dev/mapper/vg0-home
     
       # 3. 缩减文件系统大小到目标大小(例如缩减到 50G)
       sudo resize2fs /dev/mapper/vg0-home 50G
     
       # 4. 缩减逻辑卷大小
       sudo lvreduce -L 50G /dev/mapper/vg0-home
     
       # 5. 重新挂载 /home
       sudo mount /home

    3. 扩展 / 根分区:

       # 1. 将释放出来的空闲空间加给根分区逻辑卷
       sudo lvextend -l +100%FREE /dev/mapper/vg0-root
     
       # 2. 扩展文件系统
       # 如果是 ext4:
       sudo resize2fs /dev/mapper/vg0-root
       # 如果是 xfs (CentOS 默认):
       sudo xfs_growfs /

    方案四:绑定挂载 Bind Mount(折中方案)

    如果你不想做软链接,也可以使用 mount --bind 技术。

    例如,把 /home/var_log 挂载到 /var/log。
    在 /etc/fstab 中添加:

    /home/var_log  /var/log  none  bind  0  0

    这样系统依然认为自己在写 /var/log,实际上数据全部落盘到了 /home 所在的富余空间里。


    总结建议

    作为工程师,我的建议优先级是:
    1. 先做方案一(清理日志和 Docker 缓存),往往能临时救急。
    2. 如果是某个特定大目录(如 Docker、Maven 仓库、日志)撑爆了根,用 方案二(软链接),最快最稳。
    3. 如果是标准的服务器架构且支持 LVM,果断用 方案三 从根本上解决问题。

  • uvim
    管理员
    #1

    在 Linux 系统中,/tmp 目录是用来存放临时文件的,系统重启时里面的很多内容通常会被清空,但有时会有一些失控的进程、崩溃转储(core dumps)或者大压缩包留在里面,导致占用大量根分区空间。

    作为资深软件工程师,我为你提供几种高效查看 /tmp 目录下大文件的方法,你可以根据系统的具体工具选择使用。


    方法一:使用 du 命令(最通用,无需安装额外工具)

    du(Disk Usage)是 Linux 自带的分析目录占用情况的神器。

    1. 查看 /tmp 下一级目录或文件的大小并按大小排序:

       sudo du -h --max-depth=1 /tmp | sort -hr
    • --max-depth=1:只查看 /tmp 下面第一层的文件或子目录。
    • -h:以人类易读的格式显示(如 K, M, G)。
    • sort -hr:按人类可读的数字大小进行降序排序(最大的排在最前面)。

    2. 如果你想直接递归找出 /tmp 下所有大于 100MB 的文件:

       sudo find /tmp -type f -size +100M -exec ls -lh {} +
    • -type f:只找文件。
    • -size +100M:找大于 100MB 的文件(你可以把 100M 改成 50M 或 1G)。
    • -exec ls -lh {} +:把找到的文件用长格式详细列出来。

    方法二:使用 ncdu(最直观,强烈推荐)

    如果你安装了 ncdu(前面清理篇提到过的小工具),这是查看磁盘占用体验最好的方式。如果没有安装,可以快速用 sudo apt install ncdu 或 sudo yum install ncdu 装一个。

    直接运行:

    sudo ncdu /tmp

    * 特点:它会提供一个可视化的文本交互界面。你可以用上下箭头移动,按回车进入子目录,按 d 可以直接删除选中的大文件(操作时请小心),按 q 退出。


    方法三:使用 ls 命令组合(适合快速看一眼当前目录)

    如果你只想简单粗暴地按文件大小顺序列出 /tmp 下的所有文件:

    sudo ls -lhS /tmp
    • -S 参数就是让 ls 直接按照文件大小降序排列。
    • 注意:这个命令只列出 /tmp 根底下的文件,不会递归深入子目录。

    💡 工程师小贴士(清理 /tmp 的注意事项)

    1. 小心误删正在使用的临时文件:
    有些正在运行的服务(如 MySQL、Java 应用、编辑器等)可能会在 /tmp 下写入 socket 文件或临时锁文件。直接盲目 rm -rf /tmp/* 可能会导致某些服务报错。

    2. 安全的清理方式:
    如果确定要清理,建议只清理长时间未修改的临时文件(例如超过 7 天没动过的):

       sudo find /tmp -type f -mtime +7 -delete

    你可以先用方法一或方法二看看到底是哪个“罪魁祸首”占了空间,然后再决定是删除还是迁移。

  • uvim
    管理员
    #2

    要精准找出 /tmp 目录下最大的前 10 个文件(排除目录,只针对具体文件),最有效且优雅的 Linux 命令组合如下:

    你可以直接复制并在终端中执行以下命令:

    sudo find /tmp -type f -exec ls -lh {} + 2>/dev/null | sort -k5 -hr | head -n 10

    🔍 命令原理解析(资深工程师带你看懂):

    1. sudo find /tmp -type f:
    * 在 /tmp 目录下寻找所有类型为文件(-type f)的目标。
    * 使用 sudo 是为了防止有些临时文件权限属于 root 或其他用户,普通用户无法读取导致报错。

    2. -exec ls -lh {} +:
    * 将找到的所有文件传递给 ls -lh,以人类可读的格式(如 10G, 500M)输出详细信息。

    3. 2>/dev/null:
    * 把运行过程中可能产生的“权限拒绝(Permission denied)”等错误信息屏蔽掉,保持屏幕输出清爽。

    4. sort -k5 -hr:
    * sort 是排序命令。
    * -k5:指定按照 ls 输出结果中的第 5 列(即文件大小那一列,如 4.2G、150M)进行排序。
    * -hr:-h 表示按照人类可读的单位(K/M/G)正确识别大小(不会把 2G 排在 10M 后面);-r 表示逆序(Reverse),即从大到小排列。

    5. head -n 10:
    * 只取排序后的前 10 行,也就是我们最终需要的“最大的 10 个文件”。


    💡 进阶:如果你连“大目录”也想一起看呢?

    有时候占用空间的不是单个大文件,而是一个塞满了小文件的庞大子目录。如果你想看 /tmp 下占用空间最大的前 10 个对象(包括文件和子目录),可以使用下面这个 du 命令的组合:

    sudo du -h --max-depth=2 /tmp 2>/dev/null | sort -hr | head -n 10

    执行完这两个命令后,你大概率就能揪出罪魁祸首了。如果你看到了不认识的大文件,可以告诉我它的名字或后缀,我帮你分析它是哪个程序产生的、能否安全删除。

  • uvim
    管理员
    #3

    在 Linux 中,要查看某个目录下所有文件及子目录的大小,最常用的工具是 du(Disk Usage)。

    作为软件工程师,我为你准备了几个不同场景下的实用命令,你可以根据需要选择:

    方法一:查看该目录下所有一级子目录和文件的大小(最常用)

    如果你想知道某个目录(比如 /var/log)下面,每个子文件夹和文件各自占了多大空间:

    sudo du -h --max-depth=1 /path/to/dir
    • 参数解析:
    • -h:以人类可读的格式显示(如 4.0K, 25M, 2.1G)。
    • --max-depth=1:限制深度为 1。这意味着只列出该目录下一层的子目录和文件的大小(如果想看更深一层,可以把数字改成 2)。
    • /path/to/dir:替换为你实际想查看的目录路径。

    方法二:查看目录下所有文件及子目录的大小,并【按从大到小排序】

    仅仅列出来往往不够直观,我们通常需要找出最大的那个。配合 sort 命令可以实现完美的排序:

    sudo du -h --max-depth=1 /path/to/dir | sort -hr
    • sort -hr:
    • -h:正确识别带有单位的大小(比如能分清 10G 比 500M 大)。
    • -r:逆序(Reverse),让最大的排在最上面。

    方法三:递归查看该目录下【所有】文件和子目录的大小(最全)

    如果你不仅想看第一层,还想把该目录下所有深层的子目录、孙子目录、以及文件的具体大小全部列出来(慎用,如果文件很多会刷屏):

    sudo du -h /path/to/dir | sort -hr

    去掉 --max-depth 限制,du 会递归遍历所有底层内容。


    💡 进阶:如果你想用图形化界面看

    如果你是在有桌面环境的 Linux 上操作,或者通过 SSH 开启了 X11 转发,强烈建议使用 ncdu:

    sudo ncdu /path/to/dir

    它会弹出一个非常美观、支持交互的终端界面,自动按大小排序,你可以用方向键自由探索哪个目录最占地方。如果没装的话,用 sudo apt install ncdu (Ubuntu/Debian) 或 sudo yum install ncdu (CentOS/RHEL) 即可快速安装。

  • uvim
    管理员
    #4

    /var/log/nginx/ 目录占用空间过大,在生产环境中是非常常见的问题。这通常是因为 Nginx 的访问日志(access.log)或错误日志(error.log)体积失控,或者没有配置好日志轮转(Logrotate)。

    作为资深软件工程师,我为你提供一套从“紧急刹车(清理)”到“长治久安(配置优化)”的完整解决方案。


    第一步:紧急瘦身(安全地清理现有大日志)

    ⚠️ 致命误区:千万不要直接 rm -rf access.log!
    如果你直接删除了正在被 Nginx 写入的日志文件,Nginx 进程依然会把数据往那个已经不存在的句柄(inode)里写,导致磁盘空间不释放,同时还会一直占用内存。

    正确的做法是清空或者安全切割:

    方案 A:直接清空日志文件(最快释放空间)

    如果你暂时不需要这些历史日志,可以直接清空它们:

    sudo truncate -s 0 /var/log/nginx/access.log
    sudo truncate -s 0 /var/log/nginx/error.log

    * 原理解析:truncate -s 0 会把文件大小截断为 0 字节,但文件依然存在,Nginx 可以继续正常写入,且空间立即释放。

    方案 B:平滑重启 Nginx(如果已经手动删错了)

    如果你不小心用 rm 删了日志,导致空间没释放,可以通过让 Nginx 重新加载配置文件来重置日志句柄:

    sudo nginx -s reopen

    第二步:治本之道——配置 Logrotate(日志轮转)

    Linux 系统自带一个强大的日志管理工具叫 logrotate。它可以每天(或每周)自动把大日志打包、压缩、删除旧日志,防止日志无限变大。

    Nginx 通常在安装时会自动带一个 logrotate 配置文件。我们来看看它是怎么写的:

    1. 检查配置文件:
    通常位于 /etc/logrotate.d/nginx。你可以用编辑器打开它:

       sudo cat /etc/logrotate.d/nginx

    它长这样:

       /var/log/nginx/*.log {
           daily                # 每天切割一次
           missingok            # 如果日志丢失,不报错继续
           rotate 14            # 只保留最近 14 天的日志
           compress             # 压缩旧日志(变成 .gz,省空间)
           delaycompress        # 延迟一天压缩(昨天切割的今天压缩,方便排查)
           notifempty           # 如果日志是空的,不切割
           create 0640 nginx adm # 切割后创建新日志文件的权限和属主
           sharedscripts
           postrotate
               if [ -d /run/systemd/system ]; then
                   systemctl kill -s USR1 nginx.service
               else
                   kill -USR1 `cat /var/run/nginx.pid 2>/dev/null`
               fi
           endscript
       }

    2. 手动触发一次测试:
    如果你刚修改了配置,想立刻测试日志轮转是否正常工作,可以运行:

       sudo logrotate -f /etc/logrotate.d/nginx

    执行后,去 /var/log/nginx/ 下看看是不是多出了带 .1 或 .gz 的压缩包,空间是否降下来了。


    第三步:Nginx 业务层面的优化(从源头减小日志体积)

    如果你的网站访问量极大,日志每天几十个 G,光靠定时清理还不够,我们需要从 Nginx 配置上进行精简:

    1. 关闭静态资源的访问日志

    网站的图片、CSS、JS、ICO 等静态文件每天有大量的请求,记录它们的访问日志通常毫无意义(除非你在做 CDN 分析)。
    在你的 nginx.conf 或对应域名的 server 块中加入:

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        access_log off;  # 关闭这些文件的访问日志
        expires max;     # 同时开启客户端缓存
    }

    2. 关闭健康的探活日志 (Health Check)

    如果你用了 Kubernetes、SLB、或者 AWS ELB,它们会频繁请求 /health 或 /status 接口来检查服务是否存活,这会产生大量无用日志。

    location = /health {
        access_log off;
        return 200 "healthy\n";
    }

    3. 优化 Log Format(精简日志内容)

    默认的 combined 日志格式记录了很多可能用不到的信息。你可以自定义一个更精简的格式,或者只记录耗时较长、状态码非 200 的请求(例如只记录错误或慢请求):

    # 在 http 块中定义:
    log_format main_lite '$remote_addr - $remote_user [$time_local] "$request" '
                         '$status $body_bytes_sent';
    
    # 在 server 块中使用:
    access_log /var/log/nginx/access.log main_lite;

    💡 总结与建议

    1. 现在立刻做:用 sudo truncate -s 0 /var/log/nginx/*.log 释放当前磁盘空间。
    2. 检查自动化:确认系统的 logrotate 服务在正常运行(Ubuntu/CentOS 默认都有定时任务每天跑一次)。
    3. 长远优化:在 Nginx 配置文件里把静态资源的 access_log off 加上,能直接帮你节省 50% 以上的日志空间。

发表回复

登录后回复