MySQL主从复制原理
Mysql主从复制原理
基于二进制文件实现
Mysql的复制类型
- 基于语句的复制(TSATEMENT,Mysql的默认类型)
- 基于行的复制(ROW)
- 混合类型的复制(MIXED)
Mysql主从复制的工作过程
- Master节点将数据的改变记录成二进制日志(bin log),当Master上的数据发生改变时,则将其改变写入二进制日志中
- slave节点会在一定时间间隔内对Master的二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/O线程请求 Master的二进制事件
- 同时Master节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至slave节点本地的中继日志(Relay log)中,slave节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,即解析成 sql 语句逐一执行,使得其数据和 Master节点的保持一致,最后I/O线程和SQL线程将进入睡眠状态,等待下一次被唤醒
复制的用途
- 实时灾备,用于故障切换
- 可创建读写分离,提供更好的查询服务
- 把备份等操作都放在从服务器上进行,减少对业务的影响
复制存在的问题
- 主库宕机后,数据可能丢失
- 从库只有一个sql Thread,主库写压力大时,复制很可能延时
- 一主多从,从机不宜过多,主服务器需要同时向多台服务器中写入数据,压力会很大,这个时候推荐使用集群技,这个我之后会试做,在此不做描述
复制的原理
MySQL 主从复制(replication)是一个异步的复制过程。从一个实例(Master)复制到另一个实例(Slave),整个过程需要由 Master 上的 IO 进程 和 Slave 上的 Sql 进程 与 IO 进程 共同完成。 首先 Master 端必须打开 binary log(bin-log),因为整个复制过程实际上就是 Slave 端从 Master 端获取相应的二进制日志,然后在本地完全顺序的执行日志中所记录的各种操作。 原理图如下:
主从复制过程:
- Slave 端的 IO 进程连接上 Master,向 Master 请求指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
- Master 接收到来自 Slave 的 IO 进程的请求后,负责复制的 IO 进程根据 Slave 的请求信息,读取相应日志内容,返回给 Slave 的IO进程,并将本次请求读取的 bin-log 文件名及位置一起返回给 Slave 端;
- Slave 端的 IO 进程接收到信息后,将接收到的日志内容依次添加到 Slave 端的 relay-log(中继日志) 文件的最末端,并将读取到的 Master 端的 bin-log 的文件名和位置记录到 master-info 文件中,以便在下一次读取的时候能够清楚的告诉 Master :”我需要从某个 bin-log 的哪个位置开始往后的日志内容,请发给我”;
- Slave 端的 Sql 进程检测到 relay-log (中继日志)中新增加了内容后,会马上解析 relay-log 的内容成为在 Master 端真实执行时候的那些可执行的内容,并在本地执行。
过程产生三个线程(thread):
两个 IO线程:主库会创建一个线程,用来发送 binlog 内容到从库;从库I/O线程读取主库的 binlog 输出线程发送的更新并拷贝这些更新到本地文件,其中包括 relay-log(中继日志) 文件 一个 SQL线程:SQL负责将中继日志应用到 slave 数据库中,完成 AB (主从)复制数据同步。
主从复制的方式:
- 同步复制: Master 服务器操作完成,当操作作为事件写入二进制日志,传递给 slave,存放到中继日志中,然后在本地执行完操作,即反馈同步成功
- 半同步复制: 主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。 该功能不是 mysql 官方提供的,是5.5版本时由 google 研发半同步补丁后支持,需要 semi 插件
- 异步复制: 主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理
MySQL主从复制实践
在主服务器上进行设置:
编辑主服务器的 MySQL 配置文件
my.cnf
,一般位于/etc/mysql/my.cnf
或/etc/my.cnf
。
- 在
my.cnf
中,找到 [mysqld] 部分,并添加以下配置:
server-id = 1 # 主服务器设为1,从服务器可以设为不同的ID
log_bin = /var/log/mysql/mysql-bin.log # 启用二进制日志
binlog_do_db = your_database_name # 可选,指定需要复制的数据库
- 保存配置文件后,重启 MySQL 使配置生效:
sudo systemctl restart mysql
- 创建用于复制的用户,并授予适当的权限。登录到 MySQL:
mysql -u root -p
- 然后在 MySQL 提示符下执行以下命令:
CREATE USER 'replication_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'%';
FLUSH PRIVILEGES;
- 获取主服务器当前的二进制日志位置。在 MySQL 提示符下执行以下命令:
SHOW MASTER STATUS;
记下输出结果中的 File
和 Position
值,将在配置从服务器时用到。
在从服务器上进行设置:
编辑从服务器的 MySQL 配置文件
my.cnf
,同样位于/etc/mysql/my.cnf
或/etc/my.cnf
。
- 在
my.cnf
中,找到 [mysqld] 部分,并添加以下配置:
server-id = 2 # 从服务器设为不同的ID
- 停止从服务器的 MySQL 进程:
sudo systemctl stop mysql
- 清空从服务器的数据,这将删除现有的数据库数据:
sudo rm -rf /var/lib/mysql/*
- 在从服务器上配置连接到主服务器。在 MySQL 提示符下执行以下命令,将其中的参数替换为实际值:
CHANGE MASTER TO
MASTER_HOST = 'master_server_ip',
MASTER_USER = 'replication_user',
MASTER_PASSWORD = 'password',
MASTER_LOG_FILE = 'mysql-bin.XXXXXX', -- 使用主服务器上 SHOW MASTER STATUS 得到的值
MASTER_LOG_POS = log_position; -- 使用主服务器上 SHOW MASTER STATUS 得到的值
- 启动从服务器的 MySQL 进程:
sudo systemctl start mysql
- 在从服务器上运行以下命令开始主从复制:
START SLAVE; -- 开启复制
STOP SLAVE; -- 关闭复制
- 可以使用以下命令来检查主从复制状态:
-- 确保 "Slave_IO_Running" 和 "Slave_SQL_Running" 都显示为 "Yes",表示复制正在正常运行。
SHOW SLAVE STATUS;
在执行上述步骤时,请确保主服务器和从服务器之间的网络通信正常,防火墙允许数据库端口的通信,并在配置过程中使用正确的主机名、IP 地址和密码。如果遇到问题,可以查看 MySQL 日志以找出问题的根本原因。