MariaDB binlog与主从复制协同工作原理
2023-10-171.5k 阅读
MariaDB Binlog 概述
在 MariaDB 数据库中,二进制日志(Binlog,Binary Log)起着至关重要的作用。Binlog 主要用于记录数据库执行的写操作(如 INSERT、UPDATE、DELETE 等),这些记录以二进制的形式存储,用于数据备份、恢复以及主从复制等场景。
Binlog 有几种不同的格式,其中常见的有 STATEMENT、ROW 和 MIXED 格式。
- STATEMENT 格式:这种格式下,Binlog 记录的是实际执行的 SQL 语句。例如,执行
INSERT INTO users (name, age) VALUES ('John', 25);
,Binlog 中就会记录这条完整的 SQL 语句。它的优点是日志量相对较小,因为只记录 SQL 语句本身。但缺点也很明显,在一些情况下可能会导致主从数据不一致,比如使用了一些不确定的函数(如NOW()
),在主库和从库执行时可能会因为时间不同而得到不同的结果。 - ROW 格式:ROW 格式的 Binlog 记录的是数据行的变化。例如上述
INSERT
操作,Binlog 会记录插入的具体数据行('John', 25)
以及相关的表结构信息等。这种格式能最大程度保证主从数据的一致性,因为它记录的是数据实际的变化。但缺点是日志量较大,因为每行数据的变化都要详细记录。 - MIXED 格式:它结合了 STATEMENT 和 ROW 格式的特点,MariaDB 会根据执行的 SQL 语句来自动选择合适的格式进行记录。对于那些可能导致主从不一致的语句,如包含不确定函数的语句,会使用 ROW 格式记录;而对于其他普通的语句,则使用 STATEMENT 格式记录,以在保证数据一致性的同时尽量减少日志量。
MariaDB 主从复制基础
MariaDB 的主从复制是一种数据同步机制,通过将主库的数据变化同步到一个或多个从库,以实现数据的冗余备份、读写分离等功能。主从复制基于 Binlog 来实现,其基本过程可以分为以下几个步骤:
- 主库记录 Binlog:当主库上执行写操作时,会将这些操作记录到 Binlog 中。
- 从库连接主库:从库通过配置连接到主库,并告知主库它想要同步数据。
- 主库推送 Binlog 给从库:主库接收到从库的连接请求后,会根据从库提供的位置信息(通常是 Binlog 文件名称和偏移量),将从库尚未同步的 Binlog 事件推送给从库。
- 从库应用 Binlog:从库接收到主库推送的 Binlog 事件后,会将这些事件在本地的 Relay Log(中继日志)中记录下来,然后从库的 SQL 线程会按照 Relay Log 中的记录顺序,在从库上重新执行这些操作,从而实现数据的同步。
Binlog 与主从复制协同工作详细原理
- 主库写操作与 Binlog 记录
- 当主库接收到一个写操作请求,比如
INSERT INTO products (product_name, price) VALUES ('Widget', 10.99);
。首先,MariaDB 的查询执行引擎会解析和执行这条 SQL 语句,在内存中完成数据的插入操作,更新相关的数据页。 - 与此同时,Binlog 记录模块会将这个写操作记录到 Binlog 中。如果当前 Binlog 格式是 STATEMENT,那么 Binlog 中会直接记录这条
INSERT
语句;如果是 ROW 格式,会记录插入的具体数据行以及相关元数据,如表结构信息、事务相关信息等。Binlog 采用追加写的方式,新的记录会不断添加到 Binlog 文件末尾。
- 当主库接收到一个写操作请求,比如
- 从库连接主库
- 在从库配置文件(通常是
my.cnf
)中,需要设置主库的相关信息,如主库的 IP 地址、端口、用户名、密码以及起始同步位置等。例如:
- 在从库配置文件(通常是
[mysqld]
relay_log = /var/lib/mysql/mariadb-relay-bin
server_id = 2
log_slave_updates = 1
- 然后通过
CHANGE MASTER TO
语句来指定主库的详细信息,如下:
CHANGE MASTER TO
MASTER_HOST='master.example.com',
MASTER_USER='replication_user',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='master-bin.000001',
MASTER_LOG_POS=107;
- 这里
MASTER_HOST
是主库的主机名,MASTER_USER
和MASTER_PASSWORD
是用于主从复制的专用账号和密码,MASTER_LOG_FILE
和MASTER_LOG_POS
是从库开始同步的 Binlog 文件名称和偏移量。从库启动后,会根据这些配置信息连接到主库。
- 主库推送 Binlog 给从库
- 主库上有一个专门的线程叫做 Binlog Dump 线程。当从库连接到主库时,Binlog Dump 线程会根据从库提供的起始位置信息(
MASTER_LOG_FILE
和MASTER_LOG_POS
),从 Binlog 文件中读取尚未同步的 Binlog 事件。 - 例如,假设从库当前同步到
master-bin.000001
文件的偏移量为 107,而主库在这个位置之后又有新的写操作记录到 Binlog 中。Binlog Dump 线程会从偏移量 107 之后开始读取新的 Binlog 事件,并将这些事件以网络数据包的形式发送给从库。 - 主库会持续监听 Binlog 的变化,如果有新的写操作,会及时将相关的 Binlog 事件推送给从库,以保证从库的数据与主库尽可能实时同步。
- 主库上有一个专门的线程叫做 Binlog Dump 线程。当从库连接到主库时,Binlog Dump 线程会根据从库提供的起始位置信息(
- 从库接收与应用 Binlog
- 从库接收到主库推送的 Binlog 事件后,会将这些事件写入到本地的 Relay Log 中。Relay Log 的作用是作为一个临时存储区域,保存从主库接收到的 Binlog 事件。
- 从库有两个重要的线程:I/O 线程和 SQL 线程。I/O 线程负责从主库接收 Binlog 事件并写入 Relay Log,而 SQL 线程则负责从 Relay Log 中读取事件,并在从库上按照顺序重新执行这些事件,就像在主库上执行一样。
- 例如,从库接收到主库推送的
INSERT INTO products (product_name, price) VALUES ('Widget', 10.99);
这个 Binlog 事件,I/O 线程会将其写入 Relay Log,然后 SQL 线程会从 Relay Log 中读取这个事件,并在从库的products
表中执行插入操作,从而实现数据同步。
代码示例
- 配置主库
- 首先修改主库的
my.cnf
文件,添加或修改以下配置:
- 首先修改主库的
[mysqld]
log-bin = /var/lib/mysql/mariadb-bin
server_id = 1
- 这里
log-bin
指定了 Binlog 的存储路径和文件名前缀,server_id
是主库的唯一标识,每个参与主从复制的节点都要有不同的server_id
。修改完配置文件后,重启 MariaDB 服务。 - 创建用于主从复制的用户,在主库的 MariaDB 命令行中执行:
CREATE USER'replication_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO'replication_user'@'%';
FLUSH PRIVILEGES;
- 查看主库的 Binlog 状态,执行:
SHOW MASTER STATUS;
- 输出类似如下结果:
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mariadb-bin.000001 | 107 | | | |
+------------------+----------+--------------+------------------+-------------------+
- 这里的
File
和Position
信息将用于从库配置起始同步位置。
- 配置从库
- 修改从库的
my.cnf
文件,添加或修改以下配置:
- 修改从库的
[mysqld]
relay_log = /var/lib/mysql/mariadb-relay-bin
server_id = 2
log_slave_updates = 1
relay_log
指定了 Relay Log 的存储路径和文件名前缀,server_id
是从库的唯一标识,log_slave_updates
表示从库执行 Relay Log 中的事件时是否也记录到自己的 Binlog 中,一般开启以便从库可以作为其他从库的主库(级联复制)。修改完配置文件后,重启 MariaDB 服务。- 使用
CHANGE MASTER TO
语句配置主库信息,如:
CHANGE MASTER TO
MASTER_HOST='master.example.com',
MASTER_USER='replication_user',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS=107;
- 这里的
MASTER_LOG_FILE
和MASTER_LOG_POS
就是主库SHOW MASTER STATUS
输出的信息。 - 启动从库复制,执行:
START SLAVE;
- 查看从库状态,执行:
SHOW SLAVE STATUS \G;
- 重点关注
Slave_IO_Running
和Slave_SQL_Running
字段,如果都为Yes
,表示从库复制正常运行。同时还可以查看Seconds_Behind_Master
字段,它表示从库落后主库的时间(秒数),如果为 0 表示基本实时同步。
- 验证主从复制
- 在主库上创建一个测试表并插入数据,例如:
CREATE TABLE test_table (id INT PRIMARY KEY AUTO_INCREMENT, data VARCHAR(255));
INSERT INTO test_table (data) VALUES ('Test Data');
- 然后在从库上查询这个表,应该能看到相同的数据:
SELECT * FROM test_table;
- 如果能查询到插入的数据,说明主从复制配置成功,Binlog 与主从复制协同工作正常。
Binlog 与主从复制中的常见问题及解决
- 主从数据不一致
- 原因:
- Binlog 格式问题:如果使用 STATEMENT 格式,在一些情况下可能因为函数的不确定性导致主从数据不一致。例如主库上执行
INSERT INTO test (timestamp_col) VALUES (NOW());
,主库和从库执行这个语句时NOW()
的返回值可能不同。 - 网络延迟或故障:主库推送 Binlog 给从库过程中,网络延迟较大或者出现短暂中断,可能导致从库接收 Binlog 不及时或部分丢失,从而造成数据不一致。
- 从库 Relay Log 应用错误:从库在应用 Relay Log 中的事件时,如果遇到语法错误、数据类型不匹配等问题,可能会导致部分事件无法正确应用,进而数据不一致。
- Binlog 格式问题:如果使用 STATEMENT 格式,在一些情况下可能因为函数的不确定性导致主从数据不一致。例如主库上执行
- 解决方法:
- 选择合适的 Binlog 格式:对于可能出现不确定性的操作,建议使用 ROW 格式或 MIXED 格式。可以通过修改
my.cnf
文件中的binlog_format
参数来设置,例如binlog_format = ROW
,修改后重启 MariaDB 服务。 - 优化网络:检查网络连接,确保主从库之间网络稳定,延迟较小。可以通过
ping
命令、traceroute
命令等检查网络连通性和路由情况。如果网络存在问题,及时联系网络管理员解决。 - 排查从库 Relay Log 应用错误:查看从库的错误日志(通常在
var/log/mysql/error.log
),找出 Relay Log 应用失败的原因。如果是语法错误,修正主库执行的 SQL 语句;如果是数据类型不匹配,检查主从库的表结构是否一致,并进行相应调整。
- 选择合适的 Binlog 格式:对于可能出现不确定性的操作,建议使用 ROW 格式或 MIXED 格式。可以通过修改
- 原因:
- 从库复制延迟
- 原因:
- 主库写操作压力大:如果主库上有大量高并发的写操作,Binlog 生成速度过快,从库可能来不及及时接收和应用,导致延迟。
- 从库性能问题:从库的硬件性能(如 CPU、内存、磁盘 I/O 等)不足,在应用 Relay Log 时速度较慢,从而产生延迟。
- 网络带宽限制:主从库之间的网络带宽较小,限制了 Binlog 传输速度,导致从库接收 Binlog 不及时,产生延迟。
- 解决方法:
- 优化主库写操作:对主库上的写操作进行优化,例如批量插入数据而不是单个插入,合理使用事务等,减少 Binlog 的生成频率和量。可以对主库的查询进行分析,找出性能瓶颈并进行优化。
- 提升从库性能:检查从库的硬件资源使用情况,根据实际情况增加 CPU、内存等资源。优化从库的存储配置,例如使用更快的磁盘(如 SSD),调整数据库参数(如
innodb_buffer_pool_size
等)以提高从库的处理能力。 - 增加网络带宽:联系网络管理员,增加主从库之间的网络带宽,确保 Binlog 能够快速传输。同时,可以考虑使用更高效的网络协议或优化网络拓扑来提高数据传输效率。
- 原因:
Binlog 管理与维护
- Binlog 文件清理
- MariaDB 会自动管理 Binlog 文件,当 Binlog 文件达到一定大小或者满足某些配置条件时,会自动进行切换,生成新的 Binlog 文件。但是,旧的 Binlog 文件默认不会自动删除,需要手动清理。
- 可以通过
PURGE BINARY LOGS
语句来清理 Binlog 文件。例如,要删除所有早于mariadb-bin.000005
的 Binlog 文件,可以执行:
PURGE BINARY LOGS TO'mariadb-bin.000005';
- 也可以根据时间来清理,例如删除 7 天前的 Binlog 文件:
PURGE BINARY LOGS BEFORE '2023 - 10 - 01 00:00:00';
- 另外,还可以在
my.cnf
文件中配置expire_logs_days
参数,让 MariaDB 自动删除过期的 Binlog 文件。例如设置expire_logs_days = 7
,表示 7 天后自动删除 Binlog 文件。
- Binlog 备份与恢复
- 备份:可以使用
mysqlpump
或mysqldump
工具结合 Binlog 进行数据备份。例如,使用mysqldump
进行全量备份并记录 Binlog 位置:
- 备份:可以使用
mysqldump -uroot -p --all - databases --master - data > full_backup.sql
- 这个命令会生成一个全量备份文件
full_backup.sql
,同时在文件开头记录主库的 Binlog 位置信息。 - 恢复:假设数据库出现故障需要恢复,首先使用全量备份文件恢复数据:
mysql -uroot -p < full_backup.sql
- 然后根据备份文件中记录的 Binlog 位置信息,使用
mysqlbinlog
工具重放 Binlog 来恢复故障前的最新数据。例如,假设备份文件中记录的 Binlog 文件为mariadb-bin.000003
,位置为 107,执行:
mysqlbinlog --start - position = 107 mariadb - bin.000003 | mysql -uroot -p
- 这样就可以通过 Binlog 重放将数据恢复到故障前的状态。
总结 Binlog 与主从复制协同工作要点
Binlog 与主从复制在 MariaDB 数据库中是紧密协同工作的。Binlog 作为记录数据库写操作的关键机制,为主从复制提供了数据同步的基础。主从复制通过从库连接主库,主库推送 Binlog 事件,从库接收并应用这些事件的过程,实现了数据在多个节点之间的同步。
在实际应用中,正确配置 Binlog 格式、合理设置主从库参数、及时处理主从复制中出现的问题以及做好 Binlog 的管理与维护,对于保证数据库的高可用性、数据一致性以及性能优化都至关重要。通过深入理解 Binlog 与主从复制的协同工作原理,并结合实际场景进行优化和调整,可以构建出稳定、高效的 MariaDB 数据库集群。