1. MySQL 主从复制概述php
1.1 MySQL 主从复制简介mysql
MySQL 数据库的主从复制方案,与使用 scp/rsync 等命令进行的文件级别复制相似,都是数据的远程传输,只不过 MySQL 的主从复制是其自带的功能,无需借助第三方工具,并且,MySQL 的主从复制并非数据库磁盘上的文件直接拷贝,而是经过逻辑的 binlog 日志复制到要同步的服务器本地,而后由本地的线程读取日志里面的 SQL 语句,从新应用到 MySQL 数据库中。web
1.2 MySQL 主从复制架构逻辑图概述sql
MySQL 数据库支持单向、双向、链式级联、环状等不一样业务场景的复制。在复制过程当中,一台服务器充当主服务器(Master),接收来自用户的内容更新,而一个或多个其余的服务器充当从服务器(Slave),接收来自主服务器 binlog 文件的日志内容,解析出 SQL,从新更新到从服务器,使得主从服务器数据达到一致。数据库
若是设置了链式级联复制,那么从服务器自己除了充当从服务器外,也会同时充当其下面从服务器的主服务器,链式级联复制相似 A→B→C 的复制形式。vim
下图为单向主从复制架构逻辑图,此架构只能在 Master 端进行数据写入:centos
下图为双向主主复制逻辑架构图,此架构能够在 Master1 端或 Master2 端进行数据写入,或者两端同时写入数据(须要特殊设置)。服务器
下图为线性级联单向双主复制逻辑架构图,此架构只能在 Master1 端进行数据写入,工做场景中,Master1 和 Master2 做为主主互备,Slave1 做为从库,中间的 Master2 须要作特殊的设置。网络
下图为环状级联单向多主同步逻辑架构图,任意一个点均可以写入数据,此架构比较复杂,属于极端环境下的“做品”,通常场景应慎用。架构
提示:在当前的生产环境中,MySQL 主从复制都是异步的复制方式,即不是严格实时的数据同步,可是正常状况下给用户的体验是实时的。
1.3 MySQL 主从复制的企业应用场景
MySQL 主从复制集群功能使得 MySQL 数据库支持大规模高并发读写成为可能,同时有效地保护了物理服务器宕机场景的数据备份。
应用场景1:从服务器做为主服务器的实时数据备份。
应用场景2:主从服务器实现读写分离,从服务器实现负载均衡。
应用场景3:把多个从服务器根据业务重要性进行拆分访问。
1.4 实现 MySQL 主从读写分离的方案
① 经过程序实现读写分离(性能和效率最佳,推荐):
PHP 和 JAVA 程序均可以经过设置多个链接文件轻松地实现对数据库的读写分离,即当语句关键字为 select 时,就去找读库的链接文件,若为 update、insert、delete 时,则链接写库的链接文件。
经过程序实现读写分离的缺点就是须要开发人员对程序进行改造,使其对下层不透明,但这种方式更容易开发和实现,适合互联网业务场景。
② 经过开源的软件实现读写分离:
MYSQL-proxy、Amoeba 等代理软件也能够实现读写分离,可是这些软件的稳定性和功能通常,不建议生产场景使用。绝大多数公司经常使用的仍是在应用端开发程序实现读写分离。
③ 大型门户独立开发 DAL 层综合软件;
2. MySQL 主从复制原理
2.1 MySQL 主从复制原理介绍
MySQL 的主从复制是一个异步的复制过程(虽然通常状况下感受是实时的),数据将从一个 MySQL 数据库(Master)复制到另外一个 MySQL 数据库(Slave),在 Master 和 Slave 之间实现整个主从复制的过程是由三个线程参与完成的,其中有两个线程(SQL 和 I/O )在 Slave 端,另外一个线程(I/O)在 Master 端。
要实现 MySQL 的主从复制,首先必须打开 Master 端的 binlog 记录功能,不然就没法实现,由于整个复制过程实际上就是 Slave 从 Master 获取 binlog 日志,而后再在 Slave 上以相同顺序执行获取的 binlog 日志中所记录的各类 SQL 操做。MySQL 的 binlog 功能在 /etc/my.cnf 中的 [mysqld] 模块下增长 log-bin 参数来实现。
2.2 MySQL 主从复制过程原理详细描述
① 在 Slave 服务器上执行 start slave 命令开启主从复制开关,开始进行主从复制。
② 此时 Slave 服务器的 I/O 线程会经过在 Master 上已经受权的复制用户权限请求链接 Master 服务器,并请求 Master 从指定 binlog 日志文件的指定位置(日志文件名和位置就是在配置主从服务时执行 change master 命令指定的)发送 binlog 日志内容。
③ Master 服务器接收到来自 Slave 服务器的 I/O 线程的请求后,其上负责复制的 I/O 线程会根据 Slave 服务器的 I/O 线程请求的信息分批读取指定 binlog 日志文件指定位置以后的 binlog 日志信息,而后返回给 Slave 端的 I/O 线程,返回的信息中除了 binlog 日志内容外,还有在 Master 服务器端记录的新的 binlog 文件名称,以及在新的 binlog 中的下一个指定更新位置。
④ 当 Slave 服务器的 I/O 线程获取到 Master 服务器上 I/O 线程发送的日志内容、日志文件及位置点后,会将 binlog 日志内容依次写到 Slave 端自身的 Relay Log(中继日志)文件的最末端,并将新的 binlog 文件名和位置记录到 master-info文件中,以便下一次读取 Master 端新 binlog 日志时可以告诉 Master 服务器重新 binlog 日志的指定文件及位置开始请求新的 binlog 日志内容。
⑤ Slave 服务器端的 SQL 线程会实时检测本地 Relay Log 中 I/O 线程新增长的日志内容,而后及时地把 Relay Log 文件中的内容解析成 SQL 语句,并在自身 Slave 服务器上按解析 SQL 语句的位置顺序执行应用这些 SQL 语句,并在 relay-log.info 中记录当前应用中继日志的文件名及位置点。
⑥ 通过了上面的过程,就能够确保在 Master 端和 Slave 端执行了一样的 SQL 语句。当复制状态正常时,Master 端和 Slave 端的数据是彻底同样的。固然,MySQL 的复制机制也有一些特殊状况,详情查看官方手册。
2.3 MySQL 主从复制重点小结
① 主从复制是异步的逻辑的 SQL 语句级的复制;
② 复制时,主库有一个 I/O 线程,从库有两个线程,及 I/O 和 SQL 线程;
③ 实现主从复制的必要条件是主库要开启记录 binlog 的功能;
④ 做为复制的全部 MySQL 节点的 server-id 都不能相同;
⑤ binlog 文件只记录对数据内容有更改的 SQL 语句,不记录任何查询语句。
2.4 MySQL 主从复制过程原理逻辑图
3. MySQL 主从复制实战
3.1 数据库环境准备
主从复制的搭建能够用两台 MySQL 服务器或者一台 MySQL 多实例服务器完成,这里以一台有两个实例的 MySQL 数据库服务器来完成。
通常作主从复制,主从服务器在不一样的机器上,而且监听的端口均为默认的 3306。
3.2 检查及准备环境
[root@centos ~]# ll /data
drwxr-xr-x 3 mysql mysql 4096 Apr 7 10:12 3306
drwxr-xr-x 3 mysql mysql 4096 Apr 7 17:38 3307
[root@centos ~]# /data/3306/mysql start
[root@centos ~]# /data/3307/mysql start
[root@centos ~]# ss -lnt|grep 330
LISTEN 0 128 *:3306 *:*
LISTEN 0 128 *:3307 *:*
定义监听 3306 端口的实例为 Master 主库。
定义监听 3307 端口的实例为 Slave 从库。
3.3 主库上的操做
[root@centos ~]# vi /data/3306/my.cnf # 编辑 3306 实例的配置文件。
[root@centos ~]# egrep "log-bin|server-id" /data/3306/my.cnf
log-bin = /data/3306/mysql-bin # 打开 binlog 日志功能。
server-id = 1
[root@centos ~]# /data/3306/mysql restart
注意上面两个参数的位置:
[mysqld]
server-id = 1
log-bin = /data/3306/mysql-bin
查看上面配置是否生效:
[root@centos ~]# ll /data/3306/ # 有以下内容表示生效。
-rw-rw---- 1 mysql mysql 126 Apr 7 02:19 mysql-bin.000001
-rw-rw---- 1 mysql mysql 264 Apr 7 03:17 mysql-bin.000002
-rw-rw---- 1 mysql mysql 126 Apr 7 03:52 mysql-bin.000003
-rw-rw---- 1 mysql mysql 252 Apr 7 10:12 mysql-bin.index
[root@centos ~]# mysql -uroot -p'123456' -S /data/3306/mysql.sock -e "show variables like 'log_bin';" # 能够看到 binlog 功能生效。
| Variable_name | Value |
| log_bin | ON |
查看从库配置:
[root@centos ~]# egrep "log-bin|server-id" /data/3307/my.cnf
#log-bin = /data/3307/mysql-bin # 不作级联的话从库 binlog 功能是否开启都不影响主库。
server-id = 3 # 两个 id 要不一样。
创建用于同步的帐号 rep :
[root@centos ~]# mysql -uroot -p'123456' -S /data/3306/mysql.sock # 登陆 3306。
mysql> grant replication slave on *.* to 'rep'@'192.168.136.%' identified by '123456';
mysql> flush privileges ;
提示:replication slave 为 mysql 同步的必须权限,此处不要受权 all。
在主库上作备份:
mysql> flush table with read lock; # 在主库上给全部表加只读锁。
mysql> show master status;
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
| mysql-bin.000009 |335 | | |
mysql> show master logs; # 输出略略略。
[root@centos ~]# mysqldump -uroot -p123456 -S /data/3306/mysql.sock -A -B --events >/opt/rep.sql
[root@centos ~]# mysqldump -uroot -p123456 -S /data/3306/mysql.sock -A -B --events --master-data=2 >/opt/rep.sql
[root@centos ~]# vim /opt/rep.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000009', MASTER_LOG
_POS=335;
mysql> unlock tables; # 打开只读锁。
mysql> show master status; # 备份完毕查看是否有变化,确保锁表成功。
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
| mysql-bin.000009 |335 | | |
提示:上面是官方文档给的备份方式,生产场景中的备份经常使用 -x 参数锁表,用 --master-data 参数记录 binlog 的文件及位置。
3.4 从库上的操做
把上面的备份数据放入从库
[root@centos ~]# mysql -uroot -p'oldboy123' -S /data/3307/mysql.sock </opt/rep.sql
[root@centos ~]# mysql -uroot -p'oldboy123' -S /data/3307/mysql.sock # 登陆到 3307。
mysql> CHANGE MASTER TO
-> MASTER_HOST='192.168.136.141',
-> MASTER_PORT=3306,
-> MASTER_USER='rep',
-> MASTER_PASSWORD='123456',
-> MASTER_LOG_FILE='mysql-bin.000009',
-> MASTER_LOG_POS=335;
[root@centos data]# cd /data/3307/data
[root@centos data]# ll
-rw-rw---- 1 mysql mysql 80 Apr 7 18:49 master.info
[root@centos data]# cat master.info # 上面的 change 语句结果会放到 master.info 里面。
18
mysql-bin.000009
335
192.168.136.141
rep
123456
3306
60
mysql> start slave; # 打开从库两个线程的开关。
Query OK, 0 rows affected (0.10 sec)
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
3.5 主从复制配置完成后检查(主库写入数据看从库)
[root@centos ~]# mysql -uroot -p'123456' -S /data/3306/mysql.sock # 登陆主库。
mysql> create database oldboy; # 建立 oldboy 库。
[root@centos ~]# mysql -uroot -p'oldboy123' -S /data/3307/mysql.sock # 登陆从库。
mysql> show databases; #查看 Master 中的 oldboy 库是否同步到 Slave。(成功)。
| Database |
| information_schema |
| mysql |
| oldboy |
| performance_schema |
| test |
[root@centos 3307]# ll
total 44
drwxr-xr-x 6 mysql mysql 4096 Apr 7 19:06 data
-rw-r--r-- 1 mysql mysql 1901 Apr 6 20:05 my.cnf
-rwx------ 1 root root 1310 Apr 7 03:06 mysql
-rw-rw---- 1 mysql mysql 6 Apr 7 17:38 mysqld.pid
-rw-r----- 1 mysql root 11758 Apr 7 18:57 mysql_oldboy3307.err
srwxrwxrwx 1 mysql mysql 0 Apr 7 17:38 mysql.sock
-rw-rw---- 1 mysql mysql 150 Apr 7 18:57 relay-bin.000001
-rw-rw---- 1 mysql mysql 340 Apr 7 19:06 relay-bin.000002
-rw-rw---- 1 mysql mysql 56 Apr 7 18:57 relay-bin.index
-rw-rw---- 1 mysql mysql 53 Apr 7 19:06 relay-log.info
[root@centos 3307]# mysqlbinlog relay-bin.000002
create database oldboy # 可看到从库里的建库语句。
[root@centos 3307]# cat relay-bin.index
/data/3307/relay-bin.000001
/data/3307/relay-bin.000002
[root@centos 3307]# cat relay-log.info
/data/3307/relay-bin.000002
340 # relay log 的位置。
mysql-bin.000009
422 # 从库 I/O 线程取 binlog 的位置。
[root@centos 3307]# cat data/master.info # 从库 I/O 线程取 binlog 的位置。
mysql-bin.000009
422
4. MySQL 主从复制配置步骤小结
4.1 MySQL 主从复制配置完整步骤以下
① 准备两台数据库环境或单台多实例环境,肯定能正常启动和登陆。
② 配置 my.cnf 文件:主库配置 log-bin 和 server-id 参数;从库配置 server-id,该值不能和主库及其余从库同样,通常不开启从库 log-bin 功能。注意配置后须要重启服务使之生效。
③ 登陆主库,增长从库链接主库同步的帐户,例如:rep,并受权 replication slave 同步的权限。
④ 登陆主库,整库锁表 flush table with read lock(窗口关闭后即失效,超时参数设置的时间到了也失效);而后 show master status 查看 binlog 的位置状态。
⑤ 新开窗口,Linux 命令行备份或导出原有的数据库数据,并拷贝到从库所在的服务器目录。若是数据量很大,而且容许停机,可停机打包,而不用 mysqldump 。
⑥ 解锁主库,unlock tables;
⑦ 把主库导出的原有数据恢复到从库。
⑧ 根据主库的 show master status 查看 binlog 的位置状态,在从库执行 change master to ... 语句验证 rep 用户。
⑨ 从库开启同步开关,start slave。
⑩ 从库 show slave status\G,检查同步状态,并在主库进行更新测试。
锁表语句知识补充:
5.1 flush tables with read lock
5.5 flush table with read lock
4.2 MySQL 主从复制从库 IO 线程不运行解决方案
http://www.javashuo.com/article/p-qybohloh-kx.html
缘由: 首先确认 server-id 是否惟一, mysql 有可能并无加载 my.cnf 文件中的 server-id。
解决办法:① 修改server-id (在my.cnf 文件中) 。
② mysql> set global server_id=119; #此处的server_id的值和my.cnf里设置的同样。
③ mysql> start slave;
4.3 MySQL 主从复制生产实践及排障
4.3.1 故障一:主库 show master status 没结果
缘由:主库 binlog 功能开关没开或没生效。
[root@centos ~]# egrep "server-id|log-bin" /data/3306/my.cnf
log-bin = /data/3306/mysql-bin
server-id = 1
mysql> show variables like 'server_id';
| Variable_name | Value |
| server_id | 1 |
mysql> show variables like 'log_bin';
| Variable_name | Value |
| log_bin | ON |
提示:配置文件里的参数和 show variables 里的参数不同。
4.3.2 故障二:提示找不到第一个 binlog 文件
mysql> CHANGE MASTER TO
-> MASTER_HOST='192.168.136.141',
-> MASTER_PORT=3306,
-> MASTER_USER='rep',
-> MASTER_PASSWORD='123456',
-> MASTER_LOG_FILE='mysql-bin.000009',
-> MASTER_LOG_POS=335;
缘由:上面一行,binlog 文件名两端不能有空格。
4.3.3 对主数据库锁表只读(当前窗口不要关掉)
5.1 flush tables with read lock
5.5 flush table with read lock
提示:在 MySQL 5.1 中,锁表的语句是: flush tables with read lock;这个锁表语句的时间,在不一样引擎的状况,会受下面参数的控制。锁表时若是超过设置时间不操做,会自动解锁。
interactive_timeout = 60
wait_timeout = 60
mysql> show variables like '%timeout%'; # 查看默认的锁表超时时间。
interactive_timeout | 28800
wait_timeout | 28800
把上面两个参数改成 60 秒:
mysql> set global wait_timeout = 60;
mysql> set global interactive_timeout = 60;
mysql> show variables like '%timeout%'; # 退出从新进入生效。
interactive_timeout | 60
wait_timeout | 60
重启 3306 实例后失效:(由于没有修改配置文件)
mysql> show variables like '%timeout%';
interactive_timeout | 28800
wait_timeout | 28800
因为切换 binlog 致使 show master 位置变化无影响。(数据没有更新)
4.4 回顾 MySQL 主从复制原理要点
① 异步方式同步;
② 逻辑同步模式,多种模式,默认是经过 SQL 语句执行;
③ 主库经过记录 binlog 实现对从库的同步。binlog 记录数据库的更新语句。
④ 主库一个 I/O 线程,从库由一个 I/O 线程和一个 SQL 线程来完成;
⑤ 从库关键文件 master.info 、relay-log 、relay-info 功能。
⑥ 若是从库还想级联从库,须要打开 log-bin 和 log-slave-updates 参数。
4.5 企业场景快速配置 MySQL 主从复制方案
① 安装好要配置从库的数据库,配置好 log-bin 和 server-id 参数;
② 无配置主库 my.cnf 文件,主库的 log-bin 和 server-id 参数默认就是配置好的;
③ 登录主库增长因为从库链接主库同步的帐户如 rep 并受权 replication slave 的权限;
④ 半夜使用 mysqldump 带 --master-data=1 备份的全备数据恢复到从库;
⑤ 在从库执行 change master to ... 语句,无需 binlog 文件及对应位置点。
⑥ 从库开启同步开关,start slave;
⑦ 从库 show slave status\G 检查同步状态,并在主库进行更新测试。
4.6 主从复制过程当中的同步状态
4.6.1 查看主库从库同步状态
查看 3306 实例 Master 线程的同步状态:
[root@centos ~]# mysql -uroot -p123456 -S /data/3306/mysql.sock
mysql> show processlist;
Master has sent all binlog to slave; waiting for binlog to be updated
查看 3307 实例 Slave 线程的同步状态:
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock
mysql> show processlist;
Slave has read all relay log; waiting for the slave I/O thread to update it
Waiting for master to send event
4.6.2 复制主线程状态
如下是主服务器的线程最多见状态。若是在主副武器上没有看到任何 binlog dump 线程说明复制没有运行,即没有链接任何从服务器。
Sending binlog event to slave
表示线程已经从二进制日志读取了一个事件而且正在将它发送到从服务器。
Finished reading one binlog;swiching to next binlog
表示线程已经读完二进制日志文件而且正打开下一个要发送到从服务器的日志文件。
Has sent all binlog to slave;waiting for binlog to be updated
表示线程已经把全部更新的 binlog 内容发给从库,目前正在等待 binlog 的更新。
Waiting to finalize termination
表示线程中止时发生的一个很简单的状态。
4.6.3 复制从 I/O 线程状态
Connection to master
线程正试图链接主服务器。
Checking master version
创建主从服务器之间的链接后当即临时出现的状态。
Registering slave on master
创建主从服务器之间的链接后当即临时出现的状态。
Registering binlog dump
创建主从服务器之间的链接后当即临时出现的状态。线程向主服务器发送一条请求,索取从请求的二进制日志文件名和位置开始的二进制日志的内容。
Waiting to reconnect after a failed binlog dump request
若是二进制日志转储请求失败(因为没有链接),线程进入睡眠状态,而后按期尝试从新链接,可使用 --master-connect-retry 选项指定重试之间的间隔。
Reconnecting after a failed binlog dump request
线程正尝试从新链接服务器。
Waiting for master to send event
线程已经链接上主服务器,正等待二进制日志事件到达。若是主服务器正空闲,会持续较长的时间,若是等待持续 slave_read_timeout 秒,则发生超时。此时,线程认为链接被中断并企图从新链接。
Queueing master event to the relay log
线程已经读取一个事件,正将它复制到中继日志供 SQL 线程来处理。
4.6.4 复制从 SQL 线程状态
Reading event from the relay log
线程已经从中继日志读取一个事件,能够对事件进行处理了。
Slave has read all relay log; waiting for the slave I/O thread to update it
线程已经处理了中继日志文件中的全部事件,如今正等待 I/O 线程将新事件写入中继日志。
Waiting for slave mutex on exit
线程中止时发生的一个很简单的状态。
4.7 查看 MySQL 线程同步状态的用途
经过 MySQL 线程同步状态查看数据库同步是否完成,用于主库宕机或者人工数据库主从切换迁移等。主库宕机选择最快的从库提高为主,就须要查看线程状态,固然也能够利用 MySQL 的半同步功能,选择固定的库提高为主。
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock
mysql> show slave status\G
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.136.141
Master_User: rep
Master_Port: 3306
Connect_Retry: 60 # 链接重试。
Master_Log_File: mysql-bin.000011
Read_Master_Log_Pos: 107
Relay_Log_File: relay-bin.000008
Relay_Log_Pos: 253
Relay_Master_Log_File: mysql-bin.000011
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
# 上面两个参数的 yes 表示同步的状态是 OK 的,可是是否有延迟等没法体现出来。
Last_Errno: 0 # 若是报错,该参数会有数字提示码。
Last_Error:
Seconds_Behind_Master: 0 # 从库落后于主库的秒数。参考,不绝对准确。
Master_SSL_Verify_Server_Cert: No
Master_Server_Id: 1
5. MySQL 常见错误码及解释
1005:MYSQL建立表失败
1006:MYSQL建立数据库失败
1007:MYSQL数据库已存在,建立数据库失败
1008:MYSQL数据库不存在,删除数据库失败
1009:MYSQL不能删除数据库文件致使删除数据库失败
1010:MYSQL不能删除数据目录致使删除数据库失败
1011:MYSQL删除数据库文件失败
1012:MYSQL不能读取系统表中的记录
1016:文件没法打开,使用后台修复或者使用 phpmyadmin 进行修复。
1017:服务器非法关机,致使该文件损坏。
1020:MYSQL记录已被其余用户修改
1021:硬盘剩余空间不足,请加大硬盘可用空间
1022:MYSQL关键字重复,更改记录失败
1023:MYSQL关闭时发生错误
1024:MYSQL读文件错误
1025:MYSQL更更名字时发生错误
1026:MYSQL写文件错误
1030:多是服务器不稳定。(具体缘由不是很清楚)
1032:MYSQL记录不存在
1036:MYSQL数据表是只读的,不能对它进行修改
1037:系统内存不足,请重启数据库或重启服务器
1038:MYSQL用于排序的内存不足,请增大排序缓冲区
在my.ini 修改成max_connections=1000或更大,重启mysql
1041:系统内存不足
1042:无效的主机名
1043:无效链接
1044:MYSQL当前用户没有访问数据库的权限
1045:MYSQL不能链接数据库,服务器、数据库名、用户名或密码错误
6. MySQL 主从复制读写分离受权多种方案
6.1 生产受权方案一
主库:web oldboy123 10.0.0.1 3306 (select、insert、delete、update)
从库:将主库的 web 用户同步到从库,而后回收 insert、delete、update 权限。
不收回权限的解决办法:
不收回从库权限,在 my.cnf 里面设置 read-only 参数或指定 read-only 只读启动。
开发登录数据库(主从的用户密码一致):
web oldboy123 10.0.0.1 3306 (select、insert、delete、update)
web oldboy123 10.0.0.2 3306 (select)
6.2 生产受权方案二
主库:web_w oldboy123 10.0.0.1 3306 (select、insert、delete、update)
从库:web_r oldboy123 10.0.0.2 3306 (select)
风险:web_w 用户链接从库写数据!
解决上述风险的方法:
设置 read-only 参数或指定 read-only 只读。
开发登录数据库:多套用户密码,不专业。
生产受权方案三:【推荐】
不一样步 mysql 库:主从库分别进行以下受权:
主库:web oldboy123 10.0.0.1 3306 (select、insert、delete、update)
从库:web oldboy123 10.0.0.2 3306 (select)
从库设置 read-only 参数读,增长双保险。
缺陷:
当从库切换主库时,链接用户会有权限问题。
解决方法:(百度架构方案)
保留一个从库专门准备接替主库。
6.3 忽略 MySQL 主从复制主库受权表同步实战
[root@centos ~]# vi /data/3306/my.cnf # 添加以下四行。
#replicate-ignore-db = mysql
#binlog-ignore-db = mysql
#binlog-ignore-db = performance_schema
#binlog-ignore-db = information_schema
[root@centos ~]# mysql -uroot -p123456 -S /data/3306/mysql.sock
mysql> create user oldgirl@localhost identified by 'old123';
# 登陆 3306 建立用户 oldgirl@localhost 。
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock
mysql> select user,host from mysql.user;
oldgirl | localhost
# 登陆 3307 查看用户: oldgirl@localhost 存在【说明主从同步了】。
去掉上面的注释,并重启 3306 数据库:
[root@centos ~]# grep ignore-db /data/3306/my.cnf
replicate-ignore-db = mysql
binlog-ignore-db = mysql
binlog-ignore-db = performance_schema
binlog-ignore-db = information_schema
[root@centos ~]# /data/3306/mysql restart
Stopping MySQL...
Starting MySQL...
此时,在主库上建立新的用户后,再到从库查看,新建的用户不会同步。
mysql> show slave status\G # 肯定是在主从同步正常的前提下不一样步用户的。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
6.4 Replication 中可经过如下选项减小 binlog 数据量
Master 端:
--binlog-do-db 二进制日志记录的数据库(多个库用逗号分隔)。
--binlog-ignore-db 二进制日志忽略的数据库(多个库用逗号分隔)。
Slave 端:
--replication-do-db 设定须要复制的数据库。
--replication-ignore-db 设定忽略复制的数据库。
--replication-do-table 设定须要复制的数据表。
--replication-ignore-table 设定忽略复制的数据表。
--replication-wild-do-table 同 --replication-do-table ,可是可加通配符。
--replication-wild-ignore-table 同 --replication-ignore-table ,可是可加通配符。
经过 read-only 参数防止数据写从库的方法:
在从库上设置 read-only 参数或者直接带 --read-only 参数启动或重启数据库。
① 在 my.cnf 里 [mysqld] 模块下加 read-only 参数并重启数据库:
[mysqld]
read-only
② 直接带 --read-only 参数启动或重启数据库:
mysqld_safe --default-file=/data/3307/my.cnf --read-only &
测试从库是否只读:
[root@centos ~]# mysql -uroot -p123456 -S /data/3306/mysql.sock # 登陆 3306.
mysql> show databases;
| Database |
| information_schema |
| mysql |
| oldboy |
| performance_schema |
| test |
mysql> drop database test; # 删除 test 库。
mysql> Bye
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock # 登陆 3307 。
mysql> show databases; # 可看到 test 库已删除(表示同步正常)。
| Database |
| information_schema |
| mysql |
| oldboy |
| performance_schema |
mysql> create database test; # 在从库可建库,这是为何?!
Query OK, 1 row affected (0.00 sec)
提示:因为从库设置了 read-only,非 SUPER 权限是没法写入的,root 用户有 SUPER 权限,因此依旧能够在配置 read-only 的从库写入数据。建立非 SUPER 权限的用户测试:
mysql> grant select,insert,update,delete on *.* to leilei@localhost identified by '123456';
# 建立用户受权增删改查。
mysql> flush privileges;
[root@centos ~]# mysql -uleilei -p123456 -S /data/3307/mysql.sock
mysql> select user();
| user() |
| leilei@localhost |
mysql> use test;
mysql> create table t(id int); # 没法建表(提示 read-only)
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
测试结论:
① 若想要从库只读,前提是主从同步正常。
② 在 my.cnf 里的 [mysqld] 模块下加入 read-only 参数后重启服务才能生效。
③ root 用户及 ALL 权限的用户能够插入及删除数据。
④ 具有 insert、update、delete 权限的用户没法经过 read-only 的限制。
7. 生产案例:MySQL 从库数据冲突致使同步中止
7.1 模拟错误,重现问题
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock # 登陆从库。
mysql> create database butongbu; # 建立 butongbu 库。
mysql> show databases;
| butongbu |
| mysql |
| oldboy |
mysql> show slave status\G # 检查同步状态(正常)。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
[root@centos ~]# mysql -uroot -p123456 -S /data/3306/mysql.sock
mysql> create database butongbu; # 在主库建立同名的库。
Query OK, 1 row affected (0.00 sec)
登陆从库便可看到出现的错误:
[root@centos ~]# mysql -uroot -p123456 -S /data/3307/mysql.sock
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_Errno: 1007
Last_Error: Error 'Can't create database 'butongbu'; database exists' on query. Default database: 'butongbu'. Query: 'create database butongbu'
MySQL 错误代号1007: MYSQL数据库已存在,建立数据库失败。
7.2 解决上述问题
7.2.1 方法一:添加忽略冲突次数为 1 忽略
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> set global sql_slave_skip_counter = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G # 能够看到主从同步恢复正常了。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_Errno: 0
① 对于普通的互联网业务,忽略问题不是很大,固然要确认不影响公司业务的前提下。
② 企业场景解决主从同步,比主从不一致更重要。若是主从数据一致也很重要,再找时间恢复从库。
③ 主从数据不一致和保持主从同步持续状态哪一个更总要须要根据不一样业务选择。
7.2.2 方法二:经过忽略错误号跳过指定的错误
[root@centos ~]# vi /data/3307/my.cnf
[root@centos ~]# grep slave-skip /data/3307/my.cnf
slave-skip-errors = 1032,1062,1007
[root@centos ~]# /data/3307/mysql stop
[root@centos ~]# /data/3307/mysql start
此时主库建立从库已经存在的数据库,就不会产生不一样步的问题(忽略 1007 错误)。
8. 从库开启 binlog 缘由及开启实战讲解
8.1 须要记录 binlog 的状况
① 当前主库还要做为其余从库的主库,也就是级联同步,须要开启 binlog;
② 把从库做为备份服务器时须要开启 binlog。
8.2 实践操做:在从库添加以下参数
[root@centos ~]# vi /data/3307/my.cnf
#log-bin = /data/3307/mysql-bin
#log-slave-updates
#expire_logs_days = 7
8.3 重启生效:
[root@centos ~]# /data/3307/mysql stop
[root@centos ~]# /data/3307/mysql start
9. 企业场景一主多从主库宕机,切换从库为主库继续主从同步过程详解
9.1 主库 master 宕机,登录从库查看两个线程的更新状态
mysql> show processlist;
State:Waiting for master to send event # IO 线程。
State:Has read all relay log;waiting for the slave I/O thread to update it # SQL 线程。
提示:上面的状态说明该从库是和主库同步的,或者说是最新的。
9.2 工做中肯定将哪一个从库提高为主库的方法
cat /data/3307/data/master.info
cat /data/3308/data/master.info
① 确保更新完毕,看看从库哪一个最快,通过测试没有延迟的状况 POS 差距很小,甚至是一致的。经过查看 master.info 的内容来肯定将哪一个(数据最新,跟主库一致性更高的)从库提高为主库。
② 其余方法:利用半同步的功能,直接选择作了实时同步的从库(太子)。
③ 提示:若是主库只是服务宕机,服务器正常,能够将主库服务器的 binlog 拉倒要提高为主库的从库,用来补全数据。
9.3 开始切换选择的从库为主库
① 确保全部 relay log 所有更新完毕:
在每一个从库上执行 stop slave io_thread;show processlist;直到看到 Slave has read all relay log 表示从库更新都执行完毕。
② 登陆选定的从库执行以下操做:
stop slave;
retset master;
quit;
还要受权同步用户 rep 和本来来的主库同样。
提示:若是提高为主库的从库存在忽略受权表,read-only 等设置,须要清理这些设置。
③ 进入到数据库目录,删除 master.info、relay-log.info
提示:检查受权表,read-only 等参数。
④ 编辑该从库的配置文件:
开启 log-bin 参数,若是存在 log-slave-updates、read-only 等必定要注释掉,重启后提高主库完毕。
⑤ 若是主库服务器没有宕机,须要去主库拉取 binlog 补全提高主库的从库数据。
⑥ 其余从库操做:
前提检查提高为主库的从库中同步用户 rep 已经存在。
登陆从库:
stop slave;
change master to master_host = '192.168.136.152'; # 若是数据不一样步就指定位置点。
start slave;
show slave status\G
⑦ 修改程序配置文件从主库指向从库、平时访问数据库用域名则可直接改 hosts 解析。
⑧ 修改损坏的主库,做为从库或从新切换为主库。
10. MySQL 5.5 以上支持半同步
半同步下的一主多从恢复,直接对设置半同步的从库肯定为主库。让某一个稳定的从库和主库彻底一致,即主库和这个从库都更新数据完毕后再返回给用户更新数据成功的消息。
半同步的优势:
确保至少一个从库和主数据库一致。
半同步的缺点:
主从之间网络延迟,或者从库有问题的时候会下降用户体验。(可设置超时时间为10秒)。