文章内容概览
主从复制的作用
复制工作流程
复制时应该注意的问题
主从复制配置
半同步复制配置
复制过滤器方法说明和配置
双主(主主复制)配置
操作系统:
[root@master ~]# cat/etc/redhat-release CentOS release 6.6 (Final) [root@node2 ~]# uname -r 2.6.32-504.el6.x86_64 [root@node2 ~]# uname -m x86_64
数据库软件:
mariadb-5.5.43-linux-x86_64.tar.gz
ip地址:
master:172.16.4.136
slave:172.16.4.10
Mysql主从复制是mysql集群的基础,在mysql集群中为了保证数据的一致型,需要在mysql集群前端添加读写分离器,只将写入操作交给指定节点写入数据,这个节点就是主节点;将读操作交给集群中其他不执行写入操作的节点,这个节点就是从节点,那么从节点的数据从那里来?就是复制主节点的上面的数据,复制原理下文中有图文说明。
数据分布:能够将数据分散到多个位置,可以实现异地灾备
负载均衡:读操作,适用于读密集型的应用
备份:备份的时候可以停止从节点进行备份,备份更安全
高可用和故障切换:主节点故障,可以将从节点提升为主节点(需要手动实现,或者脚本监控实现,不如corosync或者heartbeat之类高可用方案)
MySQL升级测试:高版本数据库通过复制获得数据,然后进行测试
对第4、5、6步就是有两个,你没有看错,我没有画错
1、用户向主节点数据库写入数据
2、主节点将所有引起数据库更改的语句记录到bin-log日志文件中
3、从库的IO进程,不停的发送信息询问主库是否有数据更新,发送请求之前会读取master.info文件,获取上次记录的pos位置和连接主库的用户名和密码
4、主库IO线程收到从库请求,拿从库上次记录主库的pos点和主库bin-log日志当前记录的pos点进行对比,如果主库pos点的数值大于从库上次记录的pos点,就说明数据发生改变,发送bin-log的更新内容给从库;如果主库pos点的数值等于从库上次记录的pos点,说明数据没有更改,则继续接收从库请求,进行判断
5、从库IO线程收到主库的更新内容,将pos的更新信息记录到master.info文件中,下次从库在请求主库更新则是从当前记录的pos位置开始;并且将主库更新的SQL语句记录到relay-log日志文件中。
6、SQL线程从relay log中读取日志信息,在本地完成重放;(此时从库更新完成)
7、将所有引起从库更改的语句记录到从库的bin-log日志文件中;由于bin-log日志主要是用于数据恢复,并且在主库已经存在所以在从库开启会占用不必要的性能开销,推荐关闭。
主节点运行很长时间,且已经有一定规模的数据,如何启动复制?
解决方法:在主节点做一个完全备份,并记录二进制日志文件及位置;在从节点恢复此完全备份,并在启动复制时从记录的二进制日志文件和位置开始;
在从服务器启动read_only;但仅对非具有SUPER权限的用户有效;
阻止所有用户 :MariaDB> FLUSH TABLES WITH READ LOCK;
二进制日志默认在内存中会有缓冲,当一个事务提交的时候,这个数据就会被持久的存储到innodb文件中去了,但是和这个事务相关的二进制日志有可能还在内存中,所以从服务器是无法找到这种二进制日志的,所以需要尽可能做到一旦事务提交了,就立即把相关的二进制日志保存到硬盘中,以保证事务安全。
在master节点启用参数:
sync_binlog= on #同步二进制日志,一旦事务提交则立马将内存中的二进制日志文件同步到磁盘
如果用到的为InnoDB存储引擎:
innodb_flush_logs_at_trx_commit #innodb一旦在事务提交时立即将日志文件写入到磁盘
innodb_support_xa=on #支持分布式事务
在slave节点:
1、最好不要将relay-log日志和数据文件放到同一个磁盘
2、跳过slave的自动启动功能
启动了复制功能的从节点,如果从节点的mysql服务被关闭在启动之后slave线程是自动启动的,但是复制数据的位置有可能不是我们期望的位置,最好关闭slave的自启动功能,有运维人员手动启动,以免造成数据不一致,关闭命令如下:
skip_slave_start
不考虑磁盘IO的请求下,可以启动如下选项:
主节点:
sync_master_info= 1
从节点
sync_relay_log= 1
sync_relay_log_info= 1
(1) 启用二进制日志;
(2) 设置一个在当前集群中惟一的server-id;
二进制日志,在Mariadb安装完成之后默认就是启动的,这里只是将mysql-bin改为了master-bin当然不改也是可以的,另外server-id的选项也是默认的,这里并没有修改。
[root@master ~]# vim /etc/my.cnf log-bin=master-bin server-id = 1
设置完成之后重启服务生效,并验证二进制日志文件是否更改为master-bin
[root@master ~]# ll /mydata/data/ -rw-rw---- 1 mysql mysql 245 Jun 15 23:36 master-bin.000001 -rw-rw---- 1 mysql mysql 20Jun 15 23:36 master-bin.index
(3) 创建一个有复制权限(REPLICATION SLAVE, REPLICATION CLIENT)账号;
MariaDB [(none)]> grant replicationclient,replication slave on *.* to ‘repluser‘@‘172.16.%.%‘ identified by‘replpass‘; MariaDB [(none)]> flushprivileges; #设置完成一定要刷新,不然不生效
(1) 启用中继日志;
(2) 设置一个在当前集群中惟一的server-id;
设置关闭二进制日志,然后启用中继日志,由于master已经使用的1的id,所以slave需要修改id号,这里为了方便以后扩展修改为10。
[root@slvae ~]# vim /etc/my.cnf #log-bin=mysql-bin #注销即关闭二进制日志 #binlog_format=mixed relay-log = relay-bin server-id = 10 read-only = on #关闭从服务器写入功能
(3) 使用有复制权限用户账号连接至主服务器,并启动复制线程;
复制之前查看一下master服务器记录二进制日志的位置,确定从主服务器的那个位置复制。
MariaDB [(none)]> show master status; +-------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-------------------+----------+--------------+------------------+ | master-bin.000001 | 496 | | | +-------------------+----------+--------------+------------------+
从服务器使用CHANGE MASTER连接主服务器进行复制,CHANGE MASTER使用语法在下面有介绍。
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST=‘172.16.4.136‘,MASTER_USER=‘repluser‘,MASTER_PASSWORD=‘replpass‘,MASTER_LOG_FILE=‘master-bin.000001‘,MASTER_LOG_POS=496,MASTER_CONNECT_RETRY=5,MASTER_HEARTBEAT_PERIOD=2;
说明:如果是生产环境,从服务器复制之前需要导入一次主服务器的完全备份,然后在从主服务器备份之后开始记录二进制日志的pos位置开始服务。
查看从服务器复制状态,IO和SQL线程还是处于关闭状态,需要手动启动才会开始复制
MariaDB [(none)]> show slave status\G *************************** 1. row*************************** Slave_IO_State: Master_Host: 172.16.4.136 Master_User: repluser Master_Port: 3306 Connect_Retry: 5 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 496 Relay_Log_File: relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: No #值为NO表示没有启动IO线程 Slave_SQL_Running: No #值为NO表示没有启动SQL线程 Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 496 Relay_Log_Space: 245 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 0 1 row in set (0.00 sec)
使用START SLAVE命令启动从服务器的IO和SQL线程,并再次查看状态
MariaDB [(none)]> START SLAVE; #此命令启动从服务器复制 MariaDB [(none)]> show slave status\G *************************** 1. row*************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.16.4.136 Master_User: repluser Master_Port: 3306 Connect_Retry: 5 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 496 Relay_Log_File: relay-bin.000002 Relay_Log_Pos: 530 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: Yes #这里的值为YES表示启动 Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 496 Relay_Log_Space: 818 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 1 row in set (0.00 sec)
查看中继日志已经存在了
[root@slvae ~]# ll /mydata/data/relay-* -rw-rw---- 1 mysql mysql 245 May 27 23:06 /mydata/data/relay-bin.000001 -rw-rw---- 1 mysql mysql 19 May 27 23:06 /mydata/data/relay-bin.index -rw-rw---- 1 mysql mysql 43 May 27 23:06 /mydata/data/relay-log.info
主节点执行写操作,如创建一个数据库
MariaDB [(none)]> create database mydb;
从节点验证:从节点没有执行创建,数据库就自动创建过来了
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+
在此查看从服务器状态,日志的记录位置也已经改变了
MariaDB [(none)]> show slave status\G *************************** 1. row*************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.16.4.136 Master_User: repluser Master_Port: 3306 Connect_Retry: 5 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 579 #这里从496变成了579 Relay_Log_File: relay-bin.000002 Relay_Log_Pos: 613 #这里从530变成了613 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 579 Relay_Log_Space: 901 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 1 row in set (0.00 sec)
说明:服务器程序版本:最好相同;如果不同应该从版本高;
语法:CHANGE MASTER TO option [, option] ...
选项如下:
MASTER_BIND = ‘interface_name‘
| MASTER_HOST = ‘host_name‘ 主服务器地址
| MASTER_USER = ‘user_name‘ 有复制权限的用户名
| MASTER_PASSWORD = ‘password‘ 用户密码
| MASTER_PORT = port_num 主服务器的端口
| MASTER_CONNECT_RETRY = interval 连接重试时间间隔
| MASTER_HEARTBEAT_PERIOD = interval 心跳检测时间间隔
| MASTER_LOG_FILE = ‘master_log_name‘ 主服务器二进制日志文件
| MASTER_LOG_POS = master_log_pos 二进制日志文件中的位置
什么是半同步复制:
正常情况下主服务器和从服务器是同步的,但是一旦主服务器和从服务器的连接超时主服务器就自动降级为异步模式。
配置半同步需要装载模块,否则不会出现半同步配置变量
主节点装载的模块:semisync_master.so
从节点转载的模块:semisync_slave.so
装载模块
MariaDB [(none)]> INSTALL PLUGINrpl_semi_sync_master SONAME ‘semisync_master.so‘; MariaDB [(none)]> show global variables like‘%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 | #等待确保没有从服务器 +------------------------------------+-------+
设置半同步参数:
MariaDB [(none)]> SET GLOBAL rpl_semi_sync_master_enabled=1; #设置为1或者on表示启用半同步 MariaDB [(none)]> SET GLOBALrpl_semi_sync_master_timeout=2000; #设置超市时间为2秒 MariaDB [(none)]> show global variables like‘%semi%‘; +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 2000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_no_slave | ON | +------------------------------------+-------+
转载从节点模块
MariaDB [(none)]> INSTALL PLUGINrpl_semi_sync_slave SONAME ‘semisync_slave.so‘; MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE‘%semi%‘; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+
启动从节点
MariaDB [(none)]> SET GLOBALrpl_semi_sync_slave_enabled=1; MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE‘%semi%‘; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | ON | | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+
设置完成之后,从节点需要重启IO线程。
MariaDB [(none)]> STOP SLAVE IO_THREAD; MariaDB [(none)]> START SLAVE IO_THREAD;
验证:主节点查看Rpl_semi_sync_master_clients值为1表示已经有一个从节点已半同步的状态连接到了主节点
MariaDB [(none)]> show global status like‘%semi%‘; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 1 | #此值为1,表示有一个从节点以半同步模式连接到主节点 | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_net_wait_time | 0 | | Rpl_semi_sync_master_net_waits | 0 | | Rpl_semi_sync_master_no_times | 0 | | Rpl_semi_sync_master_no_tx | 0 | | Rpl_semi_sync_master_status | ON | | Rpl_semi_sync_master_timefunc_failures | 0 | | Rpl_semi_sync_master_tx_avg_wait_time | 0 | | Rpl_semi_sync_master_tx_wait_time | 0 | | Rpl_semi_sync_master_tx_waits | 0 | | Rpl_semi_sync_master_wait_pos_backtraverse |0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 0 | +--------------------------------------------+-------+
复制过滤器功能:让slave节点仅复制几个指定的数据库,而非所有。
有两种实现思路:
(1) 主服务器仅向二进制日志中记录有特定数据库相关的写操作;
问题:即时点还原将无法全面实现,不建议使用
binlog_do_db= # 数据库白名单,如果启用则只记录白名单中的数据库
binlog_ignore_db= # 数据库黑名单,如果启用则除了黑名单之外的数据库都记录
(2)从服务器的SQL_THREAD仅在中断日志中读取特定数据相关的语句并应用在本地;推荐使用
问题:会造成网络带宽和磁盘IO的浪费;
Replicate_Do_DB= #数据库白名单
Replicate_Ignore_DB= #数据库黑名单
Replicate_Do_Table= #表白名单
Replicate_Ignore_Table= #表黑名单
Replicate_Wild_Do_Table= #表白名单支持通配符;%(后面所有)、_(一个字符)
Replicate_Wild_Ignore_Table= #表黑名单支持通配符
查看Replicate相关变量,表示什么都没有设置,如果需要设置复制过滤,可以直接修改Replicate变量或者在配置文件中定义。
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE‘replicate%‘; +----------------------------------+-----------+ | Variable_name | Value | +----------------------------------+-----------+ | replicate_annotate_row_events | OFF | | replicate_do_db | | | replicate_do_table | | | replicate_events_marked_for_skip | replicate | | replicate_ignore_db | | | replicate_ignore_table | | | replicate_wild_do_table | | | replicate_wild_ignore_table | | +----------------------------------+-----------+
示例:设置只能只复制testdb数据库,设置之前需要关闭复制功能,否则会报错,设置完成之后在开启。
MariaDB [(none)]> STOP SLAVE; MariaDB [(none)]> SET GLOBALreplicate_do_db=testdb; MariaDB [(none)]> STARTSLAVE;
验证:查看slave状态,Replicate_Do_DB的值就是testdb,表示只复制testdb的内容
MariaDB [(none)]> show slave status\G; Replicate_Do_DB: testdb
操作验证:主节点创建两个数据库testdb和testdb1
MariaDB [(none)]> create database testdb; MariaDB [(none)]> createdatabase testdb1;
从节点查看数据库只是复制过来了testdb,而testdb1则是被过滤掉了
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | | testdb | +--------------------+
(1) 各自使用不同的serverid
(2) 都启用binlog和relay log
(3) 定义自动增长的id字段的增长方式
定义一个节点使用奇数id
auto_increment_offset=1 #指定开始的id
auto_increment_increment=2 #指定一次增加的id
定义另一个节点使用偶数id
auto_increment_offset=2
auto_increment_increment=2
(4) 都授权有复制权限的用户账号
(5) 各自把对方指定为主服务器
这里的配置是从新的环境中开始配置的,不是使用上面的主从配置环境。
Node1:172.16.4.136
Node2:172.16.4.10
修改node1节点配置文件,启动二进制日志和中继日志,这里的id选择为单数
[root@node1 ~]# vim /etc/my.cnf log-bin=master-bin relay-log=relay-bin auto_increment_offset=1 auto_increment_increment=2 server-id = 1
配置文件修改完成,重启服务生效
登录Mariadb创建具有复制权限的用户
MariaDB [(none)]> GRANT REPLICATIONSLAVE,REPLICATION CLIENT ON *.* TO ‘repluser‘@‘172.16.%.%‘ IDENTIFIED BY‘replpass‘; MariaDB [(none)]> FLUSH PRIVILEGES;
启动二进制日志和中继日志,这里的id选择为双数
[root@node2 ~]# vim /etc/my.cnf server-id = 10 log-bin=master-bin relay-log = relay-bin auto_increment_offset=2 auto_increment_incremtn=2
配置文件修改完成,重启服务生效
登录Mariadb创建具有复制权限的用户
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.*TO ‘repluser‘@‘172.16.%.%‘ IDENTIFIED BY ‘replpass‘; MariaDB [(none)]> FLUSH PRIVILEGES;
查看node1节点二进制文件的记录位置
MariaDB [(none)]> show master status; +-------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-------------------+----------+--------------+------------------+ | master-bin.000004 | 506 | | | +-------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
查看node2节点二进制文件的记录位置
MariaDB [(none)]> show master status; +-------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-------------------+----------+--------------+------------------+ | master-bin.000001 | 506 | | | +-------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
Node1和node2节点使用CHANGE MASTER进行复制
Node1节点
MariaDB[(none)]> CHANGE MASTER TO MASTER_HOST=‘172.16.4.136‘,MASTER_USER=‘repluser‘,MASTER_PASSWORD=‘replpass‘,MASTER_LOG_FILE=‘master-bin.000001‘,MASTER_LOG_POS=506;
命令执行如果没有报错就启动复制线程
MariaDB[(none)]> START SLAVE; MariaDB[(none)]> show slave status\G; Slave_IO_Running: Yes Slave_SQL_Running: Yes
Node2节点
MariaDB [(none)]> CHANGE MASTER TOMASTER_HOST=‘172.16.4.10‘,MASTER_USER=‘repluser‘,MASTER_PASSWORD=‘replpass‘,MASTER_LOG_FILE=‘master-bin.000004‘,MASTER_LOG_POS=506; MariaDB [(none)]> START SLAVE; MariaDB [(none)]> show slave status\G; Slave_IO_Running: Yes Slave_SQL_Running: Yes
Node1节点创建一个数据库
MariaDB [(none)]> create database node1;
Node2节点创建一个数据库
MariaDB [(none)]> create database node2;
分别在node1节点和node2节点查看,如果主节点和从节点都出现了node1,node2数据库说明双主配置成功了。
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | node1 | | node2 | | performance_schema | | test | +--------------------+ 6 rows in set (0.00 sec)
Node2节点创建一个表,并且插入数据查看字段的id就是双数
MariaDB [(none)]> use node1; MariaDB [node1]> create table tb1 (id INTUNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,name MariaDB [node1]> INSERT INTO tb1 (name) VALUES(‘stu1‘),(‘stu2‘); MariaDB [node1]> select * from tb1; +----+------+ | id | name | +----+------+ | 2 | stu1 | | 4 | stu2 | +----+------+
Node1插入数据,查看id就是单数
MariaDB [(none)]> use node1; MariaDB [node1]> INSERT INTO tb1 (name) VALUES(‘stu3‘),(‘stu4‘); MariaDB [node1]> SELECT * FROM tb1; +----+------+ | id | name | +----+------+ | 2 | stu1 | | 4 | stu2 | | 5 | stu3 | | 7 | stu4 | +----+------+
(1) 清理日志:PURGE
(2) 复制监控
SHOW MASTER STATUS #查看当前使用的二进制日志和pos位置
SHOW BINLOG EVENTS #查看二进制日志文件记录的内容
SHOW BINARY LOGS #查看所有二进制日志
SHOW SLAVE STATUS #从节点查看复制状态
(3) 如何判断slave是否落后于master
MariaDB [(none)]> show slave status\G;
Seconds_Behind_Master: 0 #为0表示不落后
(4) 如何确定主从节点数据是否一致?
通过表自身的CHECKSUM检查
使用percona-tools中pt-table-checksum
(5) 数据不一致的修复方法:
重复复制:就是在从上一次主库完全备份的导入位置重新复制一遍
本文出自 “梅花香自苦寒来” 博客,请务必保留此出处http://ximenfeibing.blog.51cto.com/8809812/1665272
原文地址:http://ximenfeibing.blog.51cto.com/8809812/1665272