Posts tagged ‘du’

zfs snapshot磁盘开销

我们的部分MySQL是安装在solaris的zfs文件系统上的,zfs默认的recordsize为128k,但是实际上MySQL的页为16k,为了修改MySQL数据文件的的recordsize参数,我们决定把已有的文件mv出去,修改对应文件系统recordsize为16k以后,然后mv进来。
由于磁盘空间比较少,所以我特地每个机器上都看了一下。确认了磁盘剩余空间比MySQL需要移动的数据多了两倍左右,才开始做,
结果还是发现磁盘空间不足。

1、先描述一下已有的场景。之前创建了zfs的一个pool:data。并且通过
zfs create data/mysqldata
创建了mysql数据的目录
在5月27号有一个快照。那么数据库没有启动时,可以看到的如下:
[root@xy-offer-db13a:/data]#zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 49.8G 124G 2.90M /data
data/mysqldata 49.7G 124G 49.7G /data/mysqldata
data/mysqldata@100527 0 – 49.7G –
此时的磁盘空间占用情况
[root@xy-offer-db13a:/data]#cd /data/
[root@xy-offer-db13a:/data]#du -sh *
48G mysqldata
2.9M slow-query.log.20100418
mysqldata文件占用了48G。slow-query占用了一点点。我们不用管它。快照因为数据没有不一致,所以占用的空间为0。此时mysqldata对应recordsize为zfs默认的128k。

2、我们想要做的是,把mysqldata里面的文件先mv出来,放到data文件系统中。然后修改mysqldata的recordsize为16k,然后cp进来,删除data文件系统中的备份文件

3、实际执行:
第一步:我们把数据mv到data文件系统
提交执行,mv命令:
[root@xy-offer-db13a:/data]#mkdir /data/md
[root@xy-offer-db13a:/data]#/bin/mv -f /data/mysqldata/* /data/md/
此时看到的磁盘容量变化:
[root@xy-offer-db13a:/data]#cd /data/
[root@xy-offer-db13a:/data]#du -sh *
1.5G md
45G mysqldata
2.9M slow-query.log.20100418
[root@xy-offer-db13a:/data]#df -kh
Filesystem size used avail capacity Mounted on
/dev/dsk/c0t0d0s0 19G 5.2G 14G 28% /
/devices 0K 0K 0K 0% /devices
ctfs 0K 0K 0K 0% /system/contract
proc 0K 0K 0K 0% /proc
mnttab 0K 0K 0K 0% /etc/mnttab
swap 8.5G 980K 8.5G 1% /etc/svc/volatile
objfs 0K 0K 0K 0% /system/object
sharefs 0K 0K 0K 0% /etc/dfs/sharetab
/usr/lib/libc/libc_hwcap1.so.1
19G 5.2G 14G 28% /lib/libc.so.1
fd 0K 0K 0K 0% /dev/fd
swap 8.5G 24K 8.5G 1% /tmp
swap 8.5G 24K 8.5G 1% /var/run
/dev/dsk/c0t0d0s3 46G 156M 45G 1% /export/home
data 174G 3.1G 121G 3% /data
data/mysqldata 174G 47G 121G 28% /data/mysqldata
[root@xy-offer-db13a:/data]#zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 52.8G 121G 3.06G /data
data/mysqldata 49.7G 121G 47.1G /data/mysqldata
data/mysqldata@100527 2.56G – 49.7G –
我们会发现快照占用的空间一直在涨,
[root@xy-offer-db13a:/data]#zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 83.0G 91.3G 33.2G /data
data/mysqldata 49.7G 91.3G 26.0G /data/mysqldata
data/mysqldata@100527 23.7G – 49.7G –
一直到mv完成了,完成mv以后磁盘占用情况如下:
[root@xy-offer-db13a:/data/md]#zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 116G 58.5G 65.9G /data
data/mysqldata 49.7G 58.5G 1.81G /data/mysqldata
data/mysqldata@100527 47.9G – 49.7G –
快照占用了47.9G(REFER),data/mysqldata里面已经没有任何数据了,还占用了49.7G(对应的就是快照的REFER),跟你没有把文件mv出去之前是一模一样的。也就是说,虽然你把文件mv出去了,如果快照还在那边的话,磁盘空间你一样的还占用了那么多。
其实这个也是可以理解的,你需要回复到之前有数据的样子,当然需要保存这么多数据阿。
这里还有一个问题,48G的MySQL数据mv到data文件目录下来,变成了65G。难道是由于recordsize改变了,导致文件增大了?
专门验证了一下,在另外一台机器上,数据只有47G
[root@xy-offer-db14a:/data/mysqldata]#du -sh
47G .
我们把它mv到data文件系统
[root@xy-offer-db14a:/data/mysqldata]#mkdir /data/md
[root@xy-offer-db14a:/data/mysqldata]#/bin/mv -f /data/mysqldata/* /data/md/
[root@xy-offer-db14a:/data/md]#du -sh
64G .
[root@xy-offer-db14a:/data/md]#zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
data 177G 111G 66.3G 62% ONLINE –
变成了64G。这个zfs的compress参数都是设置为off的。
[root@xy-offer-db14a:/data/md]#zfs get compress
NAME PROPERTY VALUE SOURCE
data compression off default
data/mysqldata compression off local
data/mysqldata@100527 compression – –
为什么拷贝一下,在同一个pool里面,会从47G变成64G?
[root@xy-offer-db14a:/data/mysqldata]#du -sh *
2.2G binlog
3.0G innodb_log
222M innodb_ts
41G mydata
287M relaylog
1K tmpdir
[root@xy-offer-db14a:/data/md]#du -sh *
2.2G binlog
3.0G innodb_log
2.0G innodb_ts
56G mydata
287M relaylog
1K tmpdir
这里innodb_ts从原来的222M增长为2G,可以理解,是MySQL虽然分配的时候是2G,但是实际用到的只有200多M,mv的过程中把空间都占用上了。mydata目录平白无故的涨了15G。难道也是这样的原因?有点想不通。

第二步,将数据拷贝回去
这里由于第一次做没有注意到前面空间的变化,所以拷贝数据回data/mysqldata目录时,空间已经不足了。

4、解决方案:
将数据mv出去,同样可以将数据mv进来,咨询了老唐,认为mv同样能够达到把文件修改为16k recordsize的效果。(如果只是修改文件指针,而不是真正的拷贝复制文件,mv应该很快返回,而现在确实需要近半个小时才能完成mv操作。并且/data和/data/mysqldata在不同的mout点上)。

这里学到了一个事情:移动zfs文件的时候,你需要计算快照可能引起的空间成倍增长。
修改zfs的recordsize是否会让文件占用空间增长还需要进一步验证。

may your success.

crontab导致磁盘空间满问题的解决

收到磁盘空间满的信息。发现主机上/var空间不足。du -sh 一层层的查下去看的时候,最终找到了/var/spool/clientmqueue这个目录。里面文件有48w个,娘阿。这个问题的原因是crontab的一些计划任务中产生了大量日志信息。这些日志信息没有导入到/dev/null或者指定的文件。结果就产生了目录下的这些文件。本来这些文件要作为mail发出去的。结果sendmail没有启动,积留在这里了。建议crontab的计划任务全部写成这个样子:
30 7 * * * /home/mysql/admin/bin/sec.startup restart  >/dev/null 2>&1
请注意后面的>/dev/null 2>&1。这里2>&1表示标准错误也放到标准输出,而标准输出导入到了/dev/null;也就是说,日志信息我不要了。如果你要的话,导入到你指定的文件咯。
这里还有一个注意的地方就是>/dev/null 2>&1的顺序。他们的顺序也不能反。否则标准错误不能导入到标准输出。还是要写到/var/spool/clientmqueue文件中。
我们可以看看spool和clientmqueue的linux帮助:
man hier
spool/     miscellaneous printer and mail system spooling
directories

clientmqueue/
undelivered submission mail queue; see
sendmail(8)

原理搞清楚了,以后的问题也避免了。那么就是已有的文件删除问题了。注意,不要这样删除rm -rf /var/spool/clientmqueue,这个文件夹还是蛮重要的,听说过删除该文件夹系统出问题的事例了,希望你不是下一个造成同样的故障的人。
删除文件本来很简单,但是删除48w个文件就是一个有技术含量的活了。直接rm *会报错说Argument list too long。rm接收的参数列太多了。我们就不追究这么通用的工具怎么会出这么令人不爽报错了吧。简单的解决办法:
a、利用xargs。xargs其实就是把传给它的列表一个一个的传给它的命令去一个一个的执行。具体的命令为ls |xargs rm -f。
b、利用find -delete。具体命令为find /var/spool/clientmqueue/ -type f -delete

may you success.