先上结论: 有连接占用这个表(会话没提交),kill掉相关连接即可释放出磁盘空间。
背景:
1、生产环境,因为历史原因某个日志表体积超过150GB,经与研发沟通后,确定处理策略是保留3个月的数据即可,其余历史数据可丢弃。
3、日志表,经业务方确认后,允许在割接期间有5分钟以内丢数据的情况发生。
说下大致处理的过程如下:
0、因为日志表,只有插入操作,我们可以根据自增id简单估算了下需要保留的数据范围。后续处理的时候,只要根据id范围来查询就行。
1、创建一个新表t_new,表结构与原先的表t保持一致。然后创建一个sequence,与t_new表关联起来。 记得给新表加下授权之类的玩意。
2、写个脚本,使用类似下面的方法,将t表的历史数据灌入t_new表中(脚本首次跑全量)
# 我这里的519999999是t表比较近的一个时刻的最大id,不需要很精准即可 while [[ $max_id -le 519999999 ]] ; do # 先插一条数据到新表里面,用于检测max_id。 sql如下:insert into t_new select * from t order by id asc limit 1; max_id=`psql -d db1 --no-align --tuples-only -c "select max(id) from t_new ;"` echo "当前时间: $(date +%F_%T)" | tee -a /tmp/archive.log echo "当前最大id:" ${max_id} | tee -a /tmp/archive.log let max_id=max_id+1 psql -d db1 -c "insert into t_new select * from t where id>=${max_id} order by id asc limit 5000;" done
3、在step2首次全量补数据完成后,我们还需要定时追下增量。给step2的这个脚本要配个cronjob,每5分钟运行一次追增量数据。
4、晚上低峰期,正式切换前,修改下新表的sequence,将last_value调大些,防止切换时候id冲突了。我这里类似这样:
alter sequence seq_t_new_id RESTART WITH 518500000;
5、低峰期切换表名
ALTER TABLE t RENAME TO t_old; ALTER TABLE t_new RENAME TO t;
6、再补下数据(如果允许丢失些数据,这一步也可以不用进行)
我们上面最后切换的时候,可能还会有数据不平的情况,我们可以再查下 t_old表最近5分钟的id情况,和新的t表做下比较,补到t表里面即可。
7、删除老表
truncate table xxx; drop table xxx;
8、执行完上面的删表操作后,我们看看磁盘空间释放出来没有?
很明显,/data 路径还是占用了87%的空间,我们drop table 完全没卵用。。。
prod-pg-01 / # df -lhP
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.7G 0 3.7G 0% /dev
tmpfs 3.7G 20K 3.7G 1% /dev/shm
tmpfs 3.7G 556K 3.7G 1% /run
tmpfs 3.7G 0 3.7G 0% /sys/fs/cgroup
/dev/vda1 50G 3.1G 44G 7% /
tmpfs 756M 0 756M 0% /run/user/0
/dev/mapper/VolGroup1-LogVol01 591G 489G 75G 87% /data
这种情况,很简单,通常是文件句柄(这里的话,就是有连接没释放)占用导致的。lsof看一下:
prod-pg-01 / # lsof | grep delete 结果如下: postgres 24550 postgres 254u REG 252,0 987389952 10224458 /data/base/16385/587704.7 (deleted) postgres 24550 postgres 255u REG 252,0 0 10224200 /data/base/16385/587708 (deleted) postgres 24550 postgres 256u REG 252,0 1073741824 10224234 /data/base/16385/587708.1 (deleted) postgres 24550 postgres 257u REG 252,0 1073741824 10223874 /data/base/16385/587708.2 (deleted) postgres 24550 postgres 258u REG 252,0 1073741824 10224205 /data/base/16385/587708.3 (deleted) postgres 24550 postgres 259u REG 252,0 1073741824 10224221 /data/base/16385/587708.4 (deleted) postgres 24550 postgres 260u REG 252,0 1073741824 10223748 /data/base/16385/587708.5 (deleted) postgres 24550 postgres 261u REG 252,0 1073741824 10224317 /data/base/16385/587708.6 (deleted) postgres 24550 postgres 262u REG 252,0 1073741824 10224367 /data/base/16385/587708.7 (deleted) postgres 24550 postgres 263u REG 252,0 1073741824 10224413 /data/base/16385/587708.8 (deleted) postgres 24550 postgres 264u REG 252,0 1073741824 10224459 /data/base/16385/587708.9 (deleted) postgres 24550 postgres 265u REG 252,0 0 10223673 /data/base/16385/587712 (deleted) postgres 24550 postgres 266u REG 252,0 1073741824 10223725 /data/base/16385/587712.1 (deleted) postgres 24550 postgres 267u REG 252,0 1073741824 10224203 /data/base/16385/587712.2 (deleted) postgres 24550 postgres 268u REG 252,0 1073741824 10224056 /data/base/16385/587712.3 (deleted) postgres 24550 postgres 269u REG 252,0 1073741824 10223755 /data/base/16385/587712.4 (deleted) postgres 24550 postgres 270u REG 252,0 1073741824 10224335 /data/base/16385/587712.5 (deleted)
找到pid后,到pg里面,干掉它:
db1=# select pg_terminate_backend(24550); pg_terminate_backend ---------------------- t (1 row) 如果上面的losf有多个进程占用的已删除的文件的话,我们这里多次执行 pg_terminate_backend即可。
再次查看,磁盘空间已经释放出来了:
prod-pg-01 / # df -lhP
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.7G 0 3.7G 0% /dev
tmpfs 3.7G 20K 3.7G 1% /dev/shm
tmpfs 3.7G 556K 3.7G 1% /run
tmpfs 3.7G 0 3.7G 0% /sys/fs/cgroup
/dev/vda1 50G 3.1G 44G 7% /
tmpfs 756M 0 756M 0% /run/user/0
/dev/mapper/VolGroup1-LogVol01 591G 242G 322G 43% /data