mariadb/mysql 主从架构
mariadb/mysql 主从架构(主从复制、双主复制、半同步复制)
- mysql主从复制原理
- 项目一 主从复制
- 项目二 主主复制
- 项目三 半同步复制
MySQL主从复制原理介绍
MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个Mysql数据库(我们称之为Master)复制到另一个Mysql数据库(我们称之为Slave),在Master与Slave之间实现整个主从复制的过程是由三个线程参与完成的。其中有两个线程(SQL线程和IO线程)在Slave端,另一个线程(I/O线程)在Master端。
要实现MySQL的主从复制,首先必须打开Master端的binlog记录功能,否则就无法实现。因为整个复制过程实际上就是Slave从aster端获取binlog日志,然后再在Slave上以相同顺序执行获取的binlog日志中的记录的各种SQL操作
1)在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。
2)此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行binlog日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change
master命令指定的)之后开始发送binlog日志内容
3)Master服务器接收到来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了binlog中的下一个指定更新位置。
4)当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(Mysql-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容
5)Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点
项目一 主从复制
主从复制要点概况
- 保证各服务器节点时间同步,可参考[时间同步设置方案](http://www.longma.tk/? p=629 "时间同步设置方案")
- 确保server_id不一样 ,主节点开启二进制日志,从节点开启中继日志从节点授权一个账号来完成复制
- 主从复制的开始位置:
- 从服务器从0开始复制?: 如果跑了好几年我们不建议从0恢复,建议使用备份+从指定的二进制日志位置向后复制
-
主从服务器mysqld程序版本不一致? 建议一致,从的版本号高于主的版本号,一般高版本兼容低版本
环境介绍
node1:172.18.43.8 ,Centos7, MariaDB-5.5.44
node2:172.18.43.88 ,Centos7, MariaDB-5.5.44
主服务器node1配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON #默认mysql会反解ip,跳过域名解析
innodb_file_per_table=ON #innodb数据每表一个文件,方便出现故障容易维护
server_id=1
log_bin=mysql-bin #开启二进制日志
systemctl start mariadb.service #从节点设置完server.conf参数以后启动
**授权可复制用户**
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'172.18.43.%' IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;
mysql> SHOW MASTER STAUS; #查看此时二进制日志的位置 让我们的从服务器从这里开始运行二进制日志
|
从服务器node2配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
配置文件vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
server_id=2
relay_log=relay-log
systemctl start mariadb.service
ls /var/lib/mysql #此时还没有中继日志,因为还没有数据复制过来,
复制指向主节点
mysql> CHANGE MASTER TO MASTER_HOST='172.18.43.8',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=#;
#MASTER_LOG_POS=#; #去主节点show master status查看
mysql> SHOW SLAVE STATUS\G; #可以看到主节点的信息,以及io_thread和sql_thread的状态
mysql> START SLAVE IO_THREAD; #启动IO线程
mysql> START SLAVE SQL_THREAD; #启动SQL线程
mysql> SHOW SLAVE STATUS\G; #看线程是否都启动
|
测试主从复制是否成功
1
2
3
4
5
6
7
8
9
10
11
12
13
|
node1:
mysql>CREATE DATABASE mydb;
mysql>SHOW MASTER STATUS; #查看二进制日志是否变化
mysql>use mydb;
mysql>CREATE TABLE tbl1 (id INT UNSIGNED NOT NULL, name VARCHAR(20));
mysql>INSERT INTO tbl1 (name) VALUES ('obama'),('xiaoqiang');
node2:
mysql>SHOW SLAVE STATUS; #查看postion
mysql>SHOW DATABASES; #看是否有mydb ;
|
复制时应该注意的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
1、从服务设定为“只读”;
在从服务器启动read_only,但仅对非SUPER权限的用户有效;
阻止所有用户:
mysql> FLUSH TABLES WITH READ LOCK;
2、尽量确保复制时的事务安全
默认事务提交commit以后 会存储在二进制日志内存缓冲区内,并不会立即同步到二进制日志,只有在缓冲区写到二进制日志 才会写到磁盘上,假如此时坏了,该段数据是没有的,sync_binlog=ON;表示只有有事务提交就同步到二进制日志上,即使此时坏掉,二进制日志
也有语句,这样事务不会丢失,但是IO会受影响
在master节点启用参数:
sync_binlog = ON
如果用到的是InnoDB存储引擎: #这两项默认是开启的不用管
innodb_flush_logs_at_trx_commit=ON #在事务提交时刷写日志
innodb_support_xa=ON
3、从服务器意外中止时尽量避免自动启动复制线程,崩溃了下次启动以后有可能造成数据不一致,应该人工检测一下从哪个位置开始
复制
node2: systemctl stop mariadb
node1: drop database mydb;
node2: systemctl start mariadb
SHOW SLAVE STATUS; 发现自动连接到主服务器复制
4、从节点:设置参数 ,保证复制是一致和安全的,但是IO也会影响
sync_master_info=ON
sync_relay_log_info=ON
|
项目二 主主复制
主主复制要点概况(实验步骤已经包含)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
1. 数据不一致;
2. 自动增长id;
定义一个节点使用奇数id
auto_increment_offset=1
auto_increment_increment=2
另一个节点使用偶数id
auto_increment_offset=2
auto_increment_increment=2
配置:
1、server_id必须要使用不同值;
2、双主实际就是各方互为主从,均启用binlog和relay log;
3、存在自动增长id的表,为了使得id不相冲突,需要定义其自动增长方式;一个节点使用1357一个节点使用2468
服务启动后执行如下两步:
4、都授权有复制权限的用户账号;
5、各把对方指定为主节点;
|
环境介绍
node1:172.18.43.8 ,Centos7, MariaDB-5.5.44
node2:172.18.43.88 ,Centos7, MariaDB-5.5.44
- 保证各服务器节点时间同步,可参考[时间同步设置方案](http://www.longma.tk/? p=629 "时间同步设置方案")
-
初始化环境 node1和 node2 #为保证不受其它实验干扰,建议恢复至初始状态,新装的mariadb即可,不要有其它实验项目干扰
主服务器node1配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
配置文件vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
server_id=1
log_bin=mysql-bin
relay_log=relay-log
auto_increment_offset=1
auto_increment_increment=2
systemctl start mariadb; #node1与node2都完成各自配置后进行下面步骤
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'172.18.43.%' IDENTIFIED BY 'replpass'; #同时node2也需要执行
mysql> FLUSH PRIVILEGES;
mysql> SHOW MASTER STATUS;
mysql> CHANGE MASTER TO MASTER_HOST='172.18.43.88',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=#;
#注意这里的HOST指向另一个主节点,而且POS也是对方的
mysql> SHOW SLVAE STATUS\G;
mysql> START SLAVE; #启动IO和SQL两个线程
mysql> SHOW SLVAE STATUS\G; #确保IO 和sql两个线程已经为YES
|
从服务器node2配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
配置文件vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
server_id=2
log_bin=mysql-bin
relay_log=relay-log
auto_increment_offset=2
auto_increment_increment=2
systemctl start mariadb;
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'172.18.43.%' IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;
mysql> SHOW MASTER STATUS;
mysql> CHANGE MASTER TO MASTER_HOST='172.18.43.8',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=#;
#注意这里的HOST指向另一个主节点,而且POS也是对方的
mysql> SHOW SLVAE STATUS\G;
mysql> START SLAVE; #启动IO和SQL两个线程
mysql> SHOW SLVAE STATUS\G; #确保IO 和sql两个线程已经为YES
|
测试双主复制是否成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mysql> CREATE DATABASE mydb CHARACTER SET 'utf8'; #node1上创建
mysql> SHOW MASTER STATUS; #node1 查看position
mysql> SHOW SLAVE STATUS; #node2 查看position
mysql> SHOW DATABASES; #node2
node2上创建表
mysql> use mydb;
mysql> CREATE TABLE tbl1 (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100));
mysql> SHOW MASTER STATUS;
mysql> SHOW SLAVE STATUS; #去node1查看是否同步
SHOW TABLES;
INSERT INTO tbl1 (name) VALUES ('user1'),('user2'); #然后去node2查看是否同步
mysql> INSERT INTO tbl1 (name) VALUES ('user3'),('user4'); #node2插入,然后查看node1是否同步
mysql> SELECT * FROM tbl1; #查看一下id的奇数偶数关系
|
项目三 半同步复制
早前的MySQL复制只能是基于异步来实现,从MySQL-5.5开始,支持半自动复制。在以前的异步(asynchronous)复制中,主库在执行完一些事务后,是不会管备库的进度的。如果备库处于落后,而更不幸的是主库此时又出现Crash(例如宕机),这时备库中的数据就是不完整的。简而言之,在主库发生故障的时候,我们无法使用备库来继续提供数据一致的服务了。Semisynchronous Replication(半同步复制)则一定程度上保证提交的事务已经传给了至少一个备库。Semi synchronous中,仅仅保证事务的已经传递到备库上,但是并不确保已经在备库上执行完成了。
此外,还有一种情况会导致主备数据不一致。在某个session中,主库上提交一个事务后,会等待事务传递给至少一个备库,如果在这个等待过程中主库Crash,那么也可能备库和主库不一致,这是很致命的。如果主备网络故障或者备库挂了,主库在事务提交后等待10秒
(rpl_semi_sync_master_timeout的默认值)后,就会继续。这时,主库就会变回原来的异步状态。MySQL在加载并开启Semi-sync插件后,每一个事务需等待备库接收日志后才返回给客户端。如果做的是小事务,两台主机的延迟又较小,则Semi-sync可以实现在性能很小损失的情况下的零数据丢失。
半同步复制要点概况(实验步骤已经包含)
1
2
3
4
5
6
7
8
9
10
11
|
半同步复制 (依赖于谷歌给mariadb提供的插件)
支持多种插件:/usr/lib64/mysql/plugins/
需要安装方可使用:
mysql> SHOW PLUGINS; #显示已经安装的插件
mysql> INSTALL PLUGIN plugin_name SONAME
'shared_library_name'; #找到我们需要的插件的名字,这里是总结名字,不是真正插件名字,具体看配置步骤
半同步复制:
semisync_master.so #半同步主节点用的
semisync_slave.so #只是需要同步的那一个节点安装,其它节点不安装
|
环境介绍
node1:172.18.43.8 ,Centos7, MariaDB-5.5.44
node2:172.18.43.88 ,Centos7, MariaDB-5.5.44
- 保证各服务器节点时间同步,可参考[时间同步设置方案](http://www.longma.tk/? p=629 "时间同步设置方案")
-
初始化环境 node1和 node2 #为保证不受其它实验干扰,建议恢复至初始状态,新装的mariadb即可,不要有其它实验项目干扰
主服务器node1配置:
1
2
3
4
5
6
7
8
9
10
11
|
配置文件vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
server_id=1
log_bin=mysql-bin
systemctl start mariadb.service
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'172.18.43.%' IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;
|
从服务器node2配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
配置文件vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
server_id=2
relay_log=relay-log
systemctl start mariadb.service
mysql> CHANGE MASTER TO MASTER_HOST='172.18.43.8',MASTER_USER='repluser',MASTER_PASSWORD='replpass'
,MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=#;
#MASTER_LOG_POS=#; #去主节点show master status查看
mysql> START SLAVE; #启动IO和SQL两个线程
|
主服务器从服务器配置完成以后验证一下主从复制:
1
2
3
|
Node1: CREATE DATABASES mydb;
Node2: SHOW DATABASES; #确定数据库是否可以复制,此时主从复制完成
|
半同步配置:
主节点Node1配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<br />mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> SHOW PLUGINS; #确定安装完成
mysql> MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 | #单位毫秒,等待从节点超时时长
| rpl_semi_sync_master_trace_level | 32 | #定义日志级别
| rpl_semi_sync_master_wait_no_slave | ON | # 没有从节点要不要等待
+------------------------------------+-------+
mysql> SET GLOBAL rpl_semi_sync_master_enabled=ON;
mysql> SHOW GLOBAL STATUS LIKE '%semi%'; #发下同步客户端还是0,需要重启从节点的IO_THREAD,默认是异步
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 987 |
| Rpl_semi_sync_master_net_wait_time | 987 |
| Rpl_semi_sync_master_net_waits | 1 |
|
从节点Node2配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SHOW PLUGINS; #确定安装完成
mysql> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
mysql> SET GLOBAL rpl_semi_sync_slave_enabled=ON;
mysql> STOP SLAVE IO_THREAD;
mysql> START SLAVE IO_THREAD;
|
测试半同步复制是否成功
1
2
3
4
5
|
mysql> use mydb;
mysql> CREATE TABLE tbl1 (id INT,name VARCHAR(100)); #主节点创建表
mysql> SHOW GLOBAL STATUS LIKE '%semi%'
mysql> SHOW TABLES; #然后去从节点查看 表是否生成
|