记一次因磁盘块默认保留策略导致的数据库导入失败问题

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://dgd2010.blog.51cto.com/1539422/1705606

近日开发人员要新测试一个功能,需要用到生产环境中的数据库(生产库版本:mysql-5.5.38-linux2.6-x86_64),因此需要我协调将生产库同步到测试库(测试库版本:mysql-5.5.38-linux2.6-x86_64)中。由于测试库中有很多从生产库同步过来的库,但这些库大都已经dirty了,所以不如重新同步一份。

由于这些数据库在我接手以前就已经存在了,但直到在我使用的过程中发现,此数据库存在问题,原来它并没有启用innodb_file_per_table选项(这个选项在MySQL 5.6.6以及更高版本中是默认启用的),如果此选项没有被启用,那么使用Innodb数据库类型的数据库的表中的数据和索引都是存放在系统表空间(the system tablespace)的,而系统表空间存放在ibdata_file文件(这个文件默认就是ibdata1)里。如果此选项没有启用就会导致文件系统的性能对数据库的性能产生巨大的影响,特别是当执行一些如DROP TABLE 和 TRUNCATE TABLE操作时。同时因为MySQL的系统表空间永远不会缩小,而且数据库中所有的数据库实例都会共享系统表空间,会导致这个文件会越来越大,以致于耗尽磁盘空间。

例如举个实际的例子:

上图就是生产库和测试库的例子,生产库的ibdata1文件已经达到了90GB,测试库的ibdata1文件也不甘示弱,达到了71GB。

以下详细说说此事情的经过。

生产库的磁盘为SSD磁盘,性能还是不错的,每日早上4点都有数据库备份脚本对生产库备份(mysqldump出sql并压缩成zip文件)。因此要将生产库的库同步到测试库的话只需要将备份文件用scp命令通过内网地址传输到测试库,将zip文件解压出来,通过nohup命令后台导入即可。

但随即发现问题不妙。原先监控系统早就报警说磁盘空间不足20%,一直没在意,后来发现磁盘空间直接利用率100%了。

 

但是发现明明总空间有99GB而使用94GB,而使用率却是100%,那5GB“不翼而飞”了?经排查,先排除磁盘损坏原因,后来确定为原来是一个默认的系统保护策略。

此策略的英文描述如下:

Reserving some number of filesystem blocks for use by  privileged  processes  is done to avoid filesystem fragmentation, and to allow system daemons, such as syslogd(8), to continue to function correctly after non-privileged processes are prevented from writing to the filesystem.  Normally, the default percentage of reserved blocks is 5%.

翻译成中文大体如下:

此策略用于为一些特权进程(这个进程与root用户发起的进程不同,注意区分)正确执行完来避免造成文件系统碎片和为了允许系统后台程序如syslogd在非特权进程被阻止写入文件系统后能继续正常的工作,而采取的保留一些文件系统块用于专用的策略。默认保留的块数量是总数量的5%。

这个策略可用于ext2/ext3/ext4等系统。

dumpe2fs /dev/xvdb1 |grep -i "block coun"     
awk 'BEGIN{print 1310694 / 26213888}' ,bc工具做浮点数除法时有问题,建议使用awk。      
#0.05 --> 5% Reserved block count --> refer to 'man 8 tune2fs' and option '-m'

经图上计算恰好是5%!既然这是默认策略,不管是默认还是不默认的,都可以调整,然后用tune2fs调整一下,如下图所示:

这样那5GB空间就可以使用了,然后清除一些应用日志继续执行程序后发现还是有问题。

重新执行mysql导入命令后发现磁盘空间很快又被用尽了,赶紧取消导入命令。

此时才开始关注MySQL的ibdata问题,也就是文章刚开始提到的问题了。因此日后配置数据库时如果要使用Innodb一定要记得开启innodb_file_per_table选项。同时5%的磁盘保留策略最好不要随意更改,免得文件系统真的遭到破坏,比如碎片的产生。

再提醒一句:MySQL的系统表空间永远不会缩小,因此ibdata1这个文件会越来越大,要想降低ibdata文件的大小,决不能采用直接删除的办法,如果直接删除了,那就比较悲催了,因为Innodb引擎的原理会轻则导致数据库无法启动(意思是可以恢复),重则导致数据库数据丢失(也能找回来,但未必能100%找回来),唯一降低ibdata文件的办法就是重新安装数据库,没错,是重新安装数据库,将原先的数据库通过mysqldump导出(不要用percona-xtrabackup备份,这个工具并不是导出sql文件),数据库重新安装后,启用innodb_file_per_table选项,再用备份的SQL文件导入。上述操作显而易见还是非常麻烦的。

再额外说一些后续。

如果只有有限的机器做数据库使用,最好不同业务运行在不同的数据库服务器上。即一台机器上运行多个数据库服务器,每一个数据库服务器只运行一个数据库实例,这样做虽然繁琐,但它的好处也是显而易见的。例如一个数据库服务器损坏不会影响一批业务系统。每一个数据库实例可以很容易的对应一个从库,更好的实现HA。如果一个数据库服务器运行多个数据库实例,那么配置主从复制时会非常麻烦,因为有多个实例需要配置主从时,它的二进制文件和pos值在利用mysqldump命令逐个备份数据库时是很难确定的,除非借助percona-xtrabackup或者一些手动的办法,获取唯一的二进制文件和pos值。这种策略的设定正好在mysql的multiserver上很好的得到了体现。

tag:mysql ibdata文件,mysql innodb_file_per_table,tune2fs,磁盘保护策略,系统保留块计数

--end--

本文出自 “通信,我的最爱” 博客,请务必保留此出处http://dgd2010.blog.51cto.com/1539422/1705606

时间: 2024-09-20 18:26:23

记一次因磁盘块默认保留策略导致的数据库导入失败问题的相关文章

UNIX内核(7):super block管理inode和磁盘块

原文转自:http://blog.chinaunix.net/uid-7471615-id-83767.html UNIX内核系列已经写了5篇了.按照"The Design of The UNIX Operation System"给出的系统原型来看,file sub-system基本上已经覆盖到了--当然要除去设备驱动相关的部分,如下图所示: http://blogimg.chinaunix.net/blog/upfile2/071118215716.jpg --注意,file su

思考与总结:扇区和磁盘块的区别是什么

    下面这篇思考,是在地铁上突然想到,然后把理解用自己的文字写在手机上.       扇区和磁盘块的区别是什么?   这么多的单位真的很难记忆,很难区别,最好是自己了解原理.物理层面分为磁道,扇区. 磁盘块是个虚拟出来的概念,是操作系统中的.操作系统为什么要虚拟个这样的概念出来呢?操作系统与磁盘打交道的最小单位是磁盘块.目前是4k大小. 操作系统操作磁盘,也需要通过磁盘驱动器进行.所以离不开扇区的. 最小单位,好比我们生活中约定最小单位是一毛.没有一分的单位了.为什么要这样,方便管理? 扇区

RMAN 配置保留策略

      RMAN保留策略关乎数据的完整性,因此事关重大,由用户定义的.基于用户数据恢复所能承受的容忍度来设置.也就是说根据恢复的需要,用户需要保留几天的数据,或者说用户需要备份的保留几个副本,或者不需要设定保留策略.在生产环境中多数使用的是基于恢复窗口的保留策略,因此需要重点关注与理解其用法.最本文主要描述了RMAN下的三种保留策略方式. 1.什么是备份保留策略    也就是说备份可以保留多久,需要保留多久的问题,我们可以通过configure retention policy 来进行配置 

阿里云如何为磁盘设置自动快照策略

阿里云如何为磁盘设置自动快照策略 您可以根据业务需求,为磁盘设置自动快照策略. 自动快照的命名格式为:auto_yyyyMMdd_1,比如 auto_20140418_1 说明: 创建快照时会对您的磁盘读写造成一定的波动,强烈建议根据您的业务负荷,选择在业务负荷较低的时间段执行自动快照,以减少对您业务的影响. 非使用中的普通云盘将不执行自动快照策略. 你手动创建的快照和自动快照没有冲突.不过正在对某一块磁盘执行自动快照时,您需要等待自动快照完成后,才能手动创建快照. 您可以通过磁盘入口或者快照入

关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析_php实例

最近由于项目开发需要,手机客户端和网页端统一使用一套接口,为保证 会话(Session) 能够正常且在各类情况下兼容,我希望能够改变 SessionID 的获取方式.默认情况下,所有网站都是通过 HTTP 请求的 Header 头部中的 Cookie 实现的,通过 Cookie 中指定的 SessionID 来关联到服务端对应数据,从而实现会话功能. 但对于手机客户端,可能并不会支持原始的 Cookie,亦或者根据平台需要而屏蔽,因此开发中要求通过增加一个请求头 X-Session-Token

如何使用DUMP数据块与BBED查看BLOCK对比数据库修改时的SCN

实验思路: 先在数据库中对bys.a表的一行进行更新,查出此行对应的FILE# BLOCK# 然后DUMP此FILE# BLOCK#,查看SCN信息 使用BBED DUMP此FILE# BLOCK#,查看SCN信息 1.在数据库中对 bys.a表的一行进行更新,记录此行的ROWID. 19:55:13 BYS@ bys3>select * from a; B ---------- 55 7 3 19:55:15 BYS@ bys3>update a  set b=0 where b=7; 1

扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题

最近由于项目开发需要,手机客户端和网页端统一使用一套接口,为保证 会话(Session) 能够正常且在各类情况下兼容,我希望能够改变 SessionID 的获取方式.默认情况下,所有网站都是通过 HTTP 请求的 Header 头部中的 Cookie 实现的,通过 Cookie 中指定的 SessionID 来关联到服务端对应数据,从而实现会话功能. 但对于手机客户端,可能并不会支持原始的 Cookie,亦或者根据平台需要而屏蔽,因此开发中要求通过增加一个请求头 X-Session-Token

SQL语句实现删除重复记录并只保留一条_数据库其它

复制代码 代码如下: delete WeiBoTopics where Id in(select max(Id) from WeiBoTopics group by WeiBoId,Title having COUNT(*) > 1); SQL:删除重复数据,只保留一条用SQL语句,删除掉重复项只保留一条在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢 1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 复制代码 代码如下:  select * f

默认apache编码导致DEDECMS乱码及其他乱码总结

朋友的dedecms乱码,文件的编码以及head里面的meta的编码都是正确的,把生成的HTML下载到本地打开,也都是正常的,一放到服务器就乱码. 经过更为细致的检查,发现他在根目录下的.htaccess里面配置了AddDefaultCharset UTF-8,这样就会导致apache默认使用utf-8编码向浏览器发送数据,客户的dedecms是GBK编码,所以自然就乱码了,所以然还有人在.htaccess里面配置这个...下面在网上找到的资料: 首先,可以使用AddDefaultCharset