一、为什么需要主从复制单机MySQL在高并发场景下面临诸多挑战读写压力集中所有请求打到一台机器单点故障主库宕机服务完全不可用备份影响性能备份时锁表影响业务扩展性差无法水平扩展读能力主从复制解决的问题读写分离提升读性能数据冗余提高可用性从库备份不影响主库水平扩展读能力二、主从复制原理1. 复制流程主库Master 从库Slave │ │ │ 1. 写操作产生Binlog │ │ │ │ 2. Binlog Dump线程 │ │ ──────────────────────────────► │ │ │ 3. IO线程接收Binlog │ │ 写入Relay Log │ │ │ │ 4. SQL线程读取Relay Log │ │ 重放SQL语句2. 三种Binlog格式格式说明优点缺点STATEMENT记录SQL语句日志量小某些函数不安全NOW()等ROW记录行变更安全可靠日志量大MIXED混合模式折中方案复杂度高推荐使用ROW格式[mysqld] binlog_format ROW binlog_row_image FULL3. GTID复制GTIDGlobal Transaction ID是MySQL 5.6引入的全局事务标识GTID server_uuid:transaction_id 示例3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5GTID的优势自动定位复制位置无需手动指定binlog文件和位置故障切换更简单避免数据重复或丢失三、主从复制搭建1. 主库配置# /etc/mysql/my.cnf [mysqld] server-id 1 log-bin mysql-bin binlog-format ROW gtid-mode ON enforce-gtid-consistency ON log-slave-updates ON sync-binlog 1 innodb-flush-log-at-trx-commit 1 # 需要复制的数据库 binlog-do-db order_db binlog-do-db user_db # 不需要复制的数据库 binlog-ignore-db mysql binlog-ignore-db information_schema创建复制账号-- 创建复制用户CREATEUSERrepl%IDENTIFIEDBYrepl_password;GRANTREPLICATIONSLAVEON*.*TOrepl%;FLUSHPRIVILEGES;-- 查看主库状态SHOWMASTERSTATUS;2. 从库配置# /etc/mysql/my.cnf [mysqld] server-id 2 relay-log relay-bin log-bin mysql-bin gtid-mode ON enforce-gtid-consistency ON log-slave-updates ON read-only ON super-read-only ON # 复制过滤 replicate-do-db order_db replicate-do-db user_db建立复制关系-- 停止从库STOP SLAVE;-- 配置主库信息GTID模式CHANGE MASTERTOMASTER_HOST192.168.1.100,MASTER_USERrepl,MASTER_PASSWORDrepl_password,MASTER_PORT3306,MASTER_AUTO_POSITION1;-- 启动从库STARTSLAVE;-- 查看从库状态SHOWSLAVESTATUS\G关键状态字段Slave_IO_Running: Yes -- IO线程正常 Slave_SQL_Running: Yes -- SQL线程正常 Seconds_Behind_Master: 0 -- 复制延迟秒3. 数据初始化使用mysqldump初始化# 主库导出数据加锁保证一致性mysqldump-hmaster\--single-transaction\--master-data2\--all-databases\-uroot-pmaster_dump.sql# 从库导入数据mysql-hslave-uroot-pmaster_dump.sql使用XtraBackup推荐不锁表# 主库备份xtrabackup--backup\--target-dir/data/backup\--userroot\--passwordpassword# 准备备份xtrabackup--prepare--target-dir/data/backup# 传输到从库rsync-avz/data/backup/ slave:/data/mysql/# 从库恢复xtrabackup --copy-back --target-dir/data/backupchown-Rmysql:mysql /data/mysql四、主从延迟问题1. 延迟原因主库多线程并发写入 从库单线程串行重放MySQL 5.6之前MySQL 5.7并行复制# 从库配置 slave-parallel-type LOGICAL_CLOCK slave-parallel-workers 8 slave-preserve-commit-order ON2. 延迟监控-- 查看复制延迟SHOWSLAVESTATUS\G-- 关键指标Seconds_Behind_Master:0-- 延迟秒数Exec_Master_Log_Pos-- 已执行到的位置Read_Master_Log_Pos-- 已读取到的位置监控脚本#!/bin/bash# check_slave_lag.shSLAVE_HOST192.168.1.101THRESHOLD60# 延迟超过60秒告警LAG$(mysql -h${SLAVE_HOST}-eSHOW SLAVE STATUS\G|grepSeconds_Behind_Master|awk{print $2})if[${LAG}NULL];thenechoCRITICAL: 从库复制已停止exit2fiif[${LAG}-gt${THRESHOLD}];thenechoWARNING: 从库延迟${LAG}秒超过阈值${THRESHOLD}秒exit1fiechoOK: 从库延迟${LAG}秒exit03. 延迟解决方案方案1并行复制slave-parallel-type LOGICAL_CLOCK slave-parallel-workers 16方案2半同步复制-- 主库安装插件INSTALL PLUGIN rpl_semi_sync_masterSONAMEsemisync_master.so;SETGLOBALrpl_semi_sync_master_enabled1;SETGLOBALrpl_semi_sync_master_timeout1000;-- 从库安装插件INSTALL PLUGIN rpl_semi_sync_slaveSONAMEsemisync_slave.so;SETGLOBALrpl_semi_sync_slave_enabled1;方案3读写分离时处理延迟ServicepublicclassOrderService{AutowiredprivateDataSourcemasterDataSource;AutowiredprivateDataSourceslaveDataSource;publicOrdercreateOrder(OrderRequestrequest){// 写操作走主库OrderordermasterOrderMapper.insert(request);// 写完后短时间内的读也走主库避免读到旧数据ThreadLocalContext.setUseMaster(true);returnorder;}publicOrdergetOrder(LongorderId){// 检查是否需要走主库if(ThreadLocalContext.isUseMaster()){returnmasterOrderMapper.selectById(orderId);}// 普通读走从库returnslaveOrderMapper.selectById(orderId);}}五、主从切换1. 手动切换# 1. 停止主库写入mysql-hmaster-eFLUSH TABLES WITH READ LOCK;# 2. 等待从库追上主库mysql-hslave-eSHOW SLAVE STATUS\G|grepSeconds_Behind_Master# 3. 从库提升为主库mysql-hslave-eSTOP SLAVE; RESET SLAVE ALL;mysql-hslave-eSET GLOBAL read_only OFF;# 4. 其他从库指向新主库mysql-hslave2-eCHANGE MASTER TO MASTER_HOSTslave1...2. 自动切换MHA# mha.conf[server default]manager_workdir/var/log/mha manager_log/var/log/mha/manager.log master_binlog_dir/var/lib/mysql usermha passwordmha_password ssh_userroot repl_userrepl repl_passwordrepl_password ping_interval3[server1]hostname192.168.1.100 port3306[server2]hostname192.168.1.101 port3306 candidate_master1[server3]hostname192.168.1.102 port3306# 启动MHA Managermasterha_manager--conf/etc/mha/mha.conf# 检查状态masterha_check_status--conf/etc/mha/mha.conf六、常见问题Q1主从数据不一致怎么办# 使用pt-table-checksum检查一致性pt-table-checksum--hostmaster\--userroot\--passwordpassword\--databasesorder_db# 使用pt-table-sync修复不一致pt-table-sync--execute\--hostmaster\--userroot\--passwordpassword\--databasesorder_db\hslaveQ2从库复制报错怎么处理-- 查看错误信息SHOWSLAVESTATUS\G-- 跳过错误谨慎使用STOP SLAVE;SETGLOBALSQL_SLAVE_SKIP_COUNTER1;STARTSLAVE;-- 或者使用GTID跳过STOP SLAVE;SETGTID_NEXTxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:N;BEGIN;COMMIT;SETGTID_NEXTAUTOMATIC;STARTSLAVE;七、总结MySQL主从复制是高可用架构的基础复制原理Binlog → Relay Log → 重放SQLGTID复制更简单可靠的复制方式延迟优化并行复制 半同步复制自动切换MHA等工具实现自动故障转移最佳实践使用GTID模式简化运维开启并行复制减少延迟监控复制延迟及时告警定期演练主从切换思考题你们的MySQL是什么复制架构有没有遇到过主从延迟的问题个人观点仅供参考