今天,跑在阿里云ECS上的生产环境,突然间访问异常,接口各种报错,无奈公司没有专业的运维人员,只能硬着头皮解决一下。
先从表面看起,数据库首先报错
Caused by: org.postgresql.util.PSQLException: ERROR: could not extend file "base/16385/16587_fsm": No space left on device
建议:Check free disk space.
直观上看,设备没有可用空间,也就是磁盘满了。
进入服务器后台,执行
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.9G 0 7.9G 0% /dev
tmpfs 1.6G 3.5M 1.6G 1% /run
/dev/vda1 59G 56G 0 100% /
tmpfs 7.9G 4.0K 7.9G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 7.9G 0 7.9G 0% /sys/fs/cgroup
/dev/mapper/vg0-vol0 1000G 14G 937G 2% /data
tmpfs 1.6G 0 1.6G 0% /run/user/0
发现确实磁盘满了,而且满的很彻底。系统盘占用100%,估计什么服务都跑不动了。/dev/vda1 59G 56G 0 100% /
不过发现/dev/mapper/vg0-vol0 1000G 14G 937G 2% /data
,1000G只用了2%
阿里云ECS分为系统盘和数据盘,1000G的是数据盘
第一反应,应该是搭建的PG数据库的数据没有移到数据盘上。
参考如何将PostgreSQL数据目录移动到Ubuntu 16.04上的新位置
$ sudo -u postgres psql
postgres# SHOW data_directory; # 查看当前数据目录
data_directory
------------------------------
/var/lib/postgresql/9.5/main
(1 row)
postgres# \q; # 退出
# 为了确保数据的完整性,我们将在实际更改数据目录之前关闭PostgreSQL
$ sudo systemctl stop postgresql
# 确保关闭完成
$ sudo systemctl status postgresql
. . .
Jul 22 16:22:44 ubuntu-512mb-nyc1-01 systemd[1]: Stopped PostgreSQL RDBMS.
$ sudo rsync -av /var/lib/postgresql /data # /data为要迁移到的新目录
$ cd /data
$ ls
... postgresql
# 删除原数据目录
$ sudo rm -rf /var/lib/postgresql
# 将新数据目录链接到原数据目录
$ sudo ln -s /data/postgresql /var/lib/postgresql
# 重启Postgres数据库
$ sudo systemctl start postgresql
$ sudo systemctl status postgresql
完成以上步骤,即将postgre数据库数据目录移到了阿里云数据盘
以为OK了,执行
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.9G 0 7.9G 0% /dev
tmpfs 1.6G 3.5M 1.6G 1% /run
/dev/vda1 59G 56G 51M 100% /
tmpfs 7.9G 4.0K 7.9G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 7.9G 0 7.9G 0% /sys/fs/cgroup
/dev/mapper/vg0-vol0 1000G 14G 937G 2% /data
tmpfs 1.6G 0 1.6G 0% /run/user/0
纹丝未动。。。
猜测是存在大文件导致磁盘被占满
$ cd /
$ find . -type f -size +800M -print0 | xargs -0 du -h
5.6G ./var/log/syslog.1
6.7G ./var/log/syslog
...
$ rm ...
如果发现是log字眼的大文件,我们可以毫不留情的删掉,要是遇见一些不认识的,不要贸然删掉,一定要查清楚文件的作用,能删则删,千万不要不小心删库跑路。。。
删除完毕后,再次查看
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.9G 0 7.9G 0% /dev
tmpfs 1.6G 3.4M 1.6G 1% /run
/dev/vda1 59G 45G 12G 80% /
tmpfs 7.9G 4.0K 7.9G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 7.9G 0 7.9G 0% /sys/fs/cgroup
/dev/mapper/vg0-vol0 1000G 14G 936G 2% /data
tmpfs 1.6G 0 1.6G 0% /run/user/0
多出了12G。
这时候,服务应该可以恢复成功。但你马上会发现,磁盘又被占满,而这次,日志文件却不算大。
查看已经删除的文件,空间有没有释放,没有的话kill掉pid
使用rm删除文件的时候,虽然文件已经被删除,但是由于文件被其他进程占用,空间却没有释放
$ sudo lsof -n |grep deleted
java 17866 root 237r REG 253,1 163541 1709285 /tmp/tomcat.8250394289784312179.8080/work/Tomcat/localhost/ROOT/upload_c6db0c17_6e6a_4141_bfb6_ac1b2d8a3b0b_00000000.tmp (deleted)
...
$ sudo kill -9 17866
再次使用df -h
命令,磁盘使用率一下子减少了好多。
服务器系统盘被占满是非常可怕的!届时,一切服务都将变得不可用,业务系统也会莫名其妙多出奇怪的问题。所以,运维需要经常性的查看服务器磁盘占用情况,阿里云ECS用户,可以开启报警,及时发现问题,解决问题!
阿里云ECS提供了系统盘和数据盘,记住,例如Pg、Redis、Cassandra等容易占磁盘的服务,一定要将数据目录放在阿里云ECS提供的数据盘上。
/var/log
是系统日志目录,可以经常性的关注下,大容量日志尽早删除。
对待进程不停对文件写日志的操作,要释放文件占用的磁盘空间,最好的方法是在线清空这个文件,可以通过如下命令完成:
[root@localhost ~]# echo "" >/var/log/syslog
通过这种方法,磁盘空间不但可以马上释放,也可保障进程继续向文件写入日志,这种方法经常用于在线清理Apache、Tomcat、Nginx等Web服务产生的日志文件。
最后,有一个专业的运维是多么重要!