Mysql复制指南(二)

故障演练

主备架构使得数据有所冗余,当灾难来临时起码有一份完整的数据可供恢复。经常做故障演练是非常有必要的。
接下来演练一种复杂的场景:一主多从的情况下当主库宕机时,如何进行主备切换

故障场景

image.png

假设有一组1主2备的Mysql集群,主节点Server1的binlog偏移量从旧到新1450、1493、1582。此时主节点突然宕机后:

  • Server2同步到的最新日志偏移量是1582,即与主节点Sever1同步。
  • Server3由于性能或网络原因,同步稍稍延迟了一个偏移量,于是Server3同步到的最新日志偏移量是1493

故障还原

我们来尝试还原故障场景。分几个步骤:

  1. 按照 Mysql复制指南(一) 配置一套1主2备的Mysql集群。
  2. 先在主库创建测试库、测试表和测试数据:
CREATE DATABASE `foo`;
USE `foo`;
CREATE TABLE `bar` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `nick_name` varchar(20) NOT NULL DEFAULT '',
  `last_login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_login_time` (`last_login_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bar` (`nick_name`) VALUES ('ted');

随后确认一下备1、备2是否也同步创建了。

  1. 此时我们将备2暂停复制,用来模拟主库奔溃后Server2复制偏移量落后的场景。在备2执行:
STOP SLAVE;
  1. 我们在主库继续插入一条:
INSERT INTO `bar` (`nick_name`) VALUES ('stone');
  1. 关闭主库,模拟主库宕机:
$ bin/mysqladmin --socket=/tmp/mysql.sock -u root -p shutdown

故障场景还原完成

  • 主库Server1宕机(关闭)。
  • 备1Server2保持最新的复制同步。
  • 备2Server3落后一条语句。

处理方案

正常思路是先想办法重新启动Server1,如果能重新启动,那么集群又能恢复健康。但如果很不幸Server1短时间内无法恢复,那就不得不抛弃主库,提升一台备库为新主库,同时将其他备库指向新主库并开始复制。

故障处理

在处理故障之前,我们必须先制定计划。

提升哪台备库为主库?

假设我们不知道哪台备库的复制进度比较新,我们通过show slave status查看:

server master_binlog 偏移量 最新
Server2 mysql-bin.000007 4629
Server3 mysql-bin.000007 4362

因此我们提升Server2为主库。

提升新主库后,其他备库指向新主库时的binlog文件和偏移量应该是多少?

Server2成为主库后,Server3需要指向Server2的binlog文件。那偏移量应该设多少?
有一件事必须清楚那就是同一条语句在Server2binlog文件里的偏移量与Server1是完全不同的,虽然每台机器的数据都在以相同的语句同步,但彼此的binlog和偏移量都可能不一样。
最可靠的方法是找出故障时Server3最新的复制偏移量语句,找出该语句在Server2的binlog位置。我们用mysqlbinlog工具试一下:
先找到故障时Server3最新的复制偏移量语句,即主库下的mysql-bin.0000074362

$ mysqlbinlog mysql-bin.000007 -vvv | less

image.png

然后找Server2下该语句的位置,即备1下的mysql-bin.000009

$ mysqlbinlog mysql-bin.000009 -vvv | less

image.png

我这里是1354
至此故障处理计划出炉:

  1. Server2提升为主库。
  2. Server3的复制源指向Server2,binlog为mysql-bin.000009、偏移量为1354

实施计划

Server2提升为主库。

更改Server2配置文件,将read_only=1注释掉,然后重启Server2

$ vim /usr/local/mysql2/etc/my.cnf
# read_only=1

重启Server2

$ bin/mysqladmin -h 127.0.0.1 -P 3307 -u root -p shutdown
$ bin/mysqld_safe --defaults-file=/usr/local/mysql2/etc/my.cnf &
Server3配置新的复制源并启动复制。
mysql> STOP SLAVE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CHANGE MASTER TO MASTER_HOST='127.0.0.1',
    -> MASTER_PORT=3307,
    -> MASTER_LOG_FILE='mysql-bin.000009',
    -> MASTER_LOG_POS=1354;
Query OK, 0 rows affected (0.10 sec)

mysql> START SLAVE;
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: repl
                  Master_Port: 3307
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
            ...

此时在Server2插入的数据已经能在Server3下看到了,快动手试试吧!

总结

对于单主架构的Mysql集群,一旦主节点发生故障,要做非计划性的备库提升是件很麻烦的事,有大量的人工操作成本。它无法像zookeeper、elasticsearch、mongodb那样当识别到主节点(或主分片)失联后自动通过广播选举机制来选出新的主节点(或主分片)。
但辩证思考一下,开箱即用的提升特性会降低定制化能力,减小人工干预的口子。Mysql这样的复制方式反而能玩出非常多样化的拓扑结构以达到不同目的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 9,333评论 0 5
  • 本篇就一下方面展开分析 如何使用主从复制? 主从复制的原理(重点是全量复制和部分复制、以及心跳机制) 实际应用中需...
    lucode阅读 4,574评论 0 5
  • redis集群分为服务端集群和客户端分片,redis3.0以上版本实现了集群机制,即服务端集群,3.0以下使用客户...
    hadoop_null阅读 5,485评论 0 6
  • 一、Redis主从复制 主从复制:主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性...
    爱情小傻蛋阅读 4,587评论 0 0
  • Valentine 转载请标明出处。 Zookeeper的由来 1、各个节点的数据一致性;2、怎么保证任务只在一个...
    valentine_liang阅读 4,750评论 2 10