[TOC]
09:mysql之主从复制
今日工作任务路线图

一、工作场景
在一家电商公司,其业务涵盖商品展示、订单处理、用户管理等,数据库中存储着海量的商品信息、用户数据和交易记录。随着业务的快速发展,数据库的读写压力与日俱增。为了缓解数据库压力,提高系统的可用性和数据安全性,公司决定采用 MySQL 主从复制架构。
主数据库负责处理所有的写操作,如商品信息更新、订单创建等。从数据库则实时同步主数据库的数据,负责处理大量的读操作,如商品查询、用户信息展示等。通过这种方式,有效地分担了数据库的负载,提高了系统的响应速度。同时,当主数据库出现故障时,可以快速将业务切换到从数据库,保障业务的连续性。
二、为什么学
学习 MySQL 主从复制有诸多重要意义。在企业应用层面,随着业务增长,数据库面临读写压力大的问题,主从复制可将读操作分发到从库,减轻主库负担,提升系统性能和响应速度,保障业务流畅运行。在数据安全与备份方面,从库是主库数据的实时副本,当主库出现故障,可快速切换到从库继续服务,降低数据丢失风险,保证业务连续性。此外,掌握主从复制也是提升个人技术能力的关键一步,如今数据库技术广泛应用,精通此技术能增强职场竞争力,为从事数据库管理、开发等工作奠定坚实基础。
三、binlog【宾-劳格】日志
当前任务环节

binlog【宾-劳格】日志介绍:
- 也称做 二进制日志
- MySQL服务日志文件的一种
- 保存除查询之外的所有SQL命令m
- 可用于数据的备份和恢复
- 配置mysql主从同步的必要条件
- 准备新的数据库服务器如表-1,做binlog【宾-劳格】
| 主机名 | IP地址 | 说明 |
|---|---|---|
| mysql52 | 192.168.90.52 | 练习binlog【宾-劳格】日志 |
mysql52的IP配置和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.52/24 autoconnect【奥特欧 坑聂特】 yes#[root@slave2 ~]# nmcli connection modify ens160 ipv4.addresses 192.168.90.52/24 autoconnect yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160#[root@slave2 ~]# nmcli connection up ens160[root@mysql52 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql52#[root@slave2 ~]# hostnamectl set-hostname mysql523.1 查看正在使用的binlog【宾-劳格】日志文件
在新创建的数据库服务器做如下操作:
# 安装软件[root@mysql52 ~]# yum -y install【因-斯多】 mysql-server# [root@slave2 ~]# yum -y install mysql-server
# 启动服务[root@mysql52 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld# [root@slave2 ~]# systemctl status mysqld
# 连接服务[root@mysql52 ~]# mysql# [root@mysql52 ~]# mysql
# 查看日志文件mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;# mysql> show master status;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| binlog.000001 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
# 执行查询命令mysql> select【涩莱克特】 count【kàn特】(*) from【弗乱】 mysql.user;# mysql> select count(*) from mysql.user;+-------------------+| count【kàn特】(*) |+-------------------+| 4 |+-------------------+1 row in set (0.00 sec)
# 执行查询命令 日志偏移量不变mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;# mysql> show master status;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| binlog.000001 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
# 执行建库、建表命令mysql> create【克瑞特】 database【得塔-贝斯】 db1;# mysql> create database db1;Query OK, 1 row affected (0.07 sec)
mysql> create【克瑞特】 table【忒-部】 db1.user(name char【查尔】(10));# mysql> create table db1.user(name char(10));Query OK, 0 rows affected (0.52 sec)
# 执行写命令 日志偏移量改变mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;# mysql> show master status;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| binlog.000001 | 535 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
# 插入记录mysql> insert【因涩特】 into【因兔】 db1.user values【挖柳斯】("jim");# mysql> insert into db1.user values("jim");Query OK, 1 row affected (0.10 sec)
# 执行写命令 日志偏移量改变mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;# mysql> show master status;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| binlog.000001 | 809 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)mysql>3.2 自定义日志目录和日志名
日志文件默认保存在/var/lib/mysql目录下,默认日志名binlog【宾-劳格】
[root@mysql52 ~]# vim /etc/my.cnf.d/mysql-server.cnf[mysqld]log-bin=/mylog/mysql52 #定义日志目录和日志文件名(手动添加):wq
[root@mysql52 ~]# mkdir【摸克跌儿】 /mylog 创建目录[root@mysql52 ~]# chown【吃-昂】 mysql /mylog 修改目录所有者mysql用户[root@mysql52 ~]# setenforce【赛特-因佛尔斯】 0 关闭selinux[root@mysql52 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld 重启服务[root@mysql52 ~]# ls /mylog/ 查看日志目录mysql52.000001 mysql52.index[root@mysql52 ~]# mysql 登陆服务
Mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】 ; 查看日志信息+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000001 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+3.3 手动创建新的日志文件
默认日志文件容量大于1G时会自动创建新的日志文件,在日志文件没写满时,执行的所有写命令都会保存到当前使用的日志文件里。
#刷新前查看mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000001 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
mysql> flush【福 辣 徐】 logs【劳格斯】; #刷新日志Query OK, 0 rows affected (0.22 sec)
mysql> flush【福 辣 徐】 logs【劳格斯】; #刷新日志Query OK, 0 rows affected (0.16 sec)
mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】; #刷新一次创建一个新日志+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000003 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
#只要服务重启就会创建新日志[root@mysql52 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld[root@mysql52 ~]# mysql 连接服务
Mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】; 查看日志+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000004 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+[root@mysql52 ~]#
#完全备份后创建新的日志文件,创建的日志个数和备份库的个数一致[root@mysql52 ~]# mysqldump【mysql-当普】 --flush【福 辣 徐】-logs【劳格斯】 mysql user > user.sql
[root@mysql52 ~]# mysql -e 'show【瘦】 master【马斯特】 status【 斯dèi 特斯】'+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000005 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+[root@mysql52 ~]# mysqldump【mysql-当普】 --flush【福 辣 徐】-logs【劳格斯】 -B mysql db1 > db_2.sql
[root@mysql52 ~]# mysql -e 'show【瘦】 master【马斯特】 status【 斯dèi 特斯】'+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000007 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+[root@mysql52 ~]#3.4 日志相关命令的使用
MySQL服务提供了管理日志的专属命令,具体练习如下:
#查看已有的日志文件mysql> show【瘦】 binary【拜讷瑞】 logs【劳格斯】;日志文件名 日志大小(字节) 加密(no/yes)+----------------+-----------+-----------+| Log_name | File_size | Encrypted |+----------------+-----------+-----------+| mysql52.000001 | 201 | No || mysql52.000002 | 201 | No || mysql52.000003 | 179 | No || mysql52.000004 | 201 | No || mysql52.000005 | 201 | No || mysql52.000006 | 201 | No || mysql52.000007 | 156 | No |+----------------+-----------+-----------+7 rows in set (0.00 sec)
#查看正在使用的日志mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000007 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
#插入记录mysql> insert【因涩特】 into【因兔】 db1.user values【挖柳斯】("yaya");Query OK, 1 row affected (0.04 sec)
#查看日志文件内容mysql> show【瘦】 binlog【宾-劳格】 events【伊文茨】 in "mysql52.000007";Log_name: 日志文件名。Pos: 命令在日志文件中的起始位置。Event_type: 事件类型,例如 Query、Table_map、Write_rows 等。Server_id: 服务器 ID。End_log_pos:命令在文件中的结束位置,以字节为单位。Info:执行命令信息。+----------------+-----+----------------+-----------+-------------+--------------------------------------+| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |+----------------+-----+----------------+-----------+-------------+--------------------------------------+| mysql52.000007 | 4 | Format_desc | 1 | 125 | Server ver: 8.0.26, Binlog ver: 4 || mysql52.000007 | 125 | Previous_gtids | 1 | 156 | || mysql52.000007 | 156 | Anonymous_Gtid | 1 | 235 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' || mysql52.000007 | 235 | Query | 1 | 306 | BEGIN || mysql52.000007 | 306 | Table_map | 1 | 359 | table_id: 108 (db1.user) || mysql52.000007 | 359 | Write_rows | 1 | 400 | table_id: 108 flags: STMT_END_F || mysql52.000007 | 400 | Xid | 1 | 431 | COMMIT /* xid=649 */ |+----------------+-----+----------------+-----------+-------------+--------------------------------------+7 rows in set (0.00 sec)
#删除日志文件名之前的所有日志文件mysql> purge【pò取】 master【马斯特】 logs【劳格斯】 to "mysql52.000004";Query OK, 0 rows affected (0.10 sec)
#查看已有的日志文件mysql> show【瘦】 binary【拜讷瑞】 logs【劳格斯】;+----------------+-----------+-----------+| Log_name | File_size | Encrypted |+----------------+-----------+-----------+| mysql52.000004 | 201 | No || mysql52.000005 | 201 | No || mysql52.000006 | 201 | No || mysql52.000007 | 431 | No |+----------------+-----------+-----------+4 rows in set (0.00 sec)
#删除所有日志文件,并重新创建日志文件mysql> reset【瑞 赛特】 master【马斯特】;Query OK, 0 rows affected (0.14 sec)
#查看已有的日志文件 ,仅有第1个文件了mysql> show【瘦】 binary【拜讷瑞】 logs【劳格斯】;+----------------+-----------+-----------+| Log_name | File_size | Encrypted |+----------------+-----------+-----------+| mysql52.000001 | 156 | No |+----------------+-----------+-----------+1 row in set (0.00 sec)3.5 使用日志恢复数据
把查看到的文件内容管道给连接mysql服务的命令执行
恢复数据命令:
mysqlbinlog【宾-劳格】 /目录/文件名 | mysql –uroot -p密码
1)在mysql52主机执行如下操:
#重置日志mysql> reset【瑞 赛特】 master【马斯特】;Query OK, 0 rows affected (0.09 sec)
#查看日志mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql52.000001 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
#建库、mysql> create【克瑞特】 database【得塔-贝斯】 gamedb;Query OK, 1 row affected (0.07 sec)
#建表mysql> create【克瑞特】 table【忒-部】 gamedb.t1(name char【查尔】(10),class【克拉斯】 char【查尔】(3));Query OK, 0 rows affected (0.55 sec)
#插入记录mysql> insert【因涩特】 into【因兔】 gamedb.t1 values【挖柳斯】 ("yaya","nsd");Query OK, 1 row affected (0.08 sec)
mysql> insert【因涩特】 into【因兔】 gamedb.t1 values【挖柳斯】 ("yaya","nsd");Query OK, 1 row affected (0.04 sec)
mysql> insert【因涩特】 into【因兔】 gamedb.t1 values【挖柳斯】 ("yaya","nsd");Query OK, 1 row affected (0.08 sec)
#查看表记录mysql> select【涩莱克特】 * from【弗乱】 gamedb.t1;+------+----------------+| name | class【克拉斯】 |+------+----------------+| yaya | nsd || yaya | nsd || yaya | nsd |+------+----------------+3 rows in set (0.00 sec)mysql> exit【诶西特】#把日志文件拷贝给恢复数据的服务器,比如 mysql50[root@mysql52 ~]# scp /mylog/mysql52.000001 root@192.168.90.50:/root/The authenticity of host '192.168.90.50 (192.168.90.50)' can't be established.ECDSA key fingerprint is SHA256:t7J3okFd0o+9zTmFCIetvDl6mxGCmc43VoD6C65zico.Are you sure you want to continue connecting (yes/no/[fingerprint])? Yes 同意Warning: Permanently added '192.168.90.50' (ECDSA) to the list of known hosts.root@192.168.90.50's password: mysql50的密码mysql52.000001 100% 1410 1.6MB/s 00:00[root@mysql52 ~]#2)在MySQL50 使用日志恢复数据
#查看日志[root@mysql50 ~]# ls /root/mysql52.000001/root/mysql52.000001
#执行日志恢复数据[root@mysql50 ~]# mysqlbinlog【mtsql宾-劳格】 /root/mysql52.000001 | mysql -uroot -pNSD123456...amysql: [Warning] Using a password on【昂】 the command line interface can be insecure.
#连接服务查看数据[root@mysql50 ~]# mysql -uroot -pNSD123456...a -e 'selectt【涩莱克特】 * from【弗乱】 gamedb.t1'mysql: [Warning] Using a password on【昂】 the command line interface can be insecure. +------+----------------+| name | class【克拉斯】 | +------+----------------+| yaya | nsd || yaya | nsd || yaya | nsd | +------+----------------+[root@mysql50 ~]#四、MySQL一主一从
当前任务环节

4.1 mysql主从复制原理
MySQL主从复制基于二进制日志(binlog【宾-劳格】)实现。主要分为三步: 首先,主库上执行更新操作时,会将变更记录到二进制日志日志里。 其次,从库的I/O线程会连接主库,请求主库发送二进制日志日志。主库的二进制日志转储线程将日志内容发送给从库I/O线程,I/O线程把接收的日志写入从库的中继日志(Relay Log)。 最后,从库的SQL线程读取中继日志中的事件,并在从库上重放,实现主从数据一致。
mysql主从复制原理
- 主库将数据变更(DDL和DML)记录到二进制日志(binlog)中。
- 从库的I/O线程向主库的log dump线程请求binlog。
- 主库的log dump线程将binlog事件发送给从库的I/O线程。
- 从库的I/O线程将接收到的事件写入中继日志(relay log)。
- 从库的SQL线程读取并解析relay log中的事件,在从库上执行这些事件,从而使从库与主库的数据保持同步。

准备两台服务器
| 主机名 | IP地址 | 说明 |
|---|---|---|
| mysql53 | 192.168.90.53 | master【马斯特】数据库 |
| mysql54 | 192.168.90.54 | slave【斯累夫】数据库 |
mysql53的IP配置和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.53/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mysql53 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql53mysql54的IP配置和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.54/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mysql54 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql544.2 配置为主数据库服务器
数据库服务器192.168.90.53配置为主数据库服务器
1)启用binlog【宾-劳格】日志
[root@mysql53 ~]# yum -y install【因-斯多】 mysql-server mysql[root@mysql53 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld[root@mysql53 ~]# vim /etc/my.cnf.d/mysql-server.cnf[mysqld]server-id=53log-bin=mysql53:wq[root@mysql53 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld2)用户授权
[root@mysql53 ~]# mysql
mysql> create【克瑞特】 user repluser@"%" identified【爱-丹-提伐】 WITH【威付】 mysql_native_password by "123qqq...A";Query OK, 0 rows affected (0.11 sec)
mysql> grant【古亮普】 replication【瑞普利K申】 slave【斯累夫】 on【昂】 *.* to repluser@"%";Query OK, 0 rows affected (0.09 sec)3)查看日志信息
mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql53.000001 | 667 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)4.3 配置为从数据库服务
数据库服务器192.168.90.54配置为从数据库服务
1)指定server-id 并重启数据库服务
[root@mysql54 ~]# yum -y install【因-斯多】 mysql-server mysql[root@mysql54 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld[root@mysql54 ~]# vim /etc/my.cnf.d/mysql-server.cnf[mysqld]server-id=54:wq[root@mysql54 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld2)登陆服务指定主服务器信息
[root@mysql54 ~]# mysqlmysql> change【趁(chèn)吉】 master【马斯特】 to master【马斯特】_host="192.168.90.53" , master【马斯特】_user="repluser" , master【马斯特】_password="123qqq...A" ,master【马斯特】_log_file="mysql53.000001" , master【马斯特】_log_pos=667;Query OK, 0 rows affected, 8 warnings (0.34 sec)
mysql> start【s 达儿】 slave【斯累夫】 ; #启动slave【斯累夫】进程Query OK, 0 rows affected, 1 warning (0.04 sec)
mysql> show【瘦】 slave【斯累夫】 status【 斯dèi 特斯】 \G #查看状态信息*************************** 1. row *************************** Slave【斯累夫】_IO_State: Waiting for source to send event master【马斯特】_Host: 192.168.90.53 master【马斯特】_User: repluser master【马斯特】_Port: 3306 Connect_Retry: 60 master【马斯特】_Log_File: mysql53.000001 Read_master【马斯特】_Log_Pos: 667 Relay_Log_File: mysql54-relay-bin.000002 Relay_Log_Pos: 322 Relay_master【马斯特】_Log_File: mysql53.000001 Slave【斯累夫】_IO_Running: Yes #IO线程 Slave【斯累夫】_SQL_Running: Yes #SQL线程 Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_master【马斯特】_Log_Pos: 667 Relay_Log_Space: 533 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 master【马斯特】_SSL_Allowed: No master【马斯特】_SSL_CA_File: master【马斯特】_SSL_CA_Path: master【马斯特】_SSL_Cert: master【马斯特】_SSL_Cipher: master【马斯特】_SSL_Key: Seconds_Behind_master【马斯特】: 0master【马斯特】_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: master【马斯特】_Server_Id: 53 master【马斯特】_UUID: 38c02165-005e-11ee-bd2d-525400007271 master【马斯特】_Info_File: mysql.slave【斯累夫】_master【马斯特】_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave【斯累夫】_SQL_Running_State: Replica has read all【ò】 relay log; waiting for more updates master【马斯特】_Retry_Count: 86400 master【马斯特】_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: master【马斯特】_SSL_Crl: master【马斯特】_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: master【马斯特】_TLS_Version: master【马斯特】_public_key_path: Get_master【马斯特】_public_key: 0 Network_Namespace:1 row in set, 1 warning (0.00 sec)mysql>4.4 客户端192.168.90.50测试配置
1)在主服务器添加用户,给客户端连接使用
[root@mysql53 ~]# mysqlmysql> create【克瑞特】 user jam@"%" identified【爱-丹-提伐】 by "123456";Query OK, 0 rows affected (0.14 sec)
mysql> grant【古亮普】 all【ò】 on【昂】 gamedb.* to jam@"%" ;Query OK, 0 rows affected (0.12 sec)mysql>2)客户端连接主服务器存储数据
[root@mysql50 ~]# mysql -h192.168.90.53 -ujam -p123456mysql> create【克瑞特】 database【得塔-贝斯】 gamedb;Query OK, 1 row affected (0.24 sec)
mysql> create【克瑞特】 table【忒-部】 gamedb.user(name char【查尔】(10) , class【克拉斯】 char【查尔】(3));Query OK, 0 rows affected (1.71 sec)
mysql> insert【因涩特】 into【因兔】 gamedb.user values【挖柳斯】 ("yaya","nsd");Query OK, 1 row affected (0.14 sec)
mysql> select【涩莱克特】 * from【弗乱】 gamedb.user;+------+-------+| name | class【克拉斯】 |+------+-------+| yaya | nsd |+------+-------+1 row in set (0.01 sec)mysql>3)客户端连接从服务器查看数据
-e 命令行下执行数据库命令
[root@mysql50 ~]# mysql -h192.168.90.54 -ujam -p123456 –e ‘select【涩莱克特】 * from【弗乱】 gamedb.user’+------+-------+| name | class【克拉斯】 |+------+-------+| yaya | nsd |+------+-------+[root@mysql54 ~]#五、配置一主多从结构
当前任务环节

准备新的服务器
| 主机名 | IP地址 | 说明 |
|---|---|---|
| mysql55 | 192.168.90.55 | 从数据库 |
mysql55的IP配置和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.55/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mysql55 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql55
5.1 配置192.168.90.55从服务器
1)指定MySQL55主机的server-id 并重启数据库服务
root@mysql55 ~]# yum -y install【因-斯多】 mysql-server[root@mysql55 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld[root@mysql55 ~]# vim /etc/my.cnf.d/mysql-server.cnf[mysqld]server-id=55:wq[root@mysql55 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld2)确保与主服务器数据一致。
#在mysql53执行备份命令前查看日志名和偏移量 ,mysql55 在当前查看到的位置同步数据[root@mysql53 ~]# mysql -e 'show【瘦】 master【马斯特】 status【 斯dèi 特斯】'+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql53.000002 | 156 | | | |+----------------+----------+--------------+------------------+-------------------+[root@mysql53 ~]#
#在主服务器存做完全备份[root@mysql53 ~]# mysqldump【mysql-当普】 -B gamedb > /root/gamedb.sql
#主服务器把备份文件拷贝给从服务器mysql55[root@mysql53 ~]# scp /root/gamedb.sql root@192.168.90.55:/root/[root@mysql55 ~]# mysql < /root/gamedb.sql3)在MySQL55主机指定主服务器信息
[root@mysql55 ~]# mysql
mysql> change【趁(chèn)吉】 master【马斯特】 to master【马斯特】_host="192.168.90.53" , master【马斯特】_user="repluser" , master【马斯特】_password="123qqq...A" , master【马斯特】_log_file="mysql53.000002" , master【马斯特】_log_pos=156;Query OK, 0 rows affected, 8 warnings (0.44 sec)
注意:日志名和偏移量 要写 在mysql53主机执行完全备份之前查看到的日志名和偏移量
mysql> start【s 达儿】 slave【斯累夫】; #启动slave【斯累夫】进程Query OK, 0 rows affected, 1 warning (0.02 sec)
#查看状态信息mysql> show【瘦】 slave【斯累夫】 status【 斯dèi 特斯】 \G*************************** 1. row *************************** Slave【斯累夫】_IO_State: Waiting for source to send event master【马斯特】_Host: 192.168.90.53 master【马斯特】_User: repluser master【马斯特】_Port: 3306 Connect_Retry: 60 master【马斯特】_Log_File: mysql53.000002 Read_master【马斯特】_Log_Pos: 156 Relay_Log_File: mysql55-relay-bin.000002 Relay_Log_Pos: 322 Relay_master【马斯特】_Log_File: mysql53.000002 Slave【斯累夫】_IO_Running: Yes #正常 Slave【斯累夫】_SQL_Running: Yes #正常 Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_master【马斯特】_Log_Pos: 156 Relay_Log_Space: 533 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 master【马斯特】_SSL_Allowed: No master【马斯特】_SSL_CA_File: master【马斯特】_SSL_CA_Path: master【马斯特】_SSL_Cert: master【马斯特】_SSL_Cipher: master【马斯特】_SSL_Key: Seconds_Behind_master【马斯特】: 0master【马斯特】_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: master【马斯特】_Server_Id: 53 master【马斯特】_UUID: 38c02165-005e-11ee-bd2d-525400007271 master【马斯特】_Info_File: mysql.slave【斯累夫】_master【马斯特】_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave【斯累夫】_SQL_Running_State: Replica has read all【ò】 relay log; waiting for more updates master【马斯特】_Retry_Count: 86400 master【马斯特】_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: master【马斯特】_SSL_Crl: master【马斯特】_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: master【马斯特】_TLS_Version: master【马斯特】_public_key_path: Get_master【马斯特】_public_key: 0 Network_Namespace:1 row in set, 1 warning (0.00 sec)
#添加客户端访问时使用的用户mysql> create【克瑞特】 user jam@"%" identified【爱-丹-提伐】 by "123456";Query OK, 0 rows affected (0.08 sec)
mysql> grant【古亮普】 all【ò】 on【昂】 gamedb.* to jam@"%" ;Query OK, 0 rows affected (0.04 sec)Mysql>5.2 客户端测试配置
1)在mysql50 连接主服务器mysql53 存储数据
#连接主服务器存储数据[root@mysql50 ~]# mysql -h192.168.90.53 -ujam -p123456
mysql> insert【因涩特】 into【因兔】 gamedb.user values【挖柳斯】("tt","aid");Query OK, 1 row affected (0.14 sec)
mysql> insert【因涩特】 into【因兔】 gamedb.user values【挖柳斯】("mm","uid");Query OK, 1 row affected (0.13 sec)2)在client50 分别连接2个从服务器查看数据
#连接从服务器54查看数据[root@mysql50 ~]# mysql -h192.168.90.54 -ujam -p123456 -e 'select【涩莱克特】 * from【弗乱】 gamedb.user'mysql: [Warning] Using a password on【昂】 the command line interface can be insecure.+------+-------+| name | class【克拉斯】 |+------+-------+| yaya | nsd || tt | aid || mm | uid |+------+-------+
#连接从服务器55查看数据[root@mysql50 ~]# mysql -h192.168.90.55 -ujam -p123456 -e 'select【涩莱克特】 * from【弗乱】 gamedb.user'mysql: [Warning] Using a password on【昂】 the command line interface can be insecure.+------+-------+| name | class【克拉斯】 |+------+-------+| yaya | nsd || tt | aid || mm | uid |+------+-------+[root@mysql50 ~]#
#我 : 按照上面的方法设置主从同步,之后新加的数据会同步从库,那要是在设置主从之前的数据呢?也会同步吗?
#Doubao : 在设置 MySQL 主从同步时,设置同步之前主库已存在的数据是否会同步到从库,取决于具体的配置和操作步骤,下面为你详细分析不同情况:
设置主从同步之前的数据不会自动同步
如果只是简单地配置主从同步的连接信息(如设置从库的 CHANGE MASTER TO 语句),而没有做额外的数据初始化操作,那么设置主从同步之前主库上已存在的数据不会自动同步到从库。这是因为主从同步是基于二进制日志(binlog)来记录和同步主库上的更改操作,在配置主从同步时,从库会从指定的二进制日志文件和位置开始读取并应用主库的更改,而设置之前的历史数据并没有被包含在这个起始点之后的二进制日志中。
可以通过特定操作实现同步
为了让设置主从同步之前主库上的数据也能同步到从库,可以采取以下常见方法:
1. 使用 mysqldump 备份和恢复
- 步骤:
- 在主库上锁定表并进行备份:为了保证数据的一致性,在备份过程中需要锁定主库上的表,防止数据被修改。
# 登录主库,锁定所有表mysql -u root -p -e "FLUSH TABLES WITH READ LOCK;"# 记录当前二进制日志文件和位置mysql -u root -p -e "SHOW MASTER STATUS;"# 使用 mysqldump 备份主库数据mysqldump -u root -p --all-databases > master_backup.sql# 解锁主库上的表mysql -u root -p -e "UNLOCK TABLES;"2. **将备份文件传输到从库**:可以使用 `scp` 等工具将备份文件从主库复制到从库。scp master_backup.sql user@slave_ip:/path/to/destination3. **在从库上恢复备份数据**:登录从库,执行备份文件中的 SQL 语句。mysql -u root -p < master_backup.sql4. **配置从库连接主库**:使用之前记录的二进制日志文件和位置,配置从库连接主库。CHANGE MASTER TO MASTER_HOST='master_ip', MASTER_USER='replication_user', MASTER_PASSWORD='replication_password', MASTER_LOG_FILE='binlog_file_name', MASTER_LOG_POS=binlog_position;START SLAVE;2. 使用 rsync 复制数据文件(适用于 InnoDB 存储引擎)
- 步骤:
- 停止主库和从库的 MySQL 服务:为了避免数据冲突,需要先停止主库和从库的 MySQL 服务。
systemctl stop mysql2. **使用 `rsync` 复制主库的数据文件到从库**:确保主库和从库的数据目录结构一致。rsync -avz /var/lib/mysql/ user@slave_ip:/var/lib/mysql/3. **启动从库的 MySQL 服务**:启动从库的 MySQL 服务,并配置从库连接主库。systemctl start mysqlCHANGE MASTER TO MASTER_HOST='master_ip', MASTER_USER='replication_user', MASTER_PASSWORD='replication_password', MASTER_LOG_FILE='binlog_file_name', MASTER_LOG_POS=binlog_position;START SLAVE;通过以上方法,可以将设置主从同步之前主库上的数据同步到从库,实现主从库数据的一致性。
异步复制、半同步复制、完全同步复制
#我 : MySQL 主从复制采用异步复制是什么?有同步复制吗?区别和优缺点是什么?
#Doubao :
MySQL 主从复制中的异步复制
概念
在 MySQL 主从复制的异步复制模式下,主库在执行完客户端提交的事务后,会立即将结果返回给客户端,而不会等待从库接收并处理该事务的二进制日志(binlog)。主库会将事务的变更记录到二进制日志中,然后异步地将这些日志发送给从库,从库会在自己的线程中独立地接收和应用这些日志。
示例代码配置
-- 在主库上创建用于复制的用户CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';FLUSH PRIVILEGES;
-- 查看主库的二进制日志信息SHOW MASTER STATUS;
-- 在从库上配置主从复制CHANGE MASTER TO MASTER_HOST='master_ip', MASTER_USER='repl_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='master_binlog_file_name', MASTER_LOG_POS=master_binlog_position;
START SLAVE;MySQL 中的同步复制
概念
严格意义上,MySQL 原生的复制模式默认是异步复制,但 MySQL 也提供了半同步复制(Semi-synchronous Replication),可以看作是一种介于异步和完全同步之间的模式。在半同步复制中,主库在提交事务后,会等待至少一个从库确认已经接收到该事务的二进制日志后,才会向客户端返回操作成功的信息。
示例代码配置
-- 在主库和从库上都要安装半同步复制插件INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
-- 在主库上启用半同步复制SET GLOBAL rpl_semi_sync_master_enabled = 1;SET GLOBAL rpl_semi_sync_master_timeout = 10000; -- 设置超时时间
-- 在从库上启用半同步复制SET GLOBAL rpl_semi_sync_slave_enabled = 1;
-- 重启从库的复制线程STOP SLAVE IO_THREAD;START SLAVE IO_THREAD;区别
数据一致性
- 异步复制:主库和从库之间存在一定的数据延迟,因为主库不会等待从库接收和应用事务。在主库发生故障时,从库可能没有完全同步主库的最新数据。
- 半同步复制:在一定程度上保证了数据的一致性,因为主库会等待至少一个从库确认接收事务。但如果所有从库都出现问题,主库会在超时后自动切换回异步复制模式。
性能影响
- 异步复制:对主库的性能影响较小,因为主库不需要等待从库的响应,可以立即返回结果给客户端。
- 半同步复制:会对主库的性能产生一定的影响,因为主库需要等待从库的确认信息,增加了事务的提交时间。
优缺点
异步复制
- 优点:
- 性能高,主库可以快速响应客户端请求,不会因为从库的性能问题而受到影响。
- 配置简单,是 MySQL 默认的复制模式,不需要额外的插件和复杂的配置。
- 缺点:
- 数据一致性较差,在主库故障时可能会导致数据丢失。
半同步复制
- 优点:
- 提高了数据的一致性,减少了主库故障时数据丢失的风险。
- 缺点:
- 性能相对较低,因为主库需要等待从库的确认信息。
- 配置相对复杂,需要安装和启用半同步复制插件。
完全同步复制
除了半同步复制,还有一些第三方解决方案可以实现完全同步复制,即主库必须等待所有从库都成功应用事务后才会提交。但这种方式会对性能产生极大的影响,实际应用中较少使用。
binlog 的三种格式
| 格式 | 记录内容 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| **STATEMENT (SBR)** | 记录造成数据变更的SQL语句本身 | 日志量小,节省磁盘和网络I/O;易于查看和审计 | 可能引起主从不一致(如使用NOW(), UUID()等非确定性函数时) | 数据结构简单、SQL模式固定、更新量大但涉及行少的场景 |
| **ROW (RBR)** | 记录每一行数据如何被修改(如修改前/后的镜像) | 数据安全性和一致性最高,可可靠地复制任何变更 | 日志量可能非常大(特别是批量更新或表结构变更时) | 对数据一致性要求极高的场景(如金融业务),或使用了可能引起不一致的函数/存储过程时 |
| **MIXED (MBR)** | 智能混合使用STATEMENT和ROW模式 | 在安全性和性能间取得平衡;多数情况下日志量小,特定情况下自动转为ROW模式以保证安全 | 仍存在极小概率在混合模式下出现不一致 | 希望兼顾性能和数据安全性的通用业务场景,MySQL 5.7.7及以上版本默认采用此格式 |
#我 : . 列举 MySQL 主从复制中 binlog 的三种格式,并说明各自特点。
#Doubao :
在 MySQL 主从复制中,binlog(二进制日志)有三种格式,分别是 STATEMENT(语句级)、ROW(行级)和 MIXED(混合级),以下是它们各自的特点:
1. STATEMENT(语句级)
- 特点
- 日志记录方式:记录的是主库上执行的 SQL 语句。也就是说,主库在执行一条 SQL 语句后,会将该语句本身记录到 binlog 中,从库在复制时,会重新执行这些 SQL 语句来达到与主库数据一致的目的。
- 优点
- 日志量小:由于只记录 SQL 语句,相比于记录每行数据变化的 ROW 格式,日志量通常要小很多,这可以减少磁盘 I/O 和网络传输的压力,同时也能节省存储空间。
- 可读性高:SQL 语句本身是人类可读的,因此查看和分析 binlog 内容相对容易,便于进行故障排查和审计。
- 缺点
- 部分语句复制可能存在问题:一些依赖于主库当前环境的 SQL 语句,如
NOW()、UUID()等函数,在主从库上执行时可能会产生不同的结果,因为主从库的系统时间、随机数种子等可能不同。此外,一些存储过程、触发器等也可能因为主从库环境差异而导致复制不一致。 - 并发复制性能受限:在高并发场景下,由于从库需要重新执行 SQL 语句,可能会受到锁和并发控制的影响,导致复制性能下降。
- 部分语句复制可能存在问题:一些依赖于主库当前环境的 SQL 语句,如
2. ROW(行级)
- 特点
- 日志记录方式:记录的是每行数据的变化情况,即哪些行被插入、更新或删除,以及具体的变更内容。而不是像 STATEMENT 格式那样记录 SQL 语句。
- 优点
- 复制一致性高:由于记录的是实际的数据变更,不依赖于 SQL 语句的执行环境,因此可以保证主从库数据的高度一致性,避免了 STATEMENT 格式中因环境差异导致的复制问题。
- 并发复制性能好:从库可以并行地应用这些行级变更,而不需要像执行 SQL 语句那样考虑锁和并发控制,因此在高并发场景下,复制性能通常比 STATEMENT 格式要好。
- 缺点
- 日志量大:需要记录每行数据的变化,对于大规模的数据更新操作,日志量会非常大,这会增加磁盘 I/O 和网络传输的负担,同时也需要更多的存储空间。
- 可读性差:由于记录的是数据行的变化,而不是 SQL 语句,因此 binlog 的内容难以直接阅读和理解,不利于故障排查和审计。
3. MIXED(混合级)
- 特点
- 日志记录方式:结合了 STATEMENT 和 ROW 两种格式的优点。MySQL 会根据具体的 SQL 语句和执行情况,自动选择使用 STATEMENT 格式还是 ROW 格式来记录 binlog。
- 优点
- 灵活性高:对于大多数普通的 SQL 语句,会使用 STATEMENT 格式记录,以减少日志量;而对于那些可能导致复制不一致的 SQL 语句,如包含不确定函数的语句,则会使用 ROW 格式记录,以保证复制的一致性。
- 性能和一致性的平衡:在保证复制一致性的同时,尽可能地减少日志量,提高复制性能和效率。
- 缺点
- 难以预测日志格式:由于是自动选择日志格式,在某些情况下可能会让人难以预测具体使用的是哪种格式,增加了故障排查和管理的难度。
可以通过以下命令来查看和设置 binlog 的格式:
-- 查看当前 binlog 格式SHOW VARIABLES LIKE 'binlog_format';
-- 设置 binlog 格式为 STATEMENTSET GLOBAL binlog_format = 'STATEMENT';-- 设置 binlog 格式为 ROWSET GLOBAL binlog_format = 'ROW';-- 设置 binlog 格式为 MIXEDSET GLOBAL binlog_format = 'MIXED';需要注意的是,设置全局变量后,新的设置只会对新建立的会话生效,对于已经存在的会话,需要重新连接才能应用新的设置。
主库宕机如何保证业务
#我 : 主从复制中,若主库宕机,应如何进行故障切换以保证业务继续运行?
#Doubao : 在 MySQL 主从复制架构中,当主库宕机时,为了保证业务能够继续运行,需要进行故障切换。以下是详细的故障切换步骤和方法:
1. 确认主库宕机
首先要通过监控系统、日志或者手动检查等方式,确认主库确实已经无法正常工作。例如,可以尝试连接主库,查看是否能够正常响应查询请求;查看主库的系统日志和 MySQL 日志,确认是否有异常信息。
2. 选择新的主库
从多个从库中选择一个合适的从库作为新的主库,通常会考虑以下因素:
- 数据同步情况:选择与原主库数据最接近同步的从库,以减少数据丢失。可以通过查看从库的
SHOW SLAVE STATUS命令输出,比较Seconds_Behind_Master的值,选择该值最小的从库。 - 硬件资源:选择硬件配置较好、性能较高的从库,以确保新主库能够稳定运行。
3. 停止从库复制
在将选定的从库提升为新主库之前,需要先停止该从库的复制进程,避免后续出现数据冲突。在选定的从库上执行以下命令:
STOP SLAVE;4. 提升从库为新主库
将选定的从库设置为独立的主库,需要重置二进制日志和中继日志。在选定的从库上执行以下命令:
RESET MASTER;5. 配置其他从库指向新主库
将其他从库配置为连接到新的主库,继续进行复制。在每个从库上执行以下命令:
-- 停止当前的复制进程STOP SLAVE;-- 配置新主库的连接信息CHANGE MASTER TO MASTER_HOST='新主库的 IP 地址', MASTER_USER='复制用户', MASTER_PASSWORD='复制用户密码', MASTER_LOG_FILE='新主库当前的二进制日志文件名', MASTER_LOG_POS=新主库当前的二进制日志位置;-- 启动复制进程START SLAVE;可以通过 SHOW SLAVE STATUS 命令检查复制是否正常工作,确保 Slave_IO_Running 和 Slave_SQL_Running 都为 Yes。
6. 更新应用程序配置
将应用程序连接的数据库地址从原主库更新为新主库的地址,确保应用程序能够正常连接到新的主库。这可能需要修改应用程序的配置文件,并重新启动应用程序。
7. 恢复原主库
在故障切换完成后,可以对原主库进行故障排查和修复。修复完成后,将原主库配置为新主库的从库,继续进行复制。在原主库上执行以下命令:
-- 停止当前的复制进程STOP SLAVE;-- 重置二进制日志和中继日志RESET SLAVE ALL;-- 配置新主库的连接信息CHANGE MASTER TO MASTER_HOST='新主库的 IP 地址', MASTER_USER='复制用户', MASTER_PASSWORD='复制用户密码', MASTER_LOG_FILE='新主库当前的二进制日志文件名', MASTER_LOG_POS=新主库当前的二进制日志位置;-- 启动复制进程START SLAVE;自动化故障切换
为了提高故障切换的效率和准确性,可以使用一些自动化工具来实现故障切换,例如 MHA(Master High Availability)、PXC(Percona XtraDB Cluster)等。这些工具可以自动检测主库的故障,并在主库宕机时自动进行故障切换,减少人工干预的时间和错误。
[root@master /]# cat /usr/local/mysql/my.cnf[mysqld]basedir=/usr/local/mysql # MySQL安装目录datadir=/usr/local/mysql/data # 数据文件存储目录socket=/tmp/mysql.sock # 本地连接使用的socket文件port=3306 # 服务监听端口log_error=/usr/local/mysql/data/master.err # 指定错误日志文件的路径。错误日志记录了MySQL启动、运行和停止过程中的错误信息。log_bin=/usr/local/mysql/data/binlog # 指定二进制日志(binlog)文件的基本路径和名称。二进制日志记录了所有更改数据的SQL语句(或数据变更),用于主从复制和数据恢复。server_id=10 # 设置服务器的唯一标识符,在主从复制拓扑中,每个服务器必须有一个唯一的server_id。character_set_server=utf8mb4 # 设置服务器默认的字符集为utf8mb4,它支持更广泛的Unicode字符(如emoji表情)gtid_mode=on # 启用全局事务标识符(GTID)模式。GTID为每个事务分配一个全局唯一的标识符,简化了主从复制的管理log_slave_updates=1 # 允许从库将其从主库接收到的更新记录到自己的二进制日志中。这通常用于链式复制(例如,A->B->C)或备份从库enforce_gtid_consistency # 强制GTID一致性,确保只有能够安全记录GTID的事务才会被执行。这有助于保证复制的可靠性。# 复制核心参数log_bin=/usr/local/mysql/data/binlogrelay_log=/usr/local/mysql/data/relaylogserver_id=20#字符集character_set_server=utf8mb4# 可靠性参数relay_log_recovery = ONmaster_info_repository = TABLErelay_log_info_repository = TABLE#设置从库只读read_only=1#我 : 检查下面作业是否有问题
六、作业
选择题
- 在 MySQL 主从复制中,主服务器记录数据变更的二进制日志文件是( A )。 A. binlog B. relay-bin C. binlog.index D. relay-bin.log
- 若要开启 MySQL 主从复制,主从服务器的以下哪个参数必须不同( A )。 A. server-id B. log-bin C. sync-binlog D. relay-log
- MySQL 主从复制中,从服务器将接收到的主服务器 binlog 日志写入的文件是( B )。 A. binlog B. relay log C. binlog.index D. relay-bin.log
- 主从复制中,主库执行写操作后,以下哪个线程负责把 binlog 的内容发送到从库( A )。 A. binlog dump thread B. I/O 线程 C. SQL 线程 D. log dump 线程
- MySQL 主从复制采用异步复制时,可能出现的问题是( A )。 A. 数据丢失 B. 性能严重下降 C. 无法实现复制 D. 主从服务器无法连接
简答题
-
简述 MySQL 主从复制的基本原理。 答:
- 主库将数据变更(DDL和DML)记录到二进制日志(binlog)中。
- 从库的I/O线程向主库的binlog dump线程请求binlog。
- 主库的binlog dump线程将binlog事件发送给从库的I/O线程。
- 从库的I/O线程将接收到的事件写入中继日志(relay log)。
- 从库的SQL线程读取并解析relay log中的事件,在从库上执行这些事件,从而使从库与主库的数据保持同步。
-
列举 MySQL 主从复制中 binlog 的三种格式,并说明各自特点。 答: binlog的三种格式,
STATEMENT(语句级)、ROW(行级)和MIXED(混合级)STATEMENT(语句级):日志量小、可读性高ROW(行级):复制一致性高、并发复制性能好MIXED(混合级):灵活性高、性能和一致性的平衡 -
主从复制中,若主库宕机,应如何进行故障切换以保证业务继续运行? 答: 1、确认主库宕机之后,第一时间选择一个从库作为新主库以承接服务 2、停止新主库上的从库配置改为主库,同事配置其它从库指向新主库 3、更新业务服务的数据库配置指向新主库
操作题
- 请详细描述搭建一主一从 MySQL 主从复制环境的步骤,包括主从服务器的配置、用户创建、同步启动等。
# 清理mariadb[root@master ~]# rpm -qa | grep mariadb | xargs rpm -e --nodeps# 基本环境安装[root@master ~]# yum install -y libaio-devel numactl wget# 下载安装官方源[root@master ~]# wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm[root@master ~]# rpm -ivh mysql80-community-release-el7-3.noarch.rpm# 下载并导入 MySQL 官方 GPG 密钥[root@master ~]# rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023[root@master ~]# yum repolist enabled | grep mysqlmysql-connectors-community/x86_64 MySQL Connectors Community 293mysql-tools-community/x86_64 MySQL Tools Community 118mysql80-community/x86_64 MySQL 8.0 Community Server 598[root@master ~]#
# 主从安装mysql服务[root@master ~]# yum install -y mysql-community-serverLoaded plugins: fastestmirrorLoading mirror speeds from cached hostfileResolving Dependencies--> Running transaction check---> Package mysql-community-server.x86_64 0:8.0.44-1.el7 will be installed--> Processing Dependency: mysql-community-common(x86-64) = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-icu-data-files = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-client(x86-64) >= 8.0.11 for package: mysql-community-server-8.0.44-1.el7.x86_64
# 配置主库,指定server_id和开启binlog日记[root@master ~]# grep -vE "#" /etc/my.cnf[mysqld]datadir=/var/lib/mysqlsocket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.logpid-file=/var/run/mysqld/mysqld.pid
server_id=10log_bin=/var/lib/mysql/binlog
#启动和添加开机启动mysql服务[root@master /]# systemctl enable mysqld[root@master /]# systemctl status mysqld
[root@master /]# mysql -uroot -p........# 第一次登陆需先修改默认密码mysql> alter user 'root'@'localhost' IDENTIFIED BY 'mysql123!';Query OK, 0 rows affected (0.01 sec)
# 创建用户同步的repluser账号密码replusermysql> create user repluser@"%" identified WITH mysql_native_password by "repluser";Query OK, 0 rows affected (0.09 sec)# 给repluser用户赋权mysql> grant replication slave on *.* to repluser@"%";Query OK, 0 rows affected (0.05 sec)# 查询binlog名称和偏移量mysql> show master status;+---------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+---------------+----------+--------------+------------------+-------------------+| binlog.000002 | 1307 | | | |+---------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
# 从库安装mysql服务# 清理mariadb[root@slave1 ~]# rpm -qa | grep mariadb | xargs rpm -e --nodeps# 基本环境安装[root@slave1 ~]# yum install -y libaio-devel numactl wget# 下载安装官方源[root@slave1 ~]# wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm[root@slave1 ~]# rpm -ivh mysql80-community-release-el7-3.noarch.rpm# 下载并导入 MySQL 官方 GPG 密钥[root@slave1 ~]# rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023[root@slave1 ~]# yum repolist enabled | grep mysqlmysql-connectors-community/x86_64 MySQL Connectors Community 293mysql-tools-community/x86_64 MySQL Tools Community 118mysql80-community/x86_64 MySQL 8.0 Community Server 598[root@slave1 ~]#
# 主从安装mysql服务[root@slave1 ~]# yum install -y mysql-community-serverLoaded plugins: fastestmirrorLoading mirror speeds from cached hostfileResolving Dependencies--> Running transaction check---> Package mysql-community-server.x86_64 0:8.0.44-1.el7 will be installed--> Processing Dependency: mysql-community-common(x86-64) = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-icu-data-files = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-client(x86-64) >= 8.0.11 for package: mysql-community-server-8.0.44-1.el7.x86_64
# 配置从库,指定server_id和开启binlog日记[root@slave1 ~]# vim /etc/my.cnf[root@slave1 ~]# grep -vE "#" /etc/my.cnf
[mysqld]
datadir=/var/lib/mysqlsocket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.logpid-file=/var/run/mysqld/mysqld.pid
server_id=20log_bin=/var/lib/mysql/binlogrelay_log=/var/lib/mysql/relaylog
[root@slave1 ~]# systemctl enable mysqld[root@slave1 ~]# systemctl start mysqld
# 从库配置# 修改默认密码mysql> alter user 'root'@'localhost' IDENTIFIED BY 'Mysql123!';Query OK, 0 rows affected (0.01 sec)
# 配置 MySQL 主从复制mysql> change master to master_host="192.168.99.10" , master_user="repluser" , master_password="repluser" ,master_log_file="binlog.000002" , master_log_pos=1307;Query OK, 0 rows affected, 8 warnings (0.06 sec)
# 启动slave进程mysql> start slave ;Query OK, 0 rows affected, 1 warning (0.32 sec)
# 同步查看状态信息mysql> show slave status \G*************************** 1. row *************************** Slave_IO_State: Waiting for source to send event Master_Host: 192.168.99.10 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: binlog.000002 Read_Master_Log_Pos: 1307 Relay_Log_File: relaylog.000002 Relay_Log_Pos: 323 Relay_Master_Log_File: binlog.000002 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB:
# 测试
# 在主服务器创建text数据库mysql> create database text;Query OK, 1 row affected (0.06 sec)
# 从库查看是否同步mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || text |+--------------------+5 rows in set (0.06 sec)- 假设已有一主多从的 MySQL 主从复制环境,现在需要新增一个从服务器,写出具体操作步骤。
# 查看主库当前binlog和偏移量mysql> show master status;+---------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+---------------+----------+--------------+------------------+-------------------+| binlog.000002 | 1492 | | | |+---------------+----------+--------------+------------------+-------------------+1 row in set (0.04 sec)
# 从库安装mysql服务# 清理mariadb[root@slave1 ~]# rpm -qa | grep mariadb | xargs rpm -e --nodeps# 基本环境安装[root@slave1 ~]# yum install -y libaio-devel numactl wget# 下载安装官方源[root@slave1 ~]# wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm[root@slave1 ~]# rpm -ivh mysql80-community-release-el7-3.noarch.rpm# 下载并导入 MySQL 官方 GPG 密钥[root@slave1 ~]# rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023[root@slave1 ~]# yum repolist enabled | grep mysqlmysql-connectors-community/x86_64 MySQL Connectors Community 293mysql-tools-community/x86_64 MySQL Tools Community 118mysql80-community/x86_64 MySQL 8.0 Community Server 598[root@slave1 ~]#
# 主从安装mysql服务[root@slave1 ~]# yum install -y mysql-community-serverLoaded plugins: fastestmirrorLoading mirror speeds from cached hostfileResolving Dependencies--> Running transaction check---> Package mysql-community-server.x86_64 0:8.0.44-1.el7 will be installed--> Processing Dependency: mysql-community-common(x86-64) = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-icu-data-files = 8.0.44-1.el7 for package: mysql-community-server-8.0.44-1.el7.x86_64--> Processing Dependency: mysql-community-client(x86-64) >= 8.0.11 for package: mysql-community-server-8.0.44-1.el7.x86_64
# 配置从库,指定server_id和开启binlog日记[root@slave1 ~]# vim /etc/my.cnf[root@slave1 ~]# grep -vE "#" /etc/my.cnf
[mysqld]
datadir=/var/lib/mysqlsocket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.logpid-file=/var/run/mysqld/mysqld.pid
server_id=30log_bin=/var/lib/mysql/binlogrelay_log=/var/lib/mysql/relaylog
[root@slave1 ~]# systemctl enable mysqld[root@slave1 ~]# systemctl start mysqld
# 从库配置# 修改默认密码mysql> alter user 'root'@'localhost' IDENTIFIED BY 'Mysql123!';Query OK, 0 rows affected (0.01 sec)
# 配置 MySQL 主从复制mysql> change master to master_host="192.168.99.10" , master_user="repluser" , master_password="repluser" ,master_log_file="binlog.000002" , master_log_pos=1492;Query OK, 0 rows affected, 8 warnings (0.04 sec)
# 启动slave进程mysql> start slave;Query OK, 0 rows affected, 1 warning (0.63 sec)
# 同步查看状态信息mysql> show slave status \G*************************** 1. row *************************** Slave_IO_State: Waiting for source to send event Master_Host: 192.168.99.10 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: binlog.000002 Read_Master_Log_Pos: 1492 Relay_Log_File: relaylog.000002 Relay_Log_Pos: 323 Relay_Master_Log_File: binlog.000002 Slave_IO_Running: Yes Slave_SQL_Running: Yes
# 测试
# 在主服务器创建text数据库mysql> create database text2;Query OK, 1 row affected (0.09 sec)
# 从库1 查看是否同步mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || text || text2 |+--------------------+6 rows in set (0.12 sec)
# 新增从库2 查看是否同步mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || text2 |+--------------------+5 rows in set (0.02 sec)#Doubao : 以下是对这份作业的详细检查分析:
选择题
所有选择题答案均正确,对 MySQL 主从复制的基本概念掌握较好。
- 第 1 题:主服务器记录数据变更的二进制日志文件是
binlog,选项 A 正确。 - 第 2 题:在 MySQL 主从复制中,主从服务器的
server-id必须不同,用于唯一标识每个服务器,选项 A 正确。 - 第 3 题:从服务器将接收到的主服务器
binlog日志写入relay log,选项 B 正确。 - 第 4 题:主库执行写操作后,
binlog dump thread负责把binlog的内容发送到从库,选项 A 正确。 - 第 5 题:MySQL 主从复制采用异步复制时,主库不等待从库确认,可能出现数据丢失的问题,选项 A 正确。
简答题
1. 简述 MySQL 主从复制的基本原理
答案准确完整,清晰地阐述了 MySQL 主从复制的基本流程,包括主库记录 binlog、从库请求和接收 binlog、写入中继日志以及执行事件等步骤。
2. 列举 MySQL 主从复制中 binlog 的三种格式,并说明各自特点
答案基本正确,但不够详细。对于每种格式的优缺点可以进一步展开说明,例如:
STATEMENT(语句级):日志量小、可读性高,但部分依赖主库环境的 SQL 语句(如含NOW()、UUID()等函数)可能导致主从复制不一致,在高并发场景下并发复制性能受限。ROW(行级):复制一致性高、并发复制性能好,但日志量大,可读性差,对于大规模数据更新操作会增加磁盘 I/O 和网络传输负担。MIXED(混合级):灵活性高、性能和一致性的平衡,会根据具体 SQL 语句自动选择STATEMENT或ROW格式,但难以预测具体使用的日志格式,增加了故障排查和管理难度。
3. 主从复制中,若主库宕机,应如何进行故障切换以保证业务继续运行
答案步骤不够详细,可能会导致实际操作时出现问题。可以补充以下内容:
- 确认主库宕机:通过监控系统、日志或者手动检查等方式,确认主库确实无法正常工作。
- 选择新的主库:考虑数据同步情况(查看
Seconds_Behind_Master)和硬件资源,选择合适的从库作为新主库。 - 停止从库复制:在选定的从库上执行
STOP SLAVE命令。 - 提升从库为新主库:执行
RESET MASTER命令。 - 配置其他从库指向新主库:在每个从库上执行
CHANGE MASTER TO命令,更新主库连接信息,然后执行START SLAVE命令。 - 更新应用程序配置:将应用程序连接的数据库地址从原主库更新为新主库的地址。
- 恢复原主库:对原主库进行故障排查和修复,修复完成后将其配置为新主库的从库。
操作题
1. 请详细描述搭建一主一从 MySQL 主从复制环境的步骤,包括主从服务器的配置、用户创建、同步启动等
整体步骤基本正确,但存在一些小问题:
- 数据库名拼写错误:在测试部分创建数据库时,写成了
text,推测可能是想写test。 - 缺少权限刷新:在主库创建用户并赋权后,应执行
FLUSH PRIVILEGES命令使权限生效。 - 日志记录:在安装和配置过程中,应检查命令执行结果,确保没有报错,并且可以记录关键步骤的日志,方便后续排查问题。
2. 假设已有一主多从的 MySQL 主从复制环境,现在需要新增一个从服务器,写出具体操作步骤
整体步骤基本正确,同样存在以下问题:
- 数据库名拼写错误:同第一题,测试部分创建数据库写成
text2,可能是test2。 - 缺少权限刷新:在主库创建用户并赋权后,应执行
FLUSH PRIVILEGES命令使权限生效。 - 日志记录:在安装和配置过程中,应检查命令执行结果,确保没有报错,并且可以记录关键步骤的日志,方便后续排查问题。
综上所述,作业对 MySQL 主从复制的基本概念和操作有较好的理解,但在一些细节和完整性方面还有提升空间。