乐趣区

关于mysql:在业务高峰期拔掉服务器电源是一种怎样的体验

写在后面

过后的我在里面玩的正起劲,忽然一个电话打来:“冰河,你在哪?服务器忽然不能拜访了!”。我:“又有什么状况啊?”。“我不小心踩到服务器电源连贯的插线板了,服务器断电了,重启时提醒无奈启动”。我心里一万个无语,问:”是哪台服务器断电了“。“我不小心踩到那个小插线板的开关了,连贯到这个插线板的服务器都断电了”。我:尼玛,那是数据库啊,我去。。。

于是我连忙飞奔回公司,开始了苦逼的数据恢复过程。。。

文章已收录到:

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 
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/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: 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 错误码的形容。

https://bugs.mysql.com/bug.ph…

好了,明天就到这儿吧,我是冰河,大家有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,我拉你进群,一起交换技术,一起进阶,一起牛逼~~

退出移动版