MYSQL主从
随着访问量的不断增加,单台MySQL数据库服务器压力不断增加,需要对MYSQL进行优化和架构改造,MYQSL优化如果不能明显改善压力情况,可以使用高可用、主从复制、读写分离来、拆分库、拆分表来进行优化。
MYSQL主从复制集群在中小企业、大型企业中被广泛使用,MYSQL主从复制的目的是实现数据库冗余备份,将Master数据库数据定时同步至Slave库中,一旦Master数据库宕机,可以将WEB应用数据库配置快速切换至Slave数据库,确保WEB应用较高的可用性。
MySQL主从主要作用
实现备份
实现故障转移
实现读写分离
MySQL主从常见架构
主从工作原理
主从前提是作为主服务器角色的数据库服务器必须开启二进制日志
主服务器上面的任何修改都会通过自己的 I/O tread(I/O 线程)保存在二进制日志 Binary log 里面。从服务器上面也启动一个 I/O thread,通过配置好的用户名和密码, 连接到主服务器上面请求读取二进制日志,然后把读取到的二进制日志写到本地的一个Realy log(中继日志)里面。从服务器上面同时开启一个 SQL thread 定时检查 Realy log(这个文件也是二进制的),如果发现有更新立即把更新的内容在本机的数据库上面执行一遍。
每个从服务器都会收到主服务器二进制日志的全部内容的副本。从服务器设备负责决定应该执行二进制日志中的哪些语句。除非另行指定,否则主从二进制日志中的所有事件都在从站上执行。如果需要,您可以将从服务器配置为仅处理一些特定数据库或表的事件。
MySQL主从部署,5.5版本源码安装
master: 192.168.179.99
slave: 192.168.179.100
配置master端(开启二进制文件,server-id唯一,给从库授权)
(1)[[email protected] mysql-5.5.60]# vim /usr/local/mysql55/my.cnf --在配置文件里面开启二进制文件log-bin=jfedu-bin,源码安装默认开启了,如果是yum安装将该行添加进配置文件[mysqld]下面
# Replication Master Server (default)
# binary logging is required for replication
(2)[[email protected] mysql-5.5.60]# vim /usr/local/mysql55/my.cnf --对于单台服务器来说server id并不重要,如果是集群主从那么server id必须要不同,那么就需要修改另外几台MySQL的server id了,修改master的server id=1,源码安装默认有,yum需要添加进去
# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
server-id=1
上面两部总结就是配置下面两行,在[mysqld]下面
log-bin=jfedu-bin
server-id=1
[[email protected] mysql-5.5.60]# /etc/init.d/mysqld restart --修改完配置文件重启数据库
mysql> show variables like "%log_bin"; --进入mysql服务器,查看二进制功能状态log_bin,可以看到已经开启ON,同时sql_log_bin也必须为on
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
| sql_log_bin | ON |
+---------------+-------+
(3)给从库授权,创建用于数据同步的账户
mysql> grant replication slave on *.* to "jfedu"@"192.168.179.100" identified by "123456";
Query OK, 0 rows affected (0.00 sec)
*.*所有数据库所有表格
授权jfedu用户以123456密码登入到192.168.179.100从服务器,来复制主服务器数据库所有表(也可以指定复制指定的数据库和表格)
mysql> flush privileges; --刷新权限
Query OK, 0 rows affected (0.00 sec)
(4)查看master状态,记录二进制文件名 jfedu-bin.000001 ,在从库指定从position 339哪个点开始
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| jfedu-bin.000001 | 339 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
[[email protected] ~]# ll /data/mysql/ | grep jfedu* --可以看到主库的数据目录下的这两个文件是用来同步的
-rw-rw---- 1 mysql mysql 339 Mar 20 11:03 jfedu-bin.000001
-rw-rw---- 1 mysql mysql 19 Mar 20 10:47 jfedu-bin.index
[[email protected] ~]# cat /data/mysql/jfedu-bin.index
./jfedu-bin.000001
配置slave
(1)这里不做互为主从就不需要和主库一样开启二进制功能,只需要修改id就行
[[email protected] mysql-5.5.60]# vim /usr/local/mysql55/my.cnf
server-id=2
[[email protected] mysql-5.5.60]# /etc/init.d/mysqld restart --重启服务,指定主库是谁
Shutting down MySQL. SUCCESS!
Starting MySQL.. SUCCESS!
(2)打开mysql会话,执行同步SQL语句(需要主服务器主机名,登陆凭据,二进制文件的名称和位置)
change master to master_host="192.168.179.99",master_user="jfedu", master_password="123456", master_log_file="jfedubin.000001", master_log_pos=339;
来指定要同步的主库是谁,指定了主库之后,主库肯定会向从库要账号密码的,这个账号和密码就是主库授权的用户和密码。之后告诉从库去主库里面拿哪个log文件。同时告诉他从文件的哪个点开始同步,这个点可以选择。
mysql> change master to master_host="192.168.179.99",master_user="jfedu", master_password="123456", master_log_file="jfedu-bin.000001", master_log_pos=339;
Query OK, 0 rows affected (0.01 sec)
(3)启动slave同步进程,这样从库就会去连接主库
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G --标红的两行必须为yes才算配置成功
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.179.99
Master_User: jfedu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: jfedu-bin.000001
Read_Master_Log_Pos: 339
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 253
Relay_Master_Log_File: jfedu-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
配置失败三则案例
(1)Slave_IO_Running: Connecting(从库指定的用户名与密码错误(与主库授权的用户名和密码不一致)或者防火墙没有关闭或者主库宕机了)
下面演示密码写错
mysql> slave stop;
mysql> change master to master_host="192.168.179.99",master_user="jfedu", master_password="23456", master_log_file="jfedu-bin.000001", master_log_pos=339;
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 192.168.179.99
Master_User: jfedu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: jfedu-bin.000001
Read_Master_Log_Pos: 339
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: jfedu-bin.000001
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Last_IO_Error: error connecting to master '[email protected]:3306' - retry-time: 60 ret
(2)Slave_IO_Running: No(正确登入了之后,会向主库请求jfedu-bin.000001这个文件,但是这个文件在主库里面找不到,主库就返回信息Slave_IO_Running: No)
mysql> slave stop;
Query OK, 0 rows affected (0.00 sec)
mysql> change master to master_host="192.168.179.99",master_user="jfedu", master_password="123456", master_log_file="jfedu-bin.000002", master_log_pos=339;
Query OK, 0 rows affected (0.01 sec)
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.179.99
Master_User: jfedu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: jfedu-bin.000002
Read_Master_Log_Pos: 339
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: jfedu-bin.000002
Slave_IO_Running: No
Slave_SQL_Running: Yes
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
(3)Slave_SQL_Running: No(pos点问题)
mysql> create database mytest charset=utf8; --主库创建数据库
Query OK, 1 row affected (0.01 sec)
mysql> show databases; --从库查看,可以看到同步过来了
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| mytest |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.01 sec)
mysql> slave stop;
Query OK, 0 rows affected (0.01 sec)
mysql> change master to master_host="192.168.179.99",master_user="jfedu", master_password="123456", master_log_file="jfedu-bin.000001", master_log_pos=339;
Query OK, 0 rows affected (0.01 sec)
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G --因为从库已经创建了mytest的数据库,所以同步不过去,需要修改pos点来跳过之前在主库执行的sql语句然后再同步
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.179.99
Master_User: jfedu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: jfedu-bin.000001
Read_Master_Log_Pos: 439
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 253
Relay_Master_Log_File: jfedu-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: No
mysql> show master status; --来到主库再查看pos点为439,更正从库pos点在同步可以解决
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| jfedu-bin.000001 | 439 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql> slave stop;
Query OK, 0 rows affected (0.01 sec)
mysql> change master to master_host="192.168.179.99",master_user="jfedu", master_password="123456", master_log_file="jfedu-bin.000001", master_log_pos=439;
Query OK, 0 rows affected (0.01 sec)
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G; --可以看到修改pos点问题已经解决了
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.179.99
Master_User: jfedu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: jfedu-bin.000001
Read_Master_Log_Pos: 439
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 253
Relay_Master_Log_File: jfedu-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
在企业当中出问题最多的就是 Slave_SQL_Running: NO,也就是数据在同步的适合会出现很多问题,比如网络问题,数据量的问题,并发用户的问题,这些可能导致数据不一致。