写在后面
过后的我在里面玩的正起劲,忽然一个电话打来:“冰河,你在哪?服务器忽然不能拜访了!”。我:“又有什么状况啊?”。“我不小心踩到服务器电源连贯的插线板了,服务器断电了,重启时提醒无奈启动”。我心里一万个无语,问:”是哪台服务器断电了“。“我不小心踩到那个小插线板的开关了,连贯到这个插线板的服务器都断电了”。我:尼玛,那是数据库啊,我去。。。
于是我连忙飞奔回公司,开始了苦逼的数据恢复过程。。。
文章已收录到:
https://github.com/sunshinelyz/technology-binghe
https://gitee.com/binghe001/technology-binghe
解决主库问题
主库问题重现
回到公司一看,断电的是公司的音讯服务子系统数据库,数据库共3台,一种两从,并采纳了分库分表的形式存储数据。我首先把三台服务器启动好,发现主数据库的过程无奈启动,两台从数据库同步主库数据的状态异样。依照程序,我先看主数据库的日志信息,发现MySQL的谬误日志中输入了如下信息。
-----------------------------------------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 7478d078000000050000000000000000000000000f271f4d000700000000000000000000000000000000001b4000000000000000000200f20000000000000006000000000000002d000000000000002e000000000000002f0000000000000030000000000(省略很多相似代码)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_count=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/refm... [mysqld]字段下,增加 innodb_force_recovery=1:
[mysqld]innodb_force_recovery = 1
如果innodb_force_recovery = 1不失效,则可尝试2——6几个数字
而后重启mysql,重启胜利。而后应用mysqldump或 pma 导出数据,执行修复操作等。修复实现后,把该参数正文掉,还原默认值0。
配置文件的参数:innodb_force_recovery
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这类操作是不容许的。
- (SRV_FORCE_IGNORE_CORRUPT):疏忽查看到的corrupt页。
- (SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程须要执行full purge操作,会导致crash。
- (SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
- (SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
- (SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
- (SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。
主库解决方案
个别修复办法参考:
第一种办法
建设一张新表:
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_logfile1、ibdata1
备份MySQL数据目录下的ib_logfile0、ib_logfile1、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将备份的数据导入到数据库中。
此种办法下要留神的问题:
- ib_logfile0、ib_logfile1、ibdata1这三个文件肯定要先备份后删除;
- 肯定要确认原数据导出胜利了
- 当数据导出胜利后,删除原数据库中的数据时,如果提醒不能删除,可在命令行进入MySQL的数据目录,手动删除相干数据库的文件夹或者数据库文件夹下的数据表文件,前提是数据肯定导出或备份胜利。
这里,我应用的是第三种办法复原了主数据库的数据。
接下来,咱们再来看看从数据库数据的复原。
解决从库问题
主从复制原理
这里,我就简略的说下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: YesSlave_SQL_Running: No
发现是Slave不同步了。这里,如果主从数据库版本统一或不统一又会存在两种解决方案。
主从版本统一解决方案
上面介绍两种解决办法
办法一:疏忽谬误后,持续同步
该办法实用于主从库数据相差不大,或者要求数据能够不齐全对立的状况,数据要求不严格的状况
解决:
stop slave; #示意跳过一步谬误,前面的数字可变set global sql_slave_skip_counter =1;start slave;
之后再用mysql> show slave status\G 查看
mysql> show slave status\GSlave_IO_Running: YesSlave_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: YesSlave_SQL_Running: Yes
(10)回到主库并执行如下命令解除表锁定。
UNLOCK TABLES;
如果主从数据库的版本是统一的,以上述形式回复从数据库是没啥问题的,如果主从数据库版本不统一的话,以上述形式回复主从数据库可能还会存在问题。
主从版本不统一解决方案
如果MySQL主库和从库的版本不统一时,应用 show slave status \G
命令查看从库状态时可能会看到如下所示的信息。
Slave_IO_Running: YesSlave_SQL_Running: No……Last_Errno: 1755Last_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: 1755Last_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错误码的形容。
https://bugs.mysql.com/bug.ph...
好了,明天就到这儿吧,我是冰河,大家有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,我拉你进群,一起交换技术,一起进阶,一起牛逼~~