Enjoy It

数据库迁移--灾难复现和解决方案
背景2018年8月8日左右,想要在只跑了Mysql的服务器上安装上lnmp,以方便跑网站。因为已经安装了Mysql...
扫描右侧二维码阅读全文
14
2018/08

数据库迁移--灾难复现和解决方案

背景

2018年8月8日左右,想要在只跑了Mysql的服务器上安装上lnmp,以方便跑网站。因为已经安装了Mysql了,所以在安装lnmp的时候,没有选择安装Mysql,这样按道理来说是没有什么问题的,可以lnmp安装后,输入 mysql -uroot -p,竟然提示如下:
1.png

这时候我有点慌了,因为数据库里保存了300多万条数据,这些数据是我两个星期努力的成果,要是全部丢失,这两个星期的努力就白费了,于是马上开始了补救措施。

灾难复现

当出现上图提示之后,我下意识的进入 /var/lib/mysql 目录下,看数据库文件还在不在
2.png

当出现上面信息的时候,我松了口气,数据库相关文件还在,问题还不算太严重。于是在 /home/ 下新建了一个文件夹,将 /var/lib/mysql/ 中的所有文件全部移动 拷贝 过去,然后重新安装mysql。

短暂的等待之后,mysql安装好了,进入 /var/lib/mysql/ 下,看到里面有了一些文件
3.png

这些都是数据库的初始文件,和刚才被移出的文件一样(少了自建的数据库)
然后,把刚才移出去的文件覆盖这些文件,大功告成。
接着进入数据库,测试了一下是否正常:

  • 显示数据库列表 √
  • 显示表列表 √
  • 显示表中信息 ×

当要显示表信息时,提示xxx.name not exist

问题

经过一系列Google,发现这是数据库迁移过程中的一个问题。

/var/lib/mysql/ 目录下,有一个文件,ibdata1,这个文件记录了数据库文件之间关系的相关信息。在mysql中之所以可以看到数据库列表和表列表,是因为这些东西是以文件的形式存在的,可以直接看到。而无法查询到表中的数据,是因为缺少了这些文件之间的对应关系。ibdata1这个文件很有可能损坏,而导致无法读取出这些关系。

可是,我在移动ibdata1的时候,并没有损坏文件。所以问题就出来安装lnmp了。

由于安装lnmp的时候没有勾选安装mysql,而lnmp很可能是先卸载本来的mysql,然后在安装mysql,由于我没有选择安装,所以就lnmp就只把mysql卸载了。

由于需要先停止服务,才能够移动ibdata1,否则就会造成文件损坏(可能是因为某些机制)

可能因为lnmp没有将mysql服务停止,就进行了卸载,导致文件损坏。

解决方案

既然原来的ibdata1文件已经损坏,也不可能恢复了。所以我采取了重新建表的方法,主要是ibdata采取的是表空间的存储机制,所以可以通过复原建数据库和建表的过程,重新在ibdata文件中建立表空间。

create database gaokaozhiyuan  //创建和原来一样的数据库

这个时候 /var/lib/mysql/ 目录下会出现 gaokaozhiyuan 这个文件夹

create 'tablename' {.....}    //创建和原来结构一样的表

这个时候 gaokaozhiyuan 目录下会有两个文件 tablename.frmtablename.ibd

alter table tablename discard tablespace   //删除新建的表在ibdata中的表空间

这个时候 gaokaozhiyuan 目录下的 tablename.ibd 文件会消失,只剩下 tablename.frm

然后把原来的文件 tablename.ibd 复制到 gaokaozhiyuan 目录下 ,并执行一下sql语句

alter table tablename import tablespace  // 导入表空间

然后:

select * from tablename

已经可以查看数据了,接下来把剩余的几个表都安装以上步骤进行复原。

相关

对于使用了innodb引擎的mysql,有必要了解一下innodb。

InnoDB存储架构

820365-20160720201614154-1247891255.png

innodb相关的磁盘文件

820365-20160720201627122-2053526887.png

innodb系统表空间文件:
ibdata1存放:

  • 回滚段
  • 所有innodb表元数据信息(这就是为什么innodb无法像myisam表一样,直接将表定义文件 表名.frm 和表数据文件 表名.ibd 拷到 另一个库中,因为还有部分元数据信息在ibdata1文件中)
  • double write,insert buffer dump 等等

自动扩展机制

基本参数

查看innodb的配置参数

mysql> show global variables like "%innodb%" ;
基本参数说明
innodb_data_home_dir系统表空间文件ibdata1存放在哪个目录下
innodb_log_group_home_dir日志文件ib_logfile0/1存放在哪个目录
innodb_data_file_path定义系统表空间文件ibdata1的属性;
innodb_autoextend_increment系统表空间文件每次扩展的大小
innodb_log_file_sizeib_logfile文件大小(写操作多时可以增大)
innodb_log_files_in_group有几个ib_logfile文件(写操作多时可以增大 )

innodb_file_per_table:
关键;开启后,会产生表定义文件 表名.frm,和表数据文件 表名.idb,
这样每个表的数据都会存在自己的.idb文件中;如果 关闭,那么所有的
数据都会 存在系统表空间文件 ibdata1文件中,这会ibdata1 非常繁忙
并且臃肿 庞大,而且ibdata1无法 收缩的,比如线上将一个 大的表 drop掉,
此时ibdata1是无法自动缩小的(需要使用 optimiza table 来优化);而如果开启,数据存在 .idb文件中,则可以随时缩小;

820365-20160720201646810-26603526.png

innodb数据文件存储结构

820365-20160720201707201-2116954787.png

特点:

  • 根据主键寻址速度很快
  • 主键值递增的insert插入效率较好
  • 主键值随机insert插入操作效率差
  • 因此,innodb表必须指定主键,建议使用自增数字;

如果不使用主键,系统会自动加上一个6字符字符串的主键;

innodb数据块缓存池

  • 数据的读写需要经过缓存(缓存在buffer pool 即在内存中)
  • 数据以整页(16K)位单位读取到缓存中
  • 缓存中的数据以LRU策略换出(最少使用策略)
  • IO效率高,性能好

820365-20160720201722529-136567453.png

innodb_buffer_pool_size:

820365-20160720201734201-47258135.png

为了IO效率,数据库修改的文件都在内存缓存中完成的;那么我们知道一旦断电,内存中的数据将消失,而数据库是如何保证数据的完整性的呢?那就是数据持久化与事务日志;

innodb 数据持久化与事务日志

  • 事务日志实时持久化
  • 内存变化数据(脏数据)增量异步刷出到磁盘
  • 实例故障靠重放日志恢复
  • 性能好,可靠,恢复快;

820365-20160720201757810-1590929469.png

如果宕机了则:应用已经持久化好了的日志文件,读取日志文件中没有被持久化到数据文件里面的记录;将这些记录重新持久化到我们的数据文件中.

820365-20160720201813247-838092887.png

优缺点:如果实时的刷新到 磁盘中,要找到x随机存放的位置,IO消耗大;而如果将修改刷新到日志文件中,因为它是顺序读写的,速度会快很多。

innodb日志持久化相关参数
innodb_flush_log_at_trx_commit

820365-20160720201824294-1035907177.png

innodb 行级锁

  • 写不阻塞读
  • 不同行间的写相互不阻塞
  • 并发性能好

innodb与事务ACID
事务ACID特性完整支持

  • 回滚段失败回滚 A
  • 支持主外键约束 C
  • 事务版本+回滚段=MVCC I
  • 事务日志持久化 D

默认可重复读隔离级别,可以调整

最后修改:2018 年 08 月 15 日 01 : 04 AM
如果觉得我的文章对你有用,请随意赞赏

发表评论