当时的我在外面玩的正起劲,忽然一个电话打来:“冰河,你在哪?服务器忽然不能访问了!”。我:“又有什么状况啊?”。“我不当心踩到服务器电源链接的插线板了,服务器断电了,重启时提示没法启动”。我内心一万个无语,问:”是哪台服务器断电了“。“我不当心踩到那个小插线板的开关了,链接到这个插线板的服务器都断电了”。我:尼玛,那是数据库啊,我去。。。php
因而我赶忙飞奔回公司,开始了苦逼的数据恢复过程。。。html
文章已收录到:python
https://github.com/sunshinelyz/technology-binghemysql
https://gitee.com/binghe001/technology-binghegit
回到公司一看,断电的是公司的消息服务子系统数据库,数据库共3台,一种两从,并采用了分库分表的方式存储数据。我首先把三台服务器启动好,发现主数据库的进程没法启动,两台从数据库同步主库数据的状态异常。按照顺序,我先看主数据库的日志信息,发现MySQL的错误日志中输出了以下信息。github
-----------------------------------------161108 23:36:45 mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/var2021-02-28 23:36:46 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).2021-02-28 23:36:46 5497 [Note] Plugin 'FEDERATED' is disabled.2021-02-28 23:36:46 7f11c48e1720 InnoDB: Warning: Using innodb_additional_mem_pool_size is DEPRECATED. This option may be removed in future releases, together with the option innodb_use_sys_malloc and with the InnoDB's internal memory allocator.2021-02-28 23:36:46 5497 [Note] InnoDB: Using atomics to ref count buffer pool pages2021-02-28 23:36:46 5497 [Note] InnoDB: The InnoDB memory heap is disabled2021-02-28 23:36:46 5497 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins2021-02-28 23:36:46 5497 [Note] InnoDB: Memory barrier is not used2021-02-28 23:36:46 5497 [Note] InnoDB: Compressed tables use zlib 1.2.32021-02-28 23:36:46 5497 [Note] InnoDB: Using CPU crc32 instructions2021-02-28 23:36:46 5497 [Note] InnoDB: Initializing buffer pool, size = 16.0M2021-02-28 23:36:46 5497 [Note] InnoDB: Completed initialization of buffer poolInnoDB: Database page corruption on disk or a failedInnoDB: file read of page 5.InnoDB: You may have to recover from a backup.2021-02-28 23:36:46 7f11c48e1720 InnoDB: Page dump in ascii and hex (16384 bytes): len 16384; hex 7478d078000000050000000000000000000000000f271f4d000700000000000000000000000000000000001b4000000000000 000000200f20000000000000006000000000000002d000000000000002e000000000000002f0000000000000030000000000( 省略不少相似代码)InnoDB: End of page dump2021-02-28 23:36:46 7f11c48e1720 InnoDB: uncompressed page, stored checksum in field1 1954074744, calculated checksums for field1: crc32 993334256, innodb 2046145943, none 3735928559, stored checksum in field2 1139795846, calculated checksums for field2: crc32 993334256, innodb 1606613742, none 3735928559, page LSN 0 254222157, low 4 bytes of LSN at page end 254221236, page number (if stored to page already) 5, space id (if created with >= MySQL-4.1.1 and stored already) 0InnoDB: Page may be a transaction system pageInnoDB: Database page corruption on disk or a failedInnoDB: file read of page 5.InnoDB: You may have to recover from a backup.InnoDB: It is also possible that your operatingInnoDB: system has corrupted its own file cacheInnoDB: and rebooting your computer removes theInnoDB: error.InnoDB: If the corrupt page is an index pageInnoDB: you can also try to fix the corruptionInnoDB: by dumping, dropping, and reimportingInnoDB: the corrupt table. You can use CHECKInnoDB: TABLE to scan your table for corruption.InnoDB: See also http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.htmlInnoDB: about forcing recovery.InnoDB: Ending processing because of a corrupt database page.2021-02-28 23:36:46 7f11c48e1720 InnoDB: Assertion failure in thread 139714288817952 in file buf0buf.cc line 4201InnoDB: We intentionally generate a memory trap.InnoDB: Submit a detailed bug report to http://bugs.mysql.com.InnoDB: If you get repeated assertion failures or crashes, evenInnoDB: immediately after the mysqld startup, there may beInnoDB: corruption in the InnoDB tablespace. Please refer toInnoDB: http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.htmlInnoDB: about forcing recovery.03:36:46 UTC - mysqld got signal 6 ;This could be because you hit a bug. It is also possible that this binaryor one of the libraries it was linked against is corrupt, improperly built,or misconfigured. This error can also be caused by malfunctioning hardware.We will try our best to scrape up some info that will hopefully helpdiagnose the problem, but since we have already crashed,something is definitely wrong and this may fail.key_buffer_size=16777216read_buffer_size=262144max_used_connections=0max_threads=1000thread_coun t=0connection_count=0It is possible that mysqld could use up tokey_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 798063 K bytes of memoryHope that's ok; if not, decrease some variables in the equation.Thread pointer: 0x0Attempting backtrace. You can use the following information to find outwhere mysqld died. If you see no messages after this, something wentterribly wrong...stack_bottom = 0 thread_stack 0x40000/usr/local/mysql/bin/mysqld(my_print_stacktrace+0x35) [0x8e64b5]/usr/local/mysql/bin/mysqld(handle_fatal_signal+0x41b) [0x652fbb]/lib64/libpthread.so.0(+0xf7e0)[0x7f11c44c77e0]/lib64/libc.so.6(gsignal+0x35) [0x7f11c315d625]/lib64/libc.so.6(abort+0x175) [0x7f11c315ee05]/usr/local/mysql/bin/mysqld[0xa585c5]/usr/local/mysql/bin/mysqld[0xa6c7b4]/usr/local/ mysql/bin/mysqld[0xa6cbc7]/usr/local/mysql/bin/mysqld[0xa5bce2]/usr/local/mysql/bin/mysqld[0xa1e2ba]/usr/local/mysql/bin/mysqld[0xa0bf60]/usr/local/mysql/bin/mysqld[0x95a427]/usr/local/mysql/bin/mysqld(_Z24ha_initialize_handlertonP13st_plugin_int+0x48) [0x58f788]/usr/local/mysql/bin/mysqld[0x6e4a36]/usr/local/mysql/bin/mysqld(_Z11plugin_initPiPPci+0xb3e) [0x6e826e]/usr/local/mysql/bin/mysqld[0x582d85]/usr/local/mysql/bin/mysqld(_Z11mysqld_mainiPPc+0x4d8) [0x587d18]/lib64/libc.so.6(__libc_start_main+0xfd) [0x7f11c3149d5d]/usr/local/mysql/bin/mysqld[0x57a019]The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html containsinformation that should help you find out what is causing the crash.161108 23:36:46 mysqld_safe mysqld from pid file /usr/local/mysql/var/VM_241_49_centos.pid ended------------------------------------------------------------------------------
从日志中能够看出是innodb引擎出了问题。日志里提示到 http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html查看强制恢复的方法。在mysql的配置文件my.cnf里找到 [mysqld]字段下,添加 innodb_force_recovery=1:sql
[mysqld]innodb_force_recovery = 1
若是innodb_force_recovery = 1不生效,则可尝试2——6几个数字shell
而后重启mysql,重启成功。而后使用mysqldump或 pma 导出数据,执行修复操做等。修复完成后,把该参数注释掉,还原默认值0。数据库
配置文件的参数:innodb_force_recoverycentos
innodb_force_recovery影响整个InnoDB存储引擎的恢复情况。默认为0,表示当须要恢复时执行全部的恢复操做(即校验数据页/purge undo/insert buffer merge/rolling back&forward),当不能进行有效的恢复操做时,mysql有可能没法启动,并记录错误日志;
innodb_force_recovery能够设置为1-6,大的数字包含前面全部数字的影响。当设置参数值大于0后,能够对表进行select,create,drop操做,但insert,update或者delete这类操做是不容许的。
通常修复方法参考:
第一种方法
创建一张新表:
create table demo_bak #和原表结构同样,只是把INNODB改为了MYISAM。
把数据导进去
insert into demo_bak select * from demo;
删除掉原表:
drop table demo;
注释掉 innodb_force_recovery 以后,重启。
重命名:
rename table demo_bak to demo;
最后改回存储引擎:
alter table demo engine = innodb
第二种方法
另外一个方法是使用mysqldump将表格导出,而后再导回到InnoDB表中。这两种方法的结果是相同的。
备份导出(包括结构和数据):
mysqldump -uroot -p123 test > test.sql
还原方法1:
use test;source test.sql
还原方法2(系统命令行):
mysql -uroot -p123 test < test.sql;
注意,CHECK TABLE命令在InnoDB数据库中基本上是没有用的。
第三种方法
(1)配置my.cnf
配置innodb_force_recovery = 1或2——6几个数字,重启MySQL
(2)导出数据脚本
mysqldump -uroot -p123 test > test.sql
导出SQL脚本。或者用Navicat将全部数据库/表导入到其余服务器的数据库中。
注意:这里的数据必定要备份成功。而后删除原数据库中的数据。
(3)删除ib_logfile0、ib_logfile一、ibdata1
备份MySQL数据目录下的ib_logfile0、ib_logfile一、ibdata1三个文件,而后将这三个文件删除
(4)配置my.cnf
将my.cnf中innodb_force_recovery = 1或2——6几个数字这行配置删除或者配置为innodb_force_recovery = 0,重启MySQL服务
(5)将数据导入MySQL数据库
mysql -uroot -p123 test < test.sql; 或者用Navicat将备份的数据导入到数据库中。
此种方法下要注意的问题:
这里,我使用的是第三种方法恢复了主数据库的数据。
接下来,咱们再来看看从数据库数据的恢复。
这里,我就简单的说下MySQL数据库的主从复制原理。
MySQL主从复制原理,也称为A/B原理。
(1) Master 将数据改变记录到二进制日志(binary log)中,也就是配置文件 log-bin 指定的文件, 这些记录叫作二进制日志事件(binary log events);
(2) Slave 经过 I/O 线程读取 Master 中的 binary log events 并写入到它的中继日志(relay log);
(3) Slave 重作中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完 成数据在本地的存储,从而实现将改变反映到它本身的数据(数据重放)。
复制过滤可让你只复制服务器中的一部分数据,有两种复制过滤:
(1) 在 Master 上过滤二进制日志中的事件;
(2) 在 Slave 上过滤中继日志中的事件。以下:
relay_log配置中继日志,log_slave_updates表示slave将复制事件 写进本身的二进制日志.当设置log_slave_updates时,你可让slave扮演其它slave的master.此时,slave把sql线程执行的事件写进本身的二进制日志(binary log)而后,它的slave能够获取这些事件并执行它。以下图所示(发送复制事件到其它的Slave):
恢复主库的数据后,向主库中插入了一批测试数据,大概有1000条,可是插入数据后,从库迟迟没有将数据同步过来。因而我先登陆主库,执行以下命令。
mysql>show processlist;
查看下进程是否Sleep太多。发现很正常。
再查看下主库的状态。
show master status;
也正常。
mysql> show master status; +-------------------+----------+--------------+-------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-------------------+----------+--------------+-------------------------------+ | mysqld-bin.000001 | 3260 | | mysql,test,information_schema | +-------------------+----------+--------------+-------------------------------+ 1 row in set (0.00 sec)
再到从库上查看从库的状态。
mysql> show slave status\G Slave_IO_Running: Yes Slave_SQL_Running: No
发现是Slave不一样步了。这里,若是主从数据库版本一致或不一致又会存在两种解决方案。
下面介绍两种解决方法
方法一:忽略错误后,继续同步
该方法适用于主从库数据相差不大,或者要求数据能够不彻底统一的状况,数据要求不严格的状况
解决:
stop slave; #表示跳过一步错误,后面的数字可变 set global sql_slave_skip_counter =1; start slave;
以后再用mysql> show slave status\G 查看
mysql> show slave status\G Slave_IO_Running: Yes Slave_SQL_Running: Yes
ok,如今主从同步状态正常了。。。
方式二:从新作主从,彻底同步
该方法适用于主从库数据相差较大,或者要求数据彻底统一的状况
解决步骤以下:
(1)先进入主库,进行锁表,防止数据写入
使用命令:
mysql> flush tables with read lock;
注意:该处是锁定为只读状态,语句不区分大小写
(2)进行数据备份
#把数据备份到mysql.bak.sql文件
mysqldump -uroot -p -hlocalhost > mysql.bak.sql
这里注意一点:数据库备份必定要按期进行,能够用shell脚本或者python脚本,都比较方便,确保数据万无一失。
(3)查看master 状态
mysql> show master status; +-------------------+----------+--------------+-------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-------------------+----------+--------------+-------------------------------+ | mysqld-bin.000001 | 3260 | | mysql,test,information_schema | +-------------------+----------+--------------+-------------------------------+ 1 row in set (0.00 sec)
(4)把mysql备份文件传到从库机器,进行数据恢复
scp mysql.bak.sql root@192.168.128.101:/tmp/
(5)中止从库的状态
mysql> stop slave;
(6)而后到从库执行mysql命令,导入数据备份
mysql> source /tmp/mysql.bak.sql
(7)设置从库同步,注意该处的同步点,就是主库show master status信息里的| File| Position两项
change master to master_host = '192.168.128.100', master_user = 'rsync', master_port=3306, master_password='', master_log_file = 'mysqld-bin.000001', master_log_pos=3260;
(8)从新开启从同步
mysql> start slave;
(9)查看同步状态
mysql> show slave status\G Slave_IO_Running: Yes Slave_SQL_Running: Yes
(10)回到主库并执行以下命令解除表锁定。
UNLOCK TABLES;
若是主从数据库的版本是一致的,以上述方式回复从数据库是没啥问题的,若是主从数据库版本不一致的话,以上述方式回复主从数据库可能还会存在问题。
若是MySQL主库和从库的版本不一致时,使用 show slave status \G
命令查看从库状态时可能会看到以下所示的信息。
Slave_IO_Running: Yes Slave_SQL_Running: No …… Last_Errno: 1755 Last_Error: Cannot execute the current event group in the parallel mode. Encountered event Gtid, relay-log name ./mysql-relay.000002, position 123321 which prevents execution of this event group in parallel mode. Reason: The master event is logically timestamped incorrectly...
注意以下的输出信息。
Last_Errno: 1755 Last_Error: Cannot execute the current event group in the parallel mode. Encountered event Gtid, relay-log name ./mysql-relay.000002, position 123321 which prevents execution of this event group in parallel mode. Reason: The master event is logically timestamped incorrectly...
这是因为主库使用的是MySQL5.6,从库使用的是MySQL5.7,数据库版本不一致引发的。
从MySQL官网搜索1755的报错看到是并行复制bug致使的报错。想要解决的办法也很简单,直接关掉并行复制便可。
stop slave; set global slave_parallel_workers=0; start slave;
若是从库仍是存在问题,则可按照主从版本一致的方案来恢复从库的数据。
这里,附加一个MySQL官方文档对于1755错误码的描述。
好了,今天就到这儿吧,我是冰河,你们有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,我拉你进群,一块儿交流技术,一块儿进阶,一块儿牛逼~~