客户反馈,收到某台服务器的磁盘告警。经查,该告警由星尘节点监控发出,而该服务器也正是星尘所在服务器。
分析问题
ssh登录服务器,使用命令检查哪个目录占用空间较大,逐个目录执行:
du -sh *
最终发现,星尘所在目录`/root/star/Data`中的StardustData.db,文件达到27G。
这里需要补充一下,客户部署IoT平台应用,仅用到2台服务器,一台部署星尘,一台部署IoT平台。为了节省资源,星尘直接使用sqlite,把mysql资源全部留给IoT平台。因为星尘的数据没有那么重要,即使损坏丢失也不影响IoT平台业务的正常运营。
检查星尘平台设置,保留数据时间都设置得很小,不大可能是数据过多所导致的问题。
在服务器上执行 sqlite3 StardustData.db,检查表确认,的确只保留了昨天和今天的数据。星尘会根据上图配置,定时清理数据,对于分表的数据直接drop过期表,非分表数据,每10分钟delete一次。从监控调用链来看,删除数据也是正常执行。
那么几乎可以确认,这是sqlite的问题,几百万行数据不应该占用27G。
虽然StardustData不是特别重要的数据,但是能留下来总比丢弃掉要好一些,尽力吧!
注:星尘重要数据保存在连接名Stardust中,对应sqlite数据库Stardust.db。一般使用mysql时,会让Stardust和StardstData这两个连接名共用一个mysql数据库。
解决问题
尝试收缩数据库,在sqlite3里面执行VACUUM命令,等了几分钟后提示错误,磁盘已满。原来,磁盘可用空间只剩下1.7G了。此路不通!
尝试备份数据库,在sqlite3里面执行 .backup sd.db,等了几分钟后提示错误,磁盘已满。不用看也知道,1.7G空间根本不足以执行这些命令。
这个库有27G大小,下载回来进行收缩处理很不现实,需要想办法在线处理。
想起2012年客户SCM系统sqlite数据库损坏时,(那会在祁连雪山里,后来到西宁上网吧去),我的处理方法:把数据库导出到sql文件,修改事务回滚语句后,重新导入到新库。
我们这个数据库是完好的,应该不需要修改,直接导出导入即可。
sqlite3 StardustData.db .dump > aa.sql
sqlite3 sd.db < aa.sql
mv StardustData.db StardustData.db.231223
cp sd.db StardustData.db
关闭星尘服务,执行'systemctl stop StarAgent',其实就是关闭星尘代理,自动停止本机所有应用。执行结果:
导出sql后,发现sql文件只有45M,那么最终数据库大概率应该比这个要小。因此决定暂时不要删除27G这个文件,以免操作失误。
导入sql到新库sd.db,并拷贝一份成为StardustData.db。
重新启动星尘代理,启动星尘服务,数据检查一切正常!
最后删掉备份文件,全面释放磁盘空间。
星尘节点监控显示,磁盘已经释放。上图9:30~10:30之间数据缺失,没错,这就是我们关闭了这台服务器StarAgent,分析解决问题的那一个小时。
而应用层面的监控数据是不受影响的,在服务器不可用时,各应用在内存里面保留埋点数据最长2小时。等到服务器或网络恢复后马上上报,下图就是10点多的埋点在10:35上传:
总结
sqlite数据库长时间运行后,可能有许多冗余空间无法收缩。
sqlite的数据收缩和备份,需要很大的磁盘空间,可通过导出导入sql来解决。