转自 运维开发_西瓜甜
https://www.jianshu.com/p/faf0127f1cb2
主从复制(也称 AB 复制)容许未来自一个MySQL数据库服务器(主服务器)的数据复制到一个或多个MySQL数据库服务器(从服务器)。html
复制是异步的 从站不须要永久链接以接收来自主站的更新。
根据配置,您能够复制数据库中的全部数据库,所选数据库甚至选定的表。mysql
MySQL中复制的优势包括:sql
前提是做为主服务器角色的数据库服务器必须开启二进制日志
Binary log
里面。Realy log
(中继日志)里面。Realy log
(这个文件也是二进制的),若是发现有更新当即把更新的内容在本机的数据库上面执行一遍。每一个从服务器都会收到主服务器二进制日志的所有内容的副本。shell
从服务器设备负责决定应该执行二进制日志中的哪些语句。数据库
除非另行指定,不然主从二进制日志中的全部事件都在从站上执行。ubuntu
若是须要,您能够将从服务器配置为仅处理一些特定数据库或表的事件。安全
重要: 您没法将主服务器配置为仅记录特定事件。服务器
每一个从站(从服务器)都会记录二进制日志坐标:网络
因为每一个从服务器都分别记录了本身当前处理二进制日志中的位置,所以能够断开从服务器的链接,从新链接而后恢复继续处理。session
若是一主多从的话,这时主库既要负责写又要负责为几个从库提供二进制日志。此时能够稍作调整,将二进制日志只给某一从,这一从再开启二进制日志并将本身的二进制日志再发给其它从。或者是干脆这个从不记录只负责将二进制日志转发给其它从,这样架构起来性能可能要好得多,并且数据之间的延时应该也稍微要好一些。工做原理图以下:
image.png
mysqld将数字扩展名附加到二进制日志基本名称以生成二进制日志文件名。每次服务器建立新日志文件时,该数字都会增长,从而建立一系列有序的文件。每次启动或刷新日志时,服务器都会在系列中建立一个新文件。服务器还会在当前日志大小达到max_binlog_size
参数设置的大小后自动建立新的二进制日志文件 。二进制日志文件可能会比max_binlog_size
使用大型事务时更大, 由于事务是以一个部分写入文件,而不是在文件之间分割。
为了跟踪已使用的二进制日志文件, mysqld还建立了一个二进制日志索引文件,其中包含全部使用的二进制日志文件的名称。默认状况下,它具备与二进制日志文件相同的基本名称,并带有扩展名'.index'
。在mysqld运行时,您不该手动编辑此文件。
术语二进制日志文件
一般表示包含数据库事件的单个编号文件。
术语 二进制日志
表示含编号的二进制日志文件集加上索引文件。
SUPER
权限的用户可使用SET sql_log_bin=0
语句禁用其当前环境下本身的语句的二进制日志记录
编辑主服务器的配置文件 my.cnf
,添加以下内容
[mysqld] log-bin=/var/log/mysql/mysql-bin server-id=1
建立日志目录并赋予权限
shell> mkdir /var/log/mysql shell> chown mysql.mysql /var/log/mysql
重启服务
shell> systemctl restart mysqld
注意:
若是省略server-id(或将其显式设置为默认值0),则主服务器拒绝来自从服务器的任何链接。
为了在使用带事务的InnoDB进行复制设置时尽量提升持久性和一致性,
您应该在master my.cnf文件中使用如下配置项:
innodb_flush_log_at_trx_commit = 1 sync_binlog = 1
确保在主服务器上 skip_networking
选项处于 OFF
关闭状态, 这是默认值。
若是是启用的,则从站没法与主站通讯,而且复制失败。
mysql> show variables like '%skip_networking%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | skip_networking | OFF | +-----------------+-------+ 1 row in set (0.00 sec)
每一个从服务器须要使用MySQL 主服务器上的用户名和密码链接到主站。
例如,计划使用用户 repl
能够从任何主机上链接到 master
上进行复制操做, 而且用户 repl
仅可使用复制的权限。
在 主服务器
上执行以下操做
mysql> CREATE USER 'repl'@'%' mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' identified by 'QFedu123!'; mysql>
从服务器
上使用刚才的用户进行测试链接shell> mysql -urepl -p'QFedu123!' -hmysql-master1
下面的操做根据以下状况继续
若是主数据库包含现有数据,则必须将此数据复制到每一个从站。有多种方法能够实现:
InnoDB
。shell> mysqldump -u用户名 -p密码 --all-databases --master-data=1 > dbdump.db
这里的用户是主服务器的用户
若是不使用 --master-data
参数,则须要手动锁定单独会话中的全部表。
scp
或 rsync
等工具,把备份出来的数据传输到从服务器中。在主服务中执行以下命令
scp dbdump.db root@mysql-slave1:/root/
这里的mysql-slave1
须要能被主服务器解析出 IP 地址,或者说能够在主服务器中ping
通。
从服务器
上编辑其配置文件 my.cnf
并添加以下内容:// my.cnf 文件
[mysqld]
server-id=2
登陆到从服务器上,执行以下操做
/*导入数据*/ mysql> source /root/fulldb.dump
在从服务器配置链接到主服务器的相关信息
mysql> CHANGE MASTER TO MASTER_HOST='mysql-master1', -- 主服务器的主机名(也能够是 IP) MASTER_USER='repl', -- 链接到主服务器的用户 MASTER_PASSWORD='123'; == 到主服务器的密码
mysql> start slave;
Query OK, 0 rows affected (0.09 sec)
检查是否成功
在从服务上执行以下操做,加长从服务器端 IO线程和 SQL 线程是不是 OK
mysql> show slave status\G
输出结果中应该看到 I/O 线程和 SQL 线程都是 YES
, 就表示成功。
执行此过程后,在主服务上操做的修改数据的操做都会在从服务器中执行一遍,这样就保证了数据的一致性。
和上面的步骤同样,可是新加入的服务器的server-id
的值不能和现有都服务器 server-id
的值同样。
假如在新加入从服务器以前,主服务器执行了删除库的操做。
而且,删除的库恰好是在第一次mysqldump
备份时的数据中。
就会出现问题,在从服务器上提示报错没有这个数据库;
主服务器中设置
my.cnf
配置文件[mysqld]
log-bin=/var/log/mysql/mysql-bin
server-id=1
设置log-bin
时必须同时设置server-id
建立日志目录并赋予权限
shell> mkdir /var/log/mysql shell> chown mysql.mysql /var/log/mysql
重启服务
从服务器设置
my.cnf
配置文件[mysqld]
server-id=3
重启服务
经过使用命令行客户端链接到主服务器来启动主服务器上的会话,并经过执行如下FLUSH TABLES WITH READ LOCK
语句来刷新全部表和阻止写语句:
mysql> FLUSH TABLES WITH READ LOCK; mysql> show master status \G ****************** 1. row **************** File: mysql-bin.000001 Position: 0 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec)
mysql> CHANGE MASTER TO
MASTER_HOST='mysql-master1',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
mysql> start slave;
在master上执行show binlog events命令,能够看到第一个binlog文件的内容。
mysql> show binlog events\G *************************** 1. row *************************** Log_name: mysql-bin.000001 Pos: 4 Event_type: Format_desc Server_id: 1 End_log_pos: 107 Info: Server ver: 5.5.28-0ubuntu0.12.10.2-log, Binlog ver: 4 *************************** 2. row *************************** Log_name: mysql-bin.000001 Pos: 107 Event_type: Query Server_id: 1 End_log_pos: 181 Info: create user rep *************************** 3. row *************************** Log_name: mysql-bin.000001 Pos: 181 Event_type: Query Server_id: 1 End_log_pos: 316 Info: grant replication slave on *.* to rep identified by '123456' 3 rows in set (0.00 sec)
您可使用STOP SLAVE
和 START SLAVE
语句中止并启动从站上的复制 。
要中止从主服务器处理二进制日志,请使用 STOP SLAVE
:
mysql> STOP SLAVE;
当复制中止时,从I / O线程中止从主二进制日志读取事件并将它们写入中继日志,而且SQL线程中止从中继日志读取事件并执行它们。您能够经过指定线程类型单独暂停I / O或SQL线程:
mysql> STOP SLAVE IO_THREAD; mysql> STOP SLAVE SQL_THREAD;
要再次开始执行,请使用如下START SLAVE
语句:
mysql> START SLAVE;
要启动特定线程,请指定线程类型:
mysql> START SLAVE IO_THREAD; mysql> START SLAVE SQL_THREAD;
MySQL复制功能使用三个线程实现,一个在主服务器上,两个在从服务器上:
SHOW PROCESSLIST
在主服务器的输出中将此线程标识为Binlog Dump
线程。二进制日志转储线程获取主机二进制日志上的锁,用于读取要发送到从机的每一个事件。一旦读取了事件,即便在事件发送到从站以前,锁也会被释放。
START SLAVE
语句时,从属服务器会建立一个 I/O 线程,该线程链接到主服务器并要求主服务器发送其在二进制日志中的更新记录。从属 I/O线程读取主Binlog Dump
线程发送的更新 (请参阅上一项)并将它们复制到包含从属中继日志的本地文件。
此线程的状态显示为 Slave_IO_running
输出 SHOW SLAVE STATUS
或 Slave_running
输出中的状态SHOW STATUS
。
在前面的描述中,每一个主/从链接有三个线程。具备多个从站的主站为每一个当前链接的从站建立一个二进制日志转储线程,每一个从站都有本身的I / O和SQL线程。
从站使用两个线程将读取更新与主站分开并将它们执行到独立任务中。所以,若是语句执行缓慢,则不会减慢读取语句的任务。例如,若是从服务器还没有运行一段时间,则当从服务器启动时,其I / O线程能够快速从主服务器获取全部二进制日志内容,即便SQL线程远远落后。若是从服务器在SQL线程执行了全部获取的语句以前中止,则I / O线程至少已获取全部内容,以便语句的安全副本本地存储在从属的中继日志中,准备在下次执行时执行奴隶开始。
该SHOW PROCESSLIST
语句提供的信息能够告诉您主服务器和从服务器上有关复制的信息。有关主状态的信息,请参见第8.14.4节“复制主线程状态”。有关从站状态,请参见第8.14.5节“复制从站I / O线程状态”和 第8.14.6节“复制从站SQL线程状态”。
如下示例说明了三个线程如何显示在输出中SHOW PROCESSLIST
。
在主服务器上,输出SHOW PROCESSLIST
以下所示:
mysql> SHOW PROCESSLIST\G *************************** 1\. row *************************** Id: 2 User: root Host: localhost:32931 db: NULL Command: Binlog Dump Time: 94 State: Has sent all binlog to slave; waiting for binlog to be updated Info: NULL
这里,线程2是Binlog Dump
为链接的从属服务的复制线程。该 State
信息代表全部未完成的更新已发送到从站,而且主站正在等待更多更新发生。若是Binlog Dump
在主服务器上看不到任何 线程,则表示复制未运行; 也就是说,目前没有链接任何从站。
在从属服务器上,输出SHOW PROCESSLIST
以下所示:
mysql> SHOW PROCESSLIST\G *************************** 1\. row *************************** Id: 10 User: system user Host: db: NULL Command: Connect Time: 11 State: Waiting for master to send event Info: NULL *************************** 2\. row *************************** Id: 11 User: system user Host: db: NULL Command: Connect Time: 11 State: Has read all relay log; waiting for the slave I/O thread to update it Info: NULL
该State
信息指示线程10是与主服务器通讯的I / O线程,而且线程11是处理存储在中继日志中的更新的SQL线程。在 SHOW PROCESSLIST
运行时,两个线程都处于空闲状态,等待进一步更新。
Time
列中 的值能够显示从站与主站进行比较的时间。请参见 第A.13节“MySQL 5.7 FAQ:复制”。若是主站侧有足够的时间在Binlog Dump
线程上没有活动,则主站肯定从站再也不链接。对于任何其余客户端链接,这样作的超时取决于的值 net_write_timeout
和 net_retry_count
; 有关这些的更多信息,请参见第5.1.7节“服务器系统变量”。
该SHOW SLAVE STATUS
语句提供有关从属服务器上的复制处理的其余信息。请参见 第16.1.7.1节“检查复制状态”。
就是利用 GTID 来实现的复制
GTID(全局事务标示符)最初由google实现,在MySQL 5.6中引入.GTID在事务提交时生成,由UUID和事务ID组成.uuid会在第一次启动MySQL时生成,保存在数据目录下的auto .CNF文件里,事务ID则从1开始自增使用GTID的好处主要有两点:
[mysqld] log-bin=/var/log/mysql/mysql-bin server-id=1 gtid_mode=ON enforce_gtid_consistency=1 # 强制执行GTID一致性。
重启服务
其余和以前的同样
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY '123';
mysql> GRANT REPLICATION SLAVE ON . TO 'repl'@'%';
mysql>
测试用户有效性
shell> mysql -urepl -p'123' -hmysql-master1 [mysqld] server-id=2 gtid_mode=ON enforce_gtid_consistency=1 # 可选项, 把链接到 master 的信息存到数据库中的表中 master-info-repository=TABLE relay-log-info-repository=TABLE
重启服务
假若有数据,先导入数据
mysql> source dump.db
Mysql 终端执行链接信息
mysql> CHANGE MASTER TO MASTER_HOST='172.16.153.10', MASTER_USER='repl', MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1; > start slave;
检查 slave 状态
mysql> show slave status\G
设置 从服务器只读状态
查看当前只读的状态
SHOW VARIABLES LIKE '%read_only%';设置普通用户只读
SET GLOBAL read_only=1;设置超级用户只读
SET GLOBAL super_read_only=1;
mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | OFF | | super_read_only | OFF | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.01 sec) mysql> SET GLOBAL read_only=1; Query OK, 0 rows affected (0.00 sec) mysql> ; ERROR: No query specified mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | ON | | super_read_only | OFF | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.00 sec) mysql> SET GLOBAL super_read_only=1; Query OK, 0 rows affected (0.00 sec) mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | ON | | super_read_only | ON | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.00 sec) mysql> create database db1; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events
意思是: 当前数据库实例中开启了 GTID 功能, 在开启有 GTID 功能的数据库实例中, 导出其中任何一个库, 若是没有显示地指定--set-gtid-purged参数, 都会提示这一行信息. 意思是默认状况下, 导出的库中含有 GTID 信息, 若是不想导出包含有 GTID 信息的数据库, 须要显示地添加--set-gtid-purged=OFF参数.
mysqldump -uroot -p --set-gtid-purged=OFF --all-databases > alldb.db
导入数据是就能够相往常同样导入了。
多线程复制在 5.6
中被引入,而且在 5.7
中获得了进一步的完善。
5.7
中是基于逻辑时钟的方式进行的多线程复制。
先在从库上查看默认的多线程复制类型
mysql> show variables like "slave_parallel_type"; | |
---|---|
Variable_name | Value |
slave_parallel_type | DATABASE |
1 row in set (0.01 sec)
mysql>
中止以前能够查看目前的线程数
show processlist; mysql> stop slave
mysql> set global slave_parallel_type = "logical_clock";
Query OK, 0 rows affected (0.00 sec)
配置并发数量
mysql> set global slave_parallel_workers = 4;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "slave_parallel_workers"; | |
---|---|
Variable_name | Value |
slave_parallel_workers | 4 |
1 row in set (0.00 sec)
mysql> start slave
上图中,Master-Master复制的两台服务器,既是master,又是另外一台服务器的slave。这样,任何一方所作的变动,都会经过复制应用到另一方的数据库中。在这种复制架构中,各自上运行的不是同一db,好比左边的是db1,右边的是db2,db1的从在右边反之db2的从在左边,二者互为主从,再辅助一些监控的服务还能够实现必定程度上的高能够用。
上图中,这是由master-master结构变化而来的,它避免了M-M的缺点,实际上,这是一种具备容错和高可用性的系统。它的不一样点在于其中只有一个节点在提供读写服务,另一个节点时刻准备着,当主节点一旦故障立刻接替服务。好比经过corosync+pacemaker+drbd+MySQL就能够提供这样一组高可用服务,主备模式下再跟着slave服务器,也能够实现读写分离。
这种结构的优势就是提供了冗余。在地理上分布的复制结构,它不存在单一节点故障问题,并且还能够将读密集型的请求放到slave上。
MySQL-5.5 及以上支持半同步复制
早前的MySQL复制只能是基于异步来实现,从MySQL-5.5开始,支持半自动复制。在之前的异步(asynchronous)复制中,主库在执行完一些事务后,是不会管备库的进度的。若是备库处于落后,而更不幸的是主库此时又出现Crash(例如宕机),这时备库中的数据就是不完整的。简而言之,在主库发生故障的时候,咱们没法使用备库来继续提供数据一致的服务了。Semisynchronous Replication(半同步复制)则必定程度上保证提交的事务已经传给了至少一个备库。Semi synchronous中,仅仅保证事务的已经传递到备库上,可是并不确保已经在备库上执行完成了。
此外,还有一种状况会致使主备数据不一致。在某个session中,主库上提交一个事务后,会等待事务传递给至少一个备库,若是在这个等待过程当中主库Crash,那么也可能备库和主库不一致,这是很致命的。若是主备网络故障或者备库挂了,主库在事务提交后等待10秒(rpl_semi_sync_master_timeout的默认值)后,就会继续。这时,主库就会变回原来的异步状态。
MySQL在加载并开启Semi-sync插件后,每个事务需等待备库接收日志后才返回给客户端。若是作的是小事务,两台主机的延迟又较小,则Semi-sync能够实如今性能很小损失的状况下的零数据丢失。
千锋云计算
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.08 sec) mysql> 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_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | +-------------------------------------------+------------+ 6 rows in set (0.00 sec) mysql>
官网: https://dev.mysql.com/doc/refman/5.7/en/change-master-to.html
官网:https://dev.mysql.com/doc/refman/5.7/en/replication-solutions-encrypted-connections.html
主服务器
建立 CA 证书和私钥 公钥
shell> mysql_ssl_rsa_setup
My.cnf 文件配置项
如下的状况是用 yum
安装 mysql 的状况
[mysqld] ssl-ca=/var/lib/mysql/ca.pem ssl-cert=/var/lib/mysql/server-cert.pem ssl-key=/var/lib/mysql/server-key.pem
选项以下:
--ssl-ca
:证书颁发机构(CA)证书文件的路径名。(--ssl-capath
相似但指定CA证书文件目录的路径名。)
--ssl-cert
:服务器公钥证书文件的路径名。能够将其发送到客户端,并根据其拥有的CA证书进行身份验证。--ssl-key
:服务器私钥文件的路径名。从服务器配置
首先要保证从服务器的 sql 线程和 io 线程处于关闭状态
mysql> stop slave; mysql> stop slave sql_thread; mysql> CHANGE MASTER TO -> MASTER_HOST='master_hostname', -> MASTER_USER='repl', -> MASTER_PASSWORD='password', -> MASTER_SSL=1, -> MASTER_SSL_CA = 'ca_file_name', -> MASTER_SSL_CAPATH = 'ca_directory_name', -> MASTER_SSL_CERT = 'cert_file_name', -> MASTER_SSL_KEY = 'key_file_name'; mysql> START SLAVE;
关于复制用户
全新建立
mysql> CREATE USER 'repl'@'%.example.com' IDENTIFIED BY 'password' -> REQUIRE SSL; mysql> GRANT REPLICATION SLAVE ON *.* -> TO 'repl'@'%.example.com';
给原来的用户添加 REQUIRE SSL
mysql> ALTER USER 'repl'@'%.example.com' REQUIRE SSL;
Mysql 终端中设置
不用重启服务
下面的命令是只保留 10 天内的日志,就是10天前的所有删除
mysql> set global expire_logs_days = 10;
当二进制日志的大小达到max_binlog_size
系统变量的值时,将刷新二进制日志 。
属性
值
命令行格式
--max-binlog-size=#
系统变量
max_binlog_size
范围
全局
动态
是
类型
整数
默认值
1073741824
最低价值
4096
最大价值
1073741824
若是对二进制日志的写入致使当前日志文件大小超过此变量的值,则服务器将轮转二进制日志(关闭当前文件并打开下一个文件)。最小值为4096字节。最大值和默认值为1GB。
事务在一个块中写入二进制日志,所以它永远不会在几个二进制日志之间拆分。所以,若是您有大事务,您可能会看到大于的二进制日志文件max_binlog_size
。
若是max_relay_log_size
为0,则该值也 max_binlog_size
适用于中继日志。
配置文件中设置
此方法须要重启服务
[mysqld] expire_logs_days=10
在 MySQL 终端中手动删除
--清除MySQL-bin.010日志 mysql> PURGE MASTER LOGS TO 'MySQL-bin.010'; --清除2008-06-22 13:00:00前binlog日志 mysql> PURGE MASTER LOGS BEFORE '2008-06-22 13:00:00'; --清除3天前binlog日志BEFORE,变量的date自变量能够为'YYYY-MM-DD hh:mm:ss'格式。 mysql> PURGE MASTER LOGS BEFORE DATE_SUB( NOW(), INTERVAL 3 DAY);