数据空洞的产生原理都是相通的,类似的。
文件空洞的概念:
在UNIX文件操作中,文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被设为 0。
如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定的。
文件空洞的特点:
用ls查看的文件大小是将空洞算在内的。
cp命令拷贝的文件,空洞部分不拷贝,所以生成的同样文件占用磁盘空间小。
用read读取空洞部分读出的数据是0,所以如果用read和write拷贝一个有空洞的文件,那么最终得到的文件没有了空洞,空洞部分都被0给填充了,文件占用的磁盘空间就大了。不过文件大小不变。
空洞文件作用很大,例如迅雷下载文件,在未下载完成时就已经占据了全部文件大小的空间,这时候就是空洞文件。下载时如果没有空洞文件,多线程下载时文件就都只能从一个地方写入,这就不是多线程了。如果有了空洞文件,可以从不同的地址写入,就完成了多线程的优势任务。
hbase空洞:
在我们的大规模的应用测试中,发现了个别异常的Region。
首先,介绍发现这个问题的来由。在线上读写请求出现个别操作失败,并且失败的请求指向同一个Region A,因此,检查该Region A的位置,指向了host1,然而进入host1的onlineRegion列表中,却没有发现该Region,因此,此时出现Region不匹配的问题。更名为Region空洞。
在互联网应用中,有一个共性是,找问题比解决问题要难。只要定位到了问题,根据上面对于AM、RS、HMaster之间Region迁移的理解,很容易发现是Region迁移过程中出现了一次事故,造成了空洞现象。
我的解决方法就是增加一个定时触发的监控程序,去检查.META.表中记录的Region位置(RS)是否与RS对应上,如果RS上onlineRegion,不存在该Region,则就报警,并尝试进行unassign操作。
将该程序放入crontab中,定时检查监控,并有Region重新部署功能。
http://blog.sina.com.cn/s/blog_4a1f59bf0101b1hv.html
MongoDB空洞:
很多时候,我们项目上线时间比较久了,我们积累了一些无用的数据,而由于MongoDB顺序写的原因,在我们删除部分无用数据后,它的storageSize和fileSize并不会变小,这就造成了大量的数据空洞。
这些数据空洞除了占用磁盘之外,也会加载到内存中,这会降低内存效率。
所以这个时候,我们一般要对这些数据空洞进行处理,一般有下面几种处理方式。 一种是使用MongoDB自带的compact命令:
db.collectionName.runCommand(“compact”)
这种方式是collection级别的压缩,只能去除collection内的碎片,但是MongoDB的数据分配是DB级别的,效果并不一定多好,其次呢,这个压缩是线上压缩,肯定会影响服务的,磁盘IO会比较高,这么干容易出事。
还有一种方式,也就是我们下面要详细说明的方式,过程大概类似于下面:
先预热从库
提升从库为主库,原主库降为从库
移除原主库的DB数据,直接remove掉
重新同步
完成后,预热,然后将此库提升为主库,原从库依然降为从库
这样做的好处是:
DB级别,不会有碎片,毕竟是新写的,收缩效率高
基本不会影响线上服务(当然,你不能只有一个从,你也不能挑服务高负荷的时候来干这个事情)
Mysql空洞:
现发现对一个几亿条记录的表进行删除记录及进行optimize操作时,会极其的耗时间和空间。
删除记录时,MyISAM表会留下空洞碎片,碎片多了会持续降低MySQL性能。如果使用optimize操作的话,MySQL会先生成一个TMD文件;完成操作后才会把这个文件删除。这个过程相当漫长……
所以再设计表和存储记录时,就应当想好这个表的记录会不会有大量记录;如果是的话应该要先设计好应对方案,水平切分或垂直切分。