概念
可拓展性和高可用
- MySQL主从复制主要用于数据读写分离的场景,即主库负责数据的写入,从库负责数据的读取,从而实现访问流量的分流,提高系统的整体负载能力。同时由于数据在主从节点都进行了冗余保存,避免了数据单点问题,提高了数据安全性。所以MySQL主从复制是可拓展性和高可用方面的一种实现方案。
基本工作流程
- 主从复制的基本工作过程为:主库处理所有的写请求,然后将该写请求异步复制给一台或多台从库,从库执行该写请求,从而保证与主库数据的最终一致性。
分布式数据一致性
- 由于主从复制是一种异步复制的过程,故从库数据可能与主机数据存在延迟,数据落后于主库,故不是数据强一致性的实现,而是最终一致性的一种实现。故适合于能容忍一定的数据延迟性的应用场景。如果既需要系统的高负载处理能力,即读写流量很大时依然能保证高性能处理能力,又需要保证数据强一致性,则通常需要使用分库分表来实现。
主从复制原理
二进制日志binlog
- MySQL主从复制是基于二进制日志binlog实现的,即使用二进制日志记录数据的修改操作,然后从主库同步该二进制日志给从库,从库根据二进制日志来执行对应的数据修改操作。
- 二进制日志的详细分析::MySQL二进制日志binlog的设计与实现
复制线程
- 由以上分析可知,主从复制是基于二进制日志实现的,主库异步复制二进制日志给从库,所以在主库从库之间首先需要建立一个连接,同时从库需要主动连接主库。
- 当从库连接主库时,除了建立连接之外,主库会创建一个复制线程来读取二进制日志并基于该连接传送给从库,从库也需要创建一个复制线程来接收主库传送过来的二进制日志,然后在从库保存为relay log,即重放日志。同时从库还需要一个对relay log进行解析并在从库执行对应的SQL的SQL线程。故这个过程涉及到了三个线程来完成主从之间的复制。
- 从库使用两个线程主要是为了加快二进制日志的同步和解析执行,降低数据延迟性。同时由于二进制日志同步加快,降低了主库在产生了大量二进制日志还没来得同步给从库而出现故障导致数据丢失的风险。
主从复制的基本步骤
1. 在主库创建用于复制的用户并授予复制权限
mysql> create user 'repl'@'192.168.0.1' identified by '123456';
Query OK, 0 rows affected (0.08 sec)
mysql> grant replication slave on *.* to 'repl'@'192.168.0.1';
Query OK, 0 rows affected (0.01 sec)
2. 创建主库某一时刻的完整数据快照备份和获取该时刻binlog的log position
数据库备份的获取:
如果可以停库的,则可以先停机获取全库冷备份的方式,具体为copy主库的全部数据库文件和日志文件到从库的指定位置;
如果不可以停库的,则需要通过mysqldump或者其他工具来创建该时刻的数据库快照,同时为了保证数据的完整性和数据一致性,需要使用FLUSH TABLES WITH READ LOCK命令来锁住所有表禁止写操作。如下为加锁和解锁操作:
mysql> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.00 sec) mysql> UNLOCK TABLES; Query OK, 0 rows affected (0.00 sec)
binlog的log position表示该时刻主库的binlog写到什么位置了,具体为在主库执行:show master status命令来获取。对于停机需要在重启还没写入操作之前执行,对于非停库方式,则在锁表期间执行。命名如下:
mysql> show master status; +——————+———-+————–+——————+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +——————+———-+————–+——————+ | mysql-bin.000001 | 79 | | | +——————+———-+————–+——————+ 1 row in set (0.00 sec)
3. 将数据快照导入从库
- 从库数据导入的方式需要根据主库所提供的数据库快照的格式来决定。
4. 启动从库并连接主库,并设置好从库对主库的binlog的log position
启动从库后,主要通过执行CHANGE MASTER TO命令来连接主库,如下:
mysql> CHANGE MASTER TO -> MASTER_HOST='192.168.0.1', -> MASTER_USER='repl', -> MASTER_PASSWORD='123456', -> MASTER_LOG_FILE='mysql-bin.000001', -> MASTER_LOG_POS=79;