复制是解决系统高可用的常见手段。其思路就是:不要把鸡蛋都放在一个篮子里。
复制解决的基本问题是让一台服务器的数据与其他服务器保持同步。一台主库的数据可以同步到多台备库上,备库本身也可以被配置成另外一台服务器的主库。主库和备库之 间可以有多种不同的组合方式。
MySQL 支持两种复制方式:基于行的复制和基于语句的复制。这两种方式都是通过在主库上记录 bin log、在备库重放日志的方式来实现异步的数据复制。这意味着:复制过程存在时延,这段时间内,主从数据可能不一致。
在 Mysql 中,复制分为三个步骤,分别由三个线程完成:
假设需要配置一对 Mysql 主备节点,环境如下:
(1)修改配置并重启
执行 vi /etc/my.cnf ,添加如下配置:
[mysqld]
server-id=1
log_bin=/var/lib/mysql/binlog
修改后,重启 mysql 使配置生效:
systemctl restart mysql
(2)创建用于同步的用户
进入 mysql 命令控制台:
$ mysql -u root -p
Password:
执行以下 SQL:
-- a. 创建 slave 用户
CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '密码';
-- 为 slave 赋予 REPLICATION SLAVE 权限
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%';
-- b. 或者,创建 slave 用户,并指定该用户能在任意主机上登录
-- 如果有多个备库,又想让所有备库都使用统一的用户名、密码认证,可以考虑这种方式
CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '密码';
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%';
-- 刷新授权表信息
FLUSH PRIVILEGES;
注意:在 Mysql 8 中,默认密码验证不再是 password。所以在创建用户时,create user ‘username’@‘%’ identified by ‘password’; 客户端是无法连接服务的。所以,需要加上 IDENTIFIED WITH mysql_native_password BY ‘password’
补充用户管理 SQL:
-- 查看所有用户
SELECT DISTINCT CONCAT('User: ''', user, '''@''', host, ''';') AS query
FROM mysql.user;
-- 查看用户权限
SHOW GRANTS FOR 'root'@'%';
-- 创建用户
-- a. 创建 slave 用户,并指定该用户只能在主机 192.168.8.11 上登录
CREATE USER 'slave'@'192.168.8.11' IDENTIFIED WITH mysql_native_password BY '密码';
-- 为 slave 赋予 REPLICATION SLAVE 权限
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'192.168.8.11';
-- 删除用户
DROP USER 'slave'@'192.168.8.11';
(3)加读锁
为了主库与从库的数据保持一致,我们先为 mysql 加入读锁,使其变为只读。
mysql> FLUSH TABLES WITH READ LOCK;
(4)查看主库状态
mysql> show master status;
+------------------+----------+--------------+---------------------------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+---------------------------------------------+-------------------+
| mysql-bin.000001 | 4202 | | mysql,information_schema,performance_schema | |
+------------------+----------+--------------+---------------------------------------------+-------------------+
1 row in set (0.00 sec)
注意:需要记录下 File 和 Position,后面会用到。
(5)导出 sql
mysqldump -u root -p --all-databases --master-data > dbdump.sql
(6)解除读锁
mysql> UNLOCK TABLES;
(7)将 sql 远程传送到备库上
scp dbdump.sql root@192.168.8.11:/home
(1)修改配置并重启
执行 vi /etc/my.cnf ,添加如下配置:
[mysqld]
server-id=2
log_bin=/var/lib/mysql/binlog
修改后,重启 mysql 使配置生效:
systemctl restart mysql
(2)导入 sql
mysql -u root -p < /home/dbdump.sql
(3)在备库上建立与主库的连接
进入 mysql 命令控制台:
$ mysql -u root -p
Password:
执行以下 SQL:
-- 停止备库服务
STOP SLAVE;
-- 注意:MASTER_USER 和
CHANGE MASTER TO
MASTER_HOST='192.168.8.10',
MASTER_USER='slave',
MASTER_PASSWORD='密码',
MASTER_LOG_FILE='binlog.000001',
MASTER_LOG_POS=4202;
(4)启动 slave 进程
mysql> start slave;
(5)查看主从同步状态
mysql> show slave status\G;
说明:如果以下两项参数均为 YES,说明配置正确。
mysql> set global read_only=1;
mysql> set global super_read_only=1;
mysql> show global variables like "%read_only%";
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_read_only | OFF |
| read_only | ON |
| super_read_only | ON |
| transaction_read_only | OFF |
+-----------------------+-------+
注:设置 slave 服务器为只读,并不影响主从同步。
主服务器用来处理写操作以及实时性要求比较高的读操作,而从服务器用来处理读操作。
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
MySQL 读写分离能提高性能的原因在于:
主从服务器负责各自的读和写,极大程度缓解了锁的争用;
从服务器可以配置 MyISAM 引擎,提升查询性能以及节约系统开销;
增加冗余,提高可用性。