返回介绍

13.2 通过 Keepalived 搭建 MySQL 双主模式的高可用集群系统

发布于 2025-04-21 21:33:25 字数 12489 浏览 0 评论 0 收藏

13.2.1 MySQL Replication 介绍

MySQL Replication 是 MySQL 自身提供的一个主从复制功能,其实也就是一台 MySQL 服务器(称为 Slave)从另一台 MySQL 服务器(称为 Master)上复制日志,然后解析日志并应用到自身的过程。MySQL Replication 是单向、异步复制,基本复制过程为:Master 服务器首先将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志的循环。这些日志文件可以发送到 Slave 服务器进行更新。当一台 Slave 服务器连接 Master 服务器时,它从 Master 服务器日志中读取上一次成功更新的位置。然后 Slave 服务器开始接收从上一次完成更新后发生的所有更新,所有更新完成,将等待主服务器通知新的更新。

MySQL Replication 支持链式复制,也就是说 Slave 服务器下还可以再链接 Slave 服务器,同时 Slave 服务器也可以充当 Master 服务器角色。这里需要注意的是,在 MySQL 主从复制中,所有表的更新必须在 Master 服务器上进行,Slave 服务器仅能提供查询操作。

基于单向复制的 MySQL Replication 技术有如下优点:

- 增加了 MySQL 应用的健壮性,如果 Master 服务器出现问题,可以随时切换到 Slave 服务器,继续提供服务。

- 可以将 MySQL 读、写操作分离,写操作只在 Master 服务器完成,读操作可在多个 Slave 服务器上完成,由于 Master 服务器和 Slave 服务器是保持数据同步的,因此不会对前端业务系统产生影响。同时,通过读、写的分离,可以大大降低 MySQL 的运行负荷。

- 在网络环境较好,业务量不是很大的环境中,Slave 服务器同步数据非常快,基本可以达到实时同步,并且,Slave 服务器在同步过程中不会干扰 Master 服务器。

MySQL Replication 支持多种类型的复制方式,常见的有基于语句的复制、基于行的复制和混合类型的复制。下面分别进行介绍。

(1)基于语句的复制

MySQL 默认采用基于语句的复制,效率很高。基本方式是:在 Master 服务器上执行的 SQL 语句,在 Slave 服务器上再次执行同样的语句。而一旦发现没法精确复制时,会自动选择基于行的复制。

(2)基于行的复制

基本方式为:把 Master 服务器上改变的内容复制过去,而不是把 SQL 语句在从服务器上执行一遍,从 MySQL 5.0 开始支持基于行的复制。

(3)混合类型的复制

其实就是上面两种类型的组合,默认采用基于语句的复制,如果发现基于语句的复制无法精确完成,就会采用基于行的复制。

13.2.2 MySQL Replication 实现原理

MySQL Replication 是一个从 Master 复制到一台或多台 Slave 的异步过程,在 Master 与 Slave 之间实现整个复制过程主要由三个线程来完成,其中一个 IO 线程在 Master 端,另两个线程(SQL 线程和 IO 线程)在 Slave 端。

要实现 MySQL Replication,首先在 Master 服务器上打开 MySQL 的 Binary Log(产生二进制日志文件)功能,因为整个复制过程实际上就是 Slave 从 Master 端获取该日志,然后在自身上将二进制文件解析为 SQL 语句并完全顺序地执行 SQL 语句所记录的各种操作。更详细的过程如下。

1)首先 Slave 上的 IO 线程连接上 Master,然后请求从指定日志文件的指定位置或者从最开始的日志位置之后的日志内容。

2)Master 在接收到来自 Slave 的 IO 线程请求后,通过自身的 IO 线程,根据请求信息读取指定日志位置之后的日志信息,并返回给 Slave 端的 IO 线程。返回信息中除了日志所包含的信息之外,还包括此次返回的信息在 Master 端对应的 Binary Log 文件的名称以及在 Binary Log 中的位置。

3)Slave 的 IO 线程接收到信息后,将获取到的日志内容依次写入 Slave 端的 Relay Log 文件(类似于 mysql-relay-bin.xxxxxx)的最后,并且将读取到的 Master 端的 Binary Log 的文件名和位置记录到一个名为 master-info 的文件中,以便在下一次读取的时候能够迅速定位开始往后读取日志信息的位置。

4)Slave 的 SQL 线程在检测到 Relay Log 文件中新增加了内容后,会马上解析该 Relay Log 文件中的内容,将日志内容解析为 SQL 语句,然后在自身执行这些 SQL,由于是在 Master 端和 Slave 端执行了同样的 SQL 操作,所以两端的数据是完全一样的。至此整个复制过程结束。

13.2.3 MySQL Replication 常用架构

MySQL Replication 技术在实际应用中有多种实现架构,常见的有:

- 一主一从,即一台 Master 服务器和一台 Slave 服务器。这是最常见的架构。

- 一主多从,即一台 Master 服务器和两台或两台以上 Slave 服务器。经常用在写操作不频繁、查询量比较大的业务环境中。

- 主主互备,又称双主互备,即两台 MySQL Server 互相将对方作为自己的 Master,自己又同时作为对方的 Slave 来进行复制。主要用于对 MySQL 写操作要求比较高的环境中,避免了 MySQL 单点故障。在 13.2.5 节会重点介绍此种架构的实现方式。

- 双主多从,其实就是双主互备,然后再加上多台 Slave 服务器。主要用于对 MySQL 写操作要求比较高,同时查询量比较大的环境中。这种构架在 13.3 节会做更详细的介绍。

其实可以根据具体的情况灵活地将 Master/Slave 结构进行变化组合,但万变不离其宗,在进行 MySQL Replication 的各种部署之前,必须遵守的规则如下:

- 同一时刻只能有一台 Master 服务器进行写操作。

- 一台 Master 服务器可以有多台 Slave 服务器。

- 无论是 Master 服务器还是 Slave 服务器,都要确保各自的 Server ID 唯一,否则双主互备就会出问题。

- 一台 Slave 服务器可以将其从 Master 服务器获得的更新信息传递给其他的 Slave 服务器。依此类推。

13.2.4 MySQL 主主互备模式架构

企业级 MySQL 集群具备高可用、可扩展、易管理、低成本的特点。下面将介绍企业环境中经常应用的一个解决方案,即 MySQL 的双主互备架构,主要设计思路是通过 MySQL Replication 技术将两台 MySQL Server 互相将对方作为自己的 Master,自己又同时作为对方的 Slave 来进行复制。这样就实现了高可用架构中的数据同步功能,同时,将采用 Keepalived 来实现 MySQL 的自动 failover。在这种架构中,虽然两台 MySQL Server 互为主从,但同一时刻只有一台 MySQL Server 可读写,而另一台 MySQL Server 只能进行读操作,这样可保证数据的一致性。整个架构如图 13-1 所示。

在图 13-1 中,DB1 和 DB2 互为主从,这样就保证了两台 MySQL 的数据始终是同步的,同时在 DB1 和 DB2 上还需要安装高可用软件 Keepalived。在正常情况下,Web Server 主机仅从 DB1 进行数据的读、写操作,DB2 只负责从 DB1 同步数据。而 Keepalived 维护着一个 VIP,此 IP 用来对外提供连接服务,同时,Keepalived 还负责监控 DB1 和 DB2 上 MySQL 数据库的运行状态,当 DB1 主机出现故障或 MySQL 运行异常时,自动将 VIP 地址和 MySQL 服务切换到 DB2 上,此时 Web Server 主机继续从 DB2 进行数据的读、写操作。通过 Keepalived 保持了数据库服务的连续性,整个切换过程非常快,并且对前端 Web Server 主机是透明的。

图 13-1 MySQL 双主互备架构

13.2.5 MySQL 主主互备模式配置

MySQL 主从复制的配置还是比较简单的,仅仅需要修改 MySQL 配置文件即可,这里要配置的是主主互备模式,但配置过程和一主一从结构是完全一样的,配置环境如表 13-1 所示。

表 13-1 MySQL 主主互备模式配置环境

下面开始进入配置过程。

1.修改 MySQL 配置文件

在默认情况下,MySQL 的配置文件是/etc/my.cnf,首先修改 DB1 主机的配置文件,在/etc/my.cnf 文件中的“[mysqld]”段添加如下内容:

server-id = 1
log-bin=mysql-bin
relay-log = mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%

然后修改 DB2 主机的配置文件,在/etc/my.cnf 文件中的“[mysqld]”段添加如下内容:

server-id = 2
log-bin=mysql-bin
relay-log = mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%

其中,server-id 是节点标识,主、从节点不能相同,必须全局唯一。log-bin 表示开启 MySQL 的 binlog 日志功能。“mysql-bin”表示日志文件的命名格式,会生成文件名为 mysql-bin.000001、mysql-bin.000002 等的日志文件。relay-log 用来定义 relay-log 日志文件的命名格式。replicate-wild-ignore-table 是个复制过滤选项,可以过滤不需要复制的数据库或表,例如“mysql.%”表示不复制 MySQL 库下的所有对象,其他依此类推。与此对应的是 replicate_wild_do_table 选项,用来指定需要复制的数据库或表。

这里需要注意的是,不要在主库上使用 binlog-do-db 或 binlog-ignore-db 选项,也不要在从库上使用 replicate-do-db 或 replicate-ignore-db 选项,因为这样可能产生跨库更新失败的问题。推荐在从库上使用 replicate_wild_do_table 和 replicate-wild-ignore-table 两个选项来解决复制过滤问题。

2.手动同步数据库

如果 DB1 上已经有 MySQL 数据,那么在执行主主互备之前,需要将 DB1 和 DB2 上两个 MySQL 的数据保持同步,首先在 DB1 上备份 MySQL 数据,执行如下 SQL 语句:

mysql>FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)

不要退出这个终端,否则这个锁就失效了。在不退出终端的情况下,再开启一个终端直接打包压缩数据文件或使用 mysqldump 工具导出数据。这里通过打包 mysql 文件来完成数据的备份,操作过程如下:

[root@DB1 ~]# cd /var/lib/
[root@DB1 lib]# tar zcvf mysql.tar.gz mysql
[root@DB1 lib]# scp mysql.tar.gz  DB2:/var/lib/

将数据传输到 DB2 后,依次重启 DB1 和 DB2 上面的 MySQL。

3.创建复制用户并授权

首先在 DB1 的 MySQL 库中创建复制用户,操作过程如图 13-2 所示。

图 13-2 在 DB1 MySQL 库中创建复制用户

然后在 DB2 的 MySQL 库中将 DB1 设为自己的主服务器,操作过程如图 13-3 所示。

图 13-3 在 DB2 MySQL 库中将 DB1 设为主服务器

这里需要注意 master_log_file 和 master_log_pos 两个选项,这两个选项的值刚好是在 DB1 上通过 SQL 语句“show master status”查询到的结果。

接着就可以在 DB2 上启动 slave 服务了,可执行如下 SQL 命令:

mysql> start slave; 

下面查看 DB2 上 slave 的运行状态,如图 13-4 所示。

图 13-4 DB2 上 slave 的运行状态

通过查看 slave 的运行状态可以发现,一切运行正常,这里需要重点关注的是 Slave_IO_Running 和 Slave_SQL_Running,这两个就是在 Slave 节点上运行的主从复制线程,正常情况下这两个值都应该为 Yes。另外,还需要注意的是 Slave_IO_State、Master_Host、Master_Log_File、Read_Master_Log_Pos、Relay_Log_File、Relay_Log_Pos 和 Relay_Master_Log_File 几个选项,从图中可以查看出 MySQL 复制的运行原理及执行规律。最后还有一个 Replicate_Wild_Ignore_Table 选项,这个是之前在 my.cnf 中添加过的,通过此选项的输出值可以知道过滤了哪些数据库。

到这里,从 DB1 到 DB2 的 MySQL 主从复制已经完成。接下来开始配置从 DB2 到 DB1 的 MySQL 主从复制,这个配置过程与上面的过程完全一样,首先在 DB2 的 MySQL 库中创建复制用户,操作如图 13-5 所示。

图 13-5 在 DB2 MySQL 库中创建复制用户

然后在 DB1 的 MySQL 库中将 DB2 设为自己的主服务器,操作如图 13-6 所示。

图 13-6 在 DB1 MySQL 库中将 DB2 设为主服务器

最后,就可以在 DB1 上启动 slave 服务了,可执行如下 SQL 命令:

mysql> start slave; 

下面查看下 DB1 上 slave 的运行状态,如图 13-7 所示。

从图 13-7 中可以看出 Slave_IO_Running 和 Slave_SQL_Running 都是 Yes 状态,表明 DB1 上复制服务运行正常。至此,MySQL 双主模式的主从复制配置完毕。

13.2.6 配置 Keepalived 实现 MySQL 双主高可用

在进行高可用配置之前,首先需要在 DB1 和 DB2 服务器上安装 Keepalived 软件。Keepalived 在前面章节中已经做过详细介绍,关于 Keepalived 的安装这里不再说明,直接进入 Keepalived 的配置过程。下面是 DB1 服务器上/etc/keepalived/keepalived.conf 文件的内容。

图 13-7 DB1 上 slave 的运行状态

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id MySQLHA_DEVEL
}
vrrp_script check_mysqld {
    script "/etc/keepalived/mysqlcheck/check_slave.pl 127.0.0.1" #
检测 MySQL
复制状态的脚本
    interval 2
    weight 21
    }
vrrp_instance HA_1 {
    state BACKUP        #
在 DB1
和 DB2
上均配置为 BACKUP
    interface eth0
    virtual_router_id 80
    priority 100
    advert_int 2
    nopreempt           #
不抢占模式,只在优先级高的机器上设置即可,优先级低的机器可不设置
    authentication {
        auth_type PASS
        auth_pass qweasdzxc
    }
    track_script {
    check_mysqld
    }
    virtual_ipaddress {
        192.168.88.10/24 dev eth0       #MySQL
的对外服务 IP
,即 VIP
    }
}

其中,/etc/keepalived/mysqlcheck/check_slave.pl 文件的内容为:

#!/usr/bin/perl -w
use DBI;
use DBD::mysql;
# CONFIG VARIABLES
$SBM = 120;
$db = "ixdba";
$host = $ARGV[0];
$port = 3306;
$user = "root";
$pw = "xxxxxx";
# SQL query
$query = "show slave status";
$dbh = DBI->connect("DBI:mysql:$db:$host:$port", 
$user, $pw, { RaiseError => 
0,PrintError => 0 }); 
if (!defined($dbh)) {
    exit 1;
} 
$sqlQuery = $dbh->prepare($query); 
$sqlQuery->execute;
$Slave_IO_Running =  ""; 
$Slave_SQL_Running = ""; 
$Seconds_Behind_Master = ""; 
while (my $ref = $sqlQuery->fetchrow_hashref()) {
    $Slave_IO_Running = $ref->{'Slave_IO_Running'};
    $Slave_SQL_Running = $ref->{'Slave_SQL_Running'};
    $Seconds_Behind_Master = $ref->{'Seconds_Behind_Master'};
}
$sqlQuery->finish;
$dbh->disconnect();
if ( $Slave_IO_Running eq "No" || $Slave_SQL_Running eq "No" ) {
    exit 1;
} else {
    if ( $Seconds_Behind_Master > $SBM ) {
        exit 1;
    } else {
        exit 0;
    }
}

这是用 Perl 写的检测 MySQL 复制状态的脚本,只需修改文件中 MySQL 数据库的端口、用户名和密码即可直接使用,但在使用前要保证此脚本有可执行权限。

接着将 keepalived.conf 文件和 check_slave.pl 文件复制到 DB2 服务器上对应的位置,然后将 keepalived.conf 文件中 priority 值修改为 90。由于配置的是不抢占模式,因此,还需要去掉 nopreempt 选项。

在完成所有配置后,分别在 DB1 和 DB2 上启动 keepalived 服务,在正常情况下 VIP 地址应该运行在 DB1 服务器上。

13.2.7 测试 MySQL 主从同步功能

为了验证 MySQL 的复制功能,可以编写一个简单的程序进行测试,也可以通过远程客户端登录进行测试。这里通过一个远程 MySQL 客户端,然后利用 MySQL 的 VIP 地址登录,看能否登录,并在登录后进行读、写操作,看看 DB1 和 DB2 之间能否实现数据同步。由于采用远程登录测试,因此 DB1 和 DB2 两台 MySQL 服务器都要事先做好授权,允许从远程登录。

1.在远程客户端通过 VIP 登录测试

首先通过远程 MySQL 客户端命令行登录 VIP 为“192.168.88.10”的数据库,操作过程如图 13-8 所示。

图 13-8 MySQL 远程客户端 VIP 登录测试

从 SQL 输出结果看,可以通过 VIP 登录,并且登录了 DB1 服务器。

2.数据复制功能测试

接着上面的 SQL 操作过程,通过远程的 MySQL 客户端连接 VIP,进行读、写操作测试,操作过程如图 13-9 所示。

图 13-9 向 DB1 数据库中插入数据

这个过程创建了一个数据库 repldb,然后在 repldb 库中创建了一张表 repl_table。为了验证数据是否复制到 DB2 主机上,登录 DB2 主机的 MySQL 命令行,查询过程如图 13-10 所示。

图 13-10 在 DB2 数据库中查询数据是否已经同步

从 SQL 输出结果看,刚才创建的库和表都已经同步到了 DB2 服务器上。其实也可以直接登录 DB2 服务器,然后执行数据库的读、写操作,看数据能否迅速同步到 DB1 的 MySQL 数据库中。测试过程与前面的完全一样,这里不再重复介绍。

13.2.8 测试 Keepalived 实现 MySQL 故障转移

为了测试 Keepalived 实现的故障转移功能,需要模拟一些故障,比如,可以通过断开 DB1 主机的网络、关闭 DB1 主机、关闭 DB1 上 MySQL 服务等各种操作实现。这里在 DB1 服务器上关闭 MySQL 的日志接收功能,以此来模拟 DB1 上 MySQL 的故障。由于在 DB1 和 DB2 服务器上都添加了监控 MySQL 运行状态的脚本 check_slave.pl,因此当关闭 DB1 的 MySQL 日志接收功能后,Keepalived 会立刻检测到,接着执行切换操作。测试过程如下。

1.停止 DB1 服务器的日志接收功能

首先在远程 MySQL 客户端以 VIP 地址登录 MySQL 系统,不要退出这个连接,然后在 DB1 服务器的 MySQL 命令行执行如下操作:

mysql> slave stop
;

2.在远程客户端测试

继续在刚才打开的远程 MySQL 连接中执行命令,操作过程如图 13-11 所示。

图 13-11 通过 Keepalived 实现 MySQL 故障转移测试

从这个操作过程可以看出,在 Keepalived 切换后,之前的 session 连接失效,所以第一个查询命令失败。然后重新执行查询命令,MySQL 会执行重新连接,随后输出了查询结果,从后面两个 SQL 的查询结果可知,MySQL 服务已经从 DB1 服务器切换到 DB2 服务器。Keepalived 的切换过程非常迅速,整个过程大概持续 1~3s,重新切换到新的服务器后,之前所有的 MySQL 连接失效,重新连接可以恢复正常。

接着,重新打开 DB1 上 MySQL 的日志接收功能,可以发现 Keepalived 将不再执行切换操作,因为上面将 Keepalived 配置为不抢占模式,此时,MySQL 服务将一直在 DB2 服务器上运行,直到 DB2 主机或服务出现故障才再次进行切换操作。这样做的原因是在数据库环境下,每次切换的代价很大,因而关闭了 Keepalived 的主动抢占模式。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。