实验环境:
rhel6.5 server3(从):172.25.70.3
rpm包:mysql5.7
为server2和server3都安装mysql5.7的rpm包,并进行初始化设置,这里使用server2做演示
[root@server2 mysql5.7]# yum install mysql-community-client-5.7.17-1.el6.x86_64.rpm mysql-community-common-5.7.17-1.el6.x86_64.rpm mysql-community-libs-5.7.17-1.el6.x86_64.rpm mysql-community-libs-compat-5.7.17-1.el6.x86_64.rpm mysql-community-server-5.7.17-1.el6.x86_64.rpm -y
[root@server2 mysql5.7]# /etc/init.d/mysqld start #开启服务
#初始化,这里两个主机用两种不同的方法分别演示:
[root@server2 ~]# grep password /var/log/mysqld.log #首先查看系统默认的mysql密码是多少
[root@server2 ~]# mysql_secure_installatio #自己设置密码,密码有安全性要求,必须大小写字母、特殊符号、数字都有
[root@server2 ~]# mysql -p ##修改之后,登录成功
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.7.17 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
****
第二种方法:先用默认密码登录mysql,然后用SQL语句更改密码
[root@server3 mysql5.7]# grep password /var/log/mysqld.log
[root@server3 mysql5.7]# mysql -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.17
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> ALTER USER root@localhost identified by 'Lcl@0514'; ##更改密码
Query OK, 0 rows affected (0.17 sec)
mysql> flush privileges; ##手动刷新
Query OK, 0 rows affected (0.10 sec)
随着访问量的不断增加,单台MySQL数据库服务器压力不断增加,需要对MySQL进行优化和架构改造,如果MySQL优化不能明显改善压力,可以使用高可用、主从复制、读写分离、拆分库、拆分表等方法来进行优化。
MySQL主从复制的目的是实现数据库冗余备份,将master数据库数据定时间同步至slave库中,一旦master数据库宕机,可以将web应用数据库配置快速切换至slave数据库,确保Web应用具有较高的高可用率
MySQL主从复制集群至少需要2台数据库服务器,其中一台为master库,另外一台为slave库,MySQL主从数据同步是一个异步复制的过程,要实现复制首先需要在master开启bin-log日志功能,bin-log日志用于记录在master库中执行的增、删、修改、更新等操作的SQL语句,整个过程需要开启3个进程,分别是master开启I/O线程,slave开启I/O线程和SQL线程,具体主从同步原理详解如下:
在/etc/my.cnf配置文件[mysqld]段中加入如下代码,然后重启MySQL服务器
server-id=1
log-bin=mysql-bin
在master数据库服务器命令行中创建tongbu用户及密码并且设置权限,并查看bin-log文件及position点
grant replication slave on *.* to 'tongbu'@'%' identified by 'Lcl@0514';
show master status;
在/etc/my.cnf配置文件[mysqld]段中加入代码server-id=2
,然后重启MySQL服务器即可。master与slave之间的server-id不能相同,slave端不需要开启bin-log功能
slave指定master IP、用户名、密码、bin-log文件名及position,代码如下
mysql> CHANGE MASTER TO master_host = '172.25.70.2',master_user='tongbu',master_password='Lcl@0514',master_log_file='mysql-bin.000001',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (1.36 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.26 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event ##slave连接到master的状态
Master_Host: 172.25.70.2 ##master主机
Master_User: tongbu ##负责主从复制的用户
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001 ##I/O线程当前正在读取的主服务器二进制日志文件的名称
Read_Master_Log_Pos: 154 ##在当前的主服务器二进制日志中,I/O线程已读取的位置
Relay_Log_File: server3-relay-bin.000002 ##salve的SQL线程当前正在读取和执行的中继日志文件名称
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000001 ##由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称
Slave_IO_Running: Yes ##I/O线程是否启动成功并连接到master上
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: ##slave的SQL线程读取日志参数的错误量和错误消息
Skip_Counter: 0
Exec_Master_Log_Pos: 154 ##来自主服务器的二进制日志的由SQL线程执行的上一个时间的位置
Relay_Log_Space: 529 ##所有的原有中继日志结合起来的总大小
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: 0 ##表示主从之间的时间差,是数字的时候表示相差多少秒,null表示未知数,一般主从出现问题就会出现null
Master_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: 1
Master_UUID: 5c570315-9953-11e8-a680-525400757e9f
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave 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:
1 row in set (0.01 sec)
在master端创建mysql_db_test数据库和t1表,命令如下
mysql> create database mysql_db_test charset=utf8;
Query OK, 1 row affected (0.25 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| mysql_db_test |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.32 sec)
mysql> use mysql_db_test;
Database changed
mysql> create table t1 (id varchar(20),name varchar(20));
Query OK, 0 rows affected (1.53 sec)
mysql> show tables;
+-------------------------+
| Tables_in_mysql_db_test |
+-------------------------+
| t1 |
+-------------------------+
1 row in set (0.00 sec)
在slave服务器查看那是否有mysql_db_test服务器和t1表,存在则表示slave复制master成功
在master服务器的t1表上插入两条数据,并在slave查看是否已经同步,master执行命令为
insert into t1 values ("1","alice");
insert into t1 values ("2","bob");
select * from t1;
MySQL主从同步集群在生产环境使用时,如果主从服务器之间网络通信条件差或者数据库数据量非常大,容易导致MySQL主从同步延迟
MySQL主从同步延迟之后,一旦主库宕机,会导致部分数据没有即使同步至主库,重新启动主库,会导致从库与主库同步错误,快速恢复主从同步关系有两种方法:
(1) 忽略错误后,继续同步
此方法适用于主从库数据内容相差不大的情况。
master端执行命令flush tables with read lock;
,将数据库设置为全局读锁,不允许写入新数据
slave端停止slave I/O线程和SQL线程,同时将同步错误的SQL跳过一次,跳过错误会导致数据不一致,启动start slave;
,同步状态恢复,命令为:
stop slave;
set global sql_slave_skip_counter = 1;
start slave;
(2) 重新做主从同步,使数据完全同步
此方法适用于主从库数据内容相差很大的情况。
master执行flush tables with read lock;
,将数据库设置全局读锁,不允许写入新数据。
master基于mysqldump、xtrabackup工具对数据库进行完整备份,也可用shell脚本或python脚本实现定时备份,备份成功后,将完整的数据导入到从库,重新配置主从关系,当slave的I/O线程、SQL线程均为Yes后,将master端的读锁解开即可,命令为unlock tables;
GTID即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。
可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式。借助GTID,在发生主备切换的情况下,MySQL的其它Slave可以自动在新主上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。
原理:
从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set) < SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)< IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了。
在master和server的my.cnf中添加:并重启服务
gtid_mode = ON
enforce-gtid-consistency=true
然后在slave上重新指定master,重启服务
mysql> stop slave;
Query OK, 0 rows affected (0.05 sec)
mysql> change master to master_host='172.25.70.2',master_user='tongbu',master_password='Lcl@0514',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.21 sec)
mysql> show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
在master中插入一条数据,查看slave
mysql> insert into t1 values('3','eve');
Query OK, 1 row affected (0.09 sec)
slave:
mysql> select * from mysql_db_test.t1;
+------+-------+
| id | name |
+------+-------+
| 1 | alice |
| 2 | bob |
| 3 | eve |
+------+-------+
3 rows in set (0.00 sec)
mysql> show slave status\G;
Retrieved_Gtid_Set: 5c570315-9953-11e8-a680-525400757e9f:1
Executed_Gtid_Set: 5c570315-9953-11e8-a680-525400757e9f:1
Auto_Position: 1
mysql-proxy是mysql官方提供的mysql中间件服务,上游可接入若干个mysql-client,后端可连接若干个mysql-server。
它使用mysql协议,任何使用mysql-client的上游无需修改任何代码,即可迁移至mysql-proxy上。
根本上,mysql-proxy是一个官方提供的框架,具备良好的扩展性,可以用来完成:
这里只用来做读写分离
tar zxf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz -C /usr/local/mysql-proxy
[root@mysqlproxy ~]# cd /usr/local/mysql-proxy/
[root@mysqlproxy mysql-proxy]# mkdir lua #创建脚本存放目录
[root@mysqlproxy mysql-proxy]# mkdir logs #创建日志目录
[root@mysqlproxy mysql-proxy]# cp share/doc/mysql-proxy/rw-splitting.lua ./lua/ #复制读写分离配置文件
[root@mysqlproxy mysql-proxy]# cp share/doc/mysql-proxy/admin-sql.lua ./lua/ ##复制管理脚本
[root@mysqlproxy mysql-proxy]# vim /etc/mysql-proxy.cnf #创建配置文件
[mysql-proxy]
user=root #运行mysql-proxy用户
admin-username='admin'
admin-password='admin'
proxy-address=172.25.70.4 #mysql-proxy运行ip和端口,不加端口,默认4040
proxy-read-only-backend-addresses=172.25.70.3 #指定后端从slave读取数据
proxy-backend-addresses=172.25.70.2 #指定后端主master写入数据
proxy-lua-script=/usr/local/mysql-proxy/lua/rw-splitting.lua #指定读写分离配置文件位置
admin-lua-script=/usr/local/mysql-proxy/lua/admin-sql.lua #指定管理脚本
log-file=/usr/local/mysql-proxy/logs/mysql-proxy.log #日志位置
log-level=info #定义log日志级别,由高到低分别有(error|warning|info|message|debug)
daemon=true #以守护进程方式运行
#keepalive=true #mysql-proxy崩溃时,尝试重启
plugins=admin
chmod 660 /etc/mysql-porxy.cnf
vim /usr/local/mysql-proxy/lua/rw-splitting.lua
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 1, #默认超过4个连接数时,才开始读写分离,改为1
max_idle_connections = 1, #默认8,改为1
is_debug = false
}
end
/usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnf ##启动mysql-proxy
##此时可以查看到3306和4041端口已经开放
关闭mysql-proxy使用:killall -9 mysql-proxy
在server2上,主服务器上
mysql> grant select,update,insert on *.* to proxy@'172.25.70.%' identified by 'Lcl@0514';
Query OK, 0 rows affected, 1 warning (0.31 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.13 sec)
##这个时候,主从服务器上都有proxy用户
读写分离测试可以参考这个链接:
测试