硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
前言
最近线上服务经常出现一些奇奇怪怪的问题,比如网页上的静态资源加载不出来,或者请求后端莫名报错,又或者 Redis 报错…
当我 SSH 登录到服务器上时,更不对劲了,敲个命令都卡顿…
如果是以前没经验,或许会以为遇到了疑难杂症,但作为多年的 Linux 用户,我已经知道了这种种异常的背后是「存储空间已满」在作祟!
那么问题就来到了「硬盘空间去哪儿了?」
排查
先用 df 看个大概
首先是最常用的命令
df -h
先来看看各个磁盘和挂载点的情况
在我的服务器上执行这个命令之后发现,根目录的可用空间已经只剩下几百 KB 了…
再用 du 看具体
使用 du 命令可以查看各个子目录占用的空间,然后再结合 sort 命令排个序
sudo du -h --max-depth=1 / | sort -hr
参数说明:
- 因为要直接统计根目录,所以需要有 root 权限
--max-depth=1:仅显示当前目录及其下一级子目录的占用情况。sort -hr:按照大小进行降序排列。
查看目录的总占用空间:
du -sh /
更好的工具
前面的 du 命令,还是没那么好用,主要是列出来的数据太多了。
这次我用上了 ncdu 工具
ncdu是一个更加用户友好的磁盘使用分析工具,支持交互式界面。
不过很多发行版没有内置,需要先安装:
sudo apt install ncdu
使用 ncdu 分析根目录占用
sudo ncdu -x /
使用 -x 参数可以限制扫描范围为当前文件系统,不跨越挂载点。因为根目录下有很多其他硬盘的挂载点,根据前面使用 df 命令的分析,是主硬盘满了,所以我只要看主硬盘的就行。
ncdu 启动之后会扫描各个文件的存储空间,然后进入一个交互式界面,可以很直观的看到各个目录的占用空间大小,从大到小排序。
罪魁祸首
在 ncdu 里可以很直观看到 /var/lib/docker 这个目录占用了 70% 以上的存储空间,妥妥的答辩啊!
使用 du 分析
sudo du -h --max-depth=1 /var/lib/docker | sort -hr
之后大概的占用情况是这样(只是例子,不是真实数据)
10G /var/lib/docker/overlay2
5G /var/lib/docker/volumes
1G /var/lib/docker/containers
500M /var/lib/docker/images
基本就是 docker 的镜像、容器日志、卷之类的把硬盘吃掉了
清理 Docker 的未使用资源
找到了问题,那就好办了
首先把没用的 docker 容器停掉
然后执行一下 docker 提供的一些清理命令。
清理未使用的资源(镜像、容器、卷和网络)
Docker 提供了 docker system prune 命令,能清理未使用的资源。
docker system prune -a
-a:删除所有未使用的镜像(包括没有关联到容器的镜像)。- 注意:这个命令不会删除被正在运行的容器依赖的资源,请小心操作。
仅清理未使用的卷
如果是 /var/lib/docker/volumes 占用空间较多:
docker volume prune
仅清理未使用的网络
如果是 /var/lib/docker/network 占用较多:
docker network prune
删除不需要的容器、镜像和卷
删除未运行的容器
docker container prune
删除无用的镜像
docker image prune -a
删除无用的卷
docker volume prune
清理旧的镜像和未使用的标签
如果在使用大量镜像,很多旧版本可能已经没有用了。
列出镜像按大小排序
docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | sort -k2 -h
删除指定镜像
docker rmi <image-id>
啥玩意这么大?
在分析存储空间的占用过程中,我还发现有个文件特别离谱,下面这个文件,500多个G…
/var/lib/docker/containers/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df-json.log
找出拉屎的容器
来看看是哪个容器拉的屎。
日志文件的路径中包含了容器的 ID:e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df
来找一下是哪个容器:
docker ps | grep e4b5a99b429a
在容器列表中找不到该容器,可能它已经被停止或删除了。在这种情况下,可以使用 docker inspect 检查具体信息:
docker inspect e4b5a99b429a
分析日志内容
可以通过 tail 或 less 查看日志内容,检查是否有异常输出:
sudo tail -n 50 /var/lib/docker/containers/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df-json.log
日志的具体内容我就不贴了,看起来应该没啥问题,就是运行久了,日积月累…
处理这个问题的方法,见下一小节。
清理 docker 日志文件
如果 /var/lib/docker/containers 占用大量空间,可能是容器日志文件过大。
查看日志文件
每个容器的日志存储在 /var/lib/docker/containers/<container-id>/<container-id>-json.log。
使用以下命令找到最大的日志文件:
sudo find /var/lib/docker/containers/ -type f -name "*.log" -exec du -h {} + | sort -hr | head -n 10
手动清理日志
清空一个特定容器的日志文件:
sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log
设置日志文件大小限制
在 Docker 的配置文件中限制日志大小(推荐):
编辑 Docker 配置文件(通常是
/etc/docker/daemon.json):sudo nano /etc/docker/daemon.json
添加或修改以下配置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
max-size:单个日志文件最大 10 MB。max-file:保留 3 个日志文件。
重新加载 Docker:
sudo systemctl restart docker
迁移 /var/lib/docker 到新磁盘
可以将 /var/lib/docker 挂载到其他磁盘,从而缓解当前磁盘的存储压力。这是一个常见的做法,尤其在有多块磁盘的情况下。
方法一:直接迁移 /var/lib/docker 到新磁盘
停止 Docker 服务
在迁移数据之前,需要先停止 Docker 服务:
sudo systemctl stop docker
移动 /var/lib/docker 到新位置
假设新磁盘挂载在 /mnt/new-disk,执行以下命令:
sudo mv /var/lib/docker /mnt/new-disk/docker
创建软链接
将新的路径链接回 /var/lib/docker,让 Docker 继续按默认路径工作:
sudo ln -s /mnt/new-disk/docker /var/lib/docker
启动 Docker 服务
sudo systemctl start docker
验证
运行以下命令确保 Docker 正常工作:
docker info
方法二:修改 Docker 配置文件,指定新存储位置
停止 Docker 服务
sudo systemctl stop docker
移动 /var/lib/docker 到新磁盘
将现有数据迁移到新磁盘挂载点。例如,新磁盘挂载在 /mnt/new-disk:
sudo mv /var/lib/docker /mnt/new-disk/docker
修改 Docker 配置
编辑 Docker 的配置文件(通常是 /etc/docker/daemon.json),指定新的存储路径:
sudo nano /etc/docker/daemon.json
添加或修改以下内容:
{
"data-root": "/mnt/new-disk/docker"
}
启动 Docker 服务
sudo systemctl start docker
验证
再次检查 Docker 是否正常运行:
docker info | grep "Docker Root Dir"
你应该能看到新的路径(如 /mnt/new-disk/docker)。
方法三:直接挂载新磁盘到 /var/lib/docker
如果想直接将新磁盘作为 /var/lib/docker 的挂载点,可以使用以下方法
格式化新磁盘
假设新磁盘为 /dev/sdb1,先格式化并创建文件系统(如 ext4):
sudo mkfs.ext4 /dev/sdb1
挂载新磁盘
将新磁盘挂载到 /var/lib/docker:
sudo mount /dev/sdb1 /var/lib/docker
迁移现有数据
如果 /var/lib/docker 目录下已有数据,需要先复制到新磁盘:
sudo rsync -a /var/lib/docker/ /mnt/new-disk/
然后再将新磁盘挂载回 /var/lib/docker。
修改 /etc/fstab 确保开机自动挂载
编辑 /etc/fstab 文件,添加一行挂载配置:
/dev/sdb1 /var/lib/docker ext4 defaults 0 2
注意事项
数据迁移风险:在迁移或重建
/var/lib/docker时,务必备份重要数据(如持久卷数据)。权限问题:确保新目录的权限与原始目录一致:
sudo chown -R root:root /mnt/new-disk/docker
检查挂载点:确保新磁盘挂载成功,并设置自动挂载,避免系统重启后路径丢失。
通过以上方法,可以成功将 /var/lib/docker 挂载到其他磁盘,缓解存储压力并优化存储布局。
重建 /var/lib/docker
如果清理后空间仍然不足,可以重建 Docker 的存储目录(会删除所有容器、镜像和数据)
停止 Docker 服务:
sudo systemctl stop docker
备份现有 Docker 数据(可选):
sudo mv /var/lib/docker /var/lib/docker.bak
创建一个新的空目录:
sudo mkdir /var/lib/docker
启动 Docker 服务:
sudo systemctl start docker
总结
在这次 Linux 服务器硬盘空间消失问题的排查过程中,我经历了一次完整的存储分析和优化实战。
关键步骤概括:
- 初步排查存储占用情况
- 使用
du和ncdu等工具,快速定位占用空间较大的目录。 - 发现
/var/lib/docker目录占用了大量存储空间。
- 使用
- 深入定位具体问题
- 找到具体的容器日志文件路径,通过容器 ID 确认了是哪个容器产生了大量日志。
- 使用
docker inspect和docker logs,进一步分析日志内容。
- 解决问题
- 清空了过大的容器日志文件,通过
truncate命令立即释放空间。 - 修改 Docker 配置文件(
daemon.json)限制了日志文件的大小,避免类似问题再次发生。
- 清空了过大的容器日志文件,通过
- 验证与优化
- 重启 Docker 服务后,验证了服务正常运行。
- 使用
docker system prune清理了无用资源,并规划了日志管理策略。
个人收获与思考:
这次问题的解决让我深刻体会到以下几点:
- 系统监控的重要性:及时监控存储使用情况,可以避免问题扩大化。
- 日志管理最佳实践:过度增长的日志文件是常见的存储占用原因,必须设置合理的日志大小限制。
- 工具的高效使用:
du、ncdu和 Docker 命令等工具在排查问题中大大提升了效率。 - 日常维护习惯:定期清理无用的容器资源(例如停止的容器、未使用的镜像),可以保持系统健康运行。
这次实践不仅解决了磁盘空间问题,也让我对 Linux 系统管理和 Docker 的运维有了更深的理解。在未来的运维工作中,我将更加注重系统的监控与优化,提前预防类似问题的发生。
硬盘空间消失之谜:Linux 服务器存储排查与优化全过程的更多相关文章
- [转载]Linux服务器性能评估与优化
转载自:Linux服务器性能评估与优化 一.影响Linux服务器性能的因素 1. 操作系统级 CPU 内存 磁盘I/O带宽 网络I/O带宽 2. 程序应用级 二.系统性能评估标准 影响性 ...
- Linux服务器性能评估与优化
一.影响务器性能因素 影响企业生产环境Linux服务器性能的因素有很多,一般分为两大类,分别为操作系统层级和应用程序级别.如下为各级别影响性能的具体项及性能评估的标准: (1)操作系统级别 内存: C ...
- EMC存储同时分配空间到两台LINUX服务器路径不一致导致双机盘符大小不一致
操作系统:Centos linux6.6 当我们从EMC存储上划分空间同时分配给两台或者多台服务器上时,有的时候会出现在服务器上所生成的磁盘路径是不一致的,这样就会导致盘符名称不一致或者是盘符对应的大 ...
- 磁盘大保健 保持你的Linux服务器存储健康
df du -sh *| sort -nr du -h --max-depth=1 / du -h --max-depth=1 /* find . -type f -size +1000000k 查找 ...
- Linux服务器性能评估与优化(一)
网络内容总结(感谢原创) 1.前言简介 一.影响Linux服务器性能的因素 1. 操作系统级 性能调优是找出系统瓶颈并消除这些瓶颈的过程. 很多系统管理员认为性能调优仅仅是调整一下 ...
- Linux服务器性能评估与优化--转
http://www.itlearner.com/article/4553 一.影响Linux服务器性能的因素 1. 操作系统级 Ø CPU Ø 内存 Ø 磁盘I/ ...
- Linux服务器性能分析与优化
影响服务器性能的因素: CPU :大部分cpu在同一时间只能运行一个线程,超线程的处理器可以在同一时间处理多个线程,因此可以利用超线程特性提高系统性能. 在linux系统下,只有运行SMP内核才能支持 ...
- Linux服务器性能评估与优化(二)
网络内容总结(感谢原创) 1.Linux内核参数优化 内核参数是用户和系统内核之间交互的一个接口,通过这个接口,用户可以在系统运行的同时动态更新内核配置,而这些内核参数是通过Linux Proc文件系 ...
- Linux服务器沦陷为肉鸡的全过程实录
1 从防火墙瘫痪说起 2015年3月10日,还没到公司就被电话告知办公室无法正常连接互联网了,网速非常慢,无法正常浏览网页.急急忙忙感到公司,开始查找问题. 首先排除了交换机故障,因为内部局域网正常. ...
- linux服务器问题排查:w命令卡住
基本情况 系统: ubuntu16.04 症状: who命令可以用,w命令用不了 sudo iotop命令会卡住,黑屏 nvidia-smi命令和nvl命令都用不了,卡住 排查步骤 strace ps ...
随机推荐
- 浅谈 K-D Tree 及其进阶应用
前言 \(\text{K-D Tree (K-Dimension Tree)}\) 是一种可以有效处理高维信息的数据结构. 在一般信息学竞赛题目中 \(k = 2\),此时它又称 \(\text{2- ...
- Win11使用Translucent TB设置Windows导航栏透明失败解决方案
Win11使用Translucent TB设置Windows导航栏透明失败解决方案 Translucent TB下载方式:直接在Windows自带的Microsoft应用商店里面搜索下载就可以了 1. ...
- 基础控件(ListView,RecyclerView,单位和尺寸,ViewPager,ViewPager2)
ListView list_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLa ...
- ES检索服务搜索结果高亮
一.前言 在实际使用中搜索结果中的关键词前端通常会以特殊形式展示,比如标记为红色使人一目了然.我们可以通过 ES 提供的高亮功能实现此效果. 二.代码实现 前文查询是通过一个继承 Elasticsea ...
- 霍夫(Hough)直线变换(直线检测)
0 原理 霍夫变换在检测各种形状的的技术中非常流行,如果你要检测的形状可以用数学表达式写出,你就可以是使用霍夫变换检测它.及时要检测的形状存在一点破坏或者扭曲也可以使用.我们下面就看看如何使用霍夫变换 ...
- 数据分析(matplotlib pyplot)
文章目录 1.导入pyplot 库 2.绘出直线图 3.绘出实心点 4.绘出折线图 5.绘制正余弦函数 Pyplot 是 Matplotlib 的子库,提供了和 MATLAB 类似的绘图 API. P ...
- 物理实验霍尔效应判断P/N型半导体笔记
最近这不要物理实验期末考试了嘛,我火速抄起实验书准备复习. 复习到霍尔效应判断P/N型半导体这一部分时很惊奇地发现网上一会儿还搜不出个明了的总结,也有很多误导性的判断方法.Σ( ° △ °|||)︴ ...
- 人形机器人是未来?6只手臂加AI模型,异形机器人重塑种植业。
图源:reddit user IlustriousTea 近日,一则视频在媒体上引起了人们的讨论.国外一处苹果园里,机械嗡鸣声中,六只机械手熟练且快速地采摘成熟的苹果. 这是2018年于美国加利福尼亚 ...
- 每日学学Java开发规范,常量定义(附阿里巴巴Java开发手册(终极版))
前言 每次去不同的公司,码不同的代码,适应不同的规范,经常被老大教育规范问题,我都有点走火入魔的感觉,还是要去看看阿里巴巴Java开发规范,从中熟悉一下,纠正自己,码出高效,码出质量. 想细看的可以去 ...
- php 对二维数组按照汉字首字母排序
1 /** 2 * 取汉字的第一个字的首字母 3 * @param type $str 4 * @return string|null 5 */ 6 function _getFirstCharter ...