一台跑了两年的机器,df突然满格。du从根目录一路找下去,定位到nginx日志目录占了几十G。第一个念头是删。rm掉access.log,再看df,可用空间一点没变。文件是删了,可nginx还握着那个文件的句柄,空间要等进程关掉才释放。这时候要么重启nginx,要么把文件原地截断,句柄还在,空间立刻回来。磁盘满的告警往往先到,那时候网站还能打开,很多人不当回事。等数据库写不进去,才开始查。查之前先确认是哪块盘满了,根分区和数据盘经常不是同一块。
删文件不释放空间这件事,本质是文件系统按句柄算引用。引用没归零,块就不会回收,df看到的还是占用。lsof +L1可以列出已经删除但还占着空间的文件,一眼能看到是谁握着。
空间回来只是止血。日志为什么会涨到几十G,得看切分。多数发行版里nginx的logrotate配置是按天切,保留若干份。配置里rotate设成30,一天几百兆,一个月就是十几G。compress开着能省七成,但很多默认配置里没开。保留份数和单份大小要一起算,只算份数没有意义。按一天的量乘以保留天数,再跟磁盘容量对一下。
更隐蔽的是postrotate没写。日志切走了,nginx还在往老文件的inode里写。看目录里有个access.log.1一直在长,就是这个原因。判断方法很简单:看最新那份日志有没有继续变大。切分之后还在长,就是没重新打开。
正确的切分要有两步。先把当前文件改名,再让nginx重新打开日志。nginx收到USR1信号会重开文件,所以postrotate里通常是kill -USR1加pid。程序不支持重开的,用copytruncate,复制一份再清空原文件,代价是切分瞬间可能丢几行。复制和清空之间写进来的日志会丢,流量大的站点不建议用这个模式。
改完用logrotate -d干跑一遍,看有没有报错。权限不对、目录属主不对,都会静默失败,第二天起来照旧。-d是干跑,只打印打算做什么,不真的动文件。加-f是强制执行,测试的时候别顺手加上。
还有一种情况:日志量本身不正常。爬虫、扫描器、被刷的接口,一天能顶平时一个月。切分治不了这个,得回头看访问日志里谁在刷。按IP和URL各排一次,异常集中的那个就是源头。
监控阈值设在七成,别等满了再处理。磁盘满的时候,数据库和会话都可能写不进去,一个日志问题会变成整站故障。告警要发到会看的人手里,发到没人看的群里等于没设。
A5创业网 版权所有