在企业应用中,成熟的业务通常数据量都比较大,单台MysQL在安全性、高可用性和高并发方面都无法满足实际的需求配置多台主从数据库服务器以实现读写分离
主从复制原理
MySQL复制类型
- 基于行复制
- 基于sql语句复制
- 混合型复制
MySQL主从复制默认使用的机制
- 1.全同步
- 2.半同步
- 3.异步(默认)
MySQL主从复制工作过程
原理在于两个日志文件,和三个线程
-
2个日志文件:二进制和中继 master:bin-log slave:relay-log
-
3个线程:1.master上的dump线程 2.slave上的IO线程和SQL线程
-
目的:slave上到中继日志 趋近实时同步master上的二进制日志,首先,slave上的IO线程–》master上申请同步二进制日志的更新内容。Dump线程会吧同步的sql日志内容给予slave服务器,slave上的IO线程就会写入自己的中继日志。Slave sql线程把日志中的更新语句同步执行到数据库内部。以达到和master服务器趋近一致。
-
如果主,从数据库版本不一致怎么兼容:从版本大于主。
主从复制实验
需要一个master,两个slave
1.主从同步时间
①.安装ntp,修改配置文件
master
[root@www ~]# hostnamectl set-hostname master //永久修改主机名
[root@www ~]# su
[root@master ~]#
[root@master ~]# yum -y install ntp ntpdate
[root@master ~]# ntpdate ntp.aliyum.com //时间同步
18 Jul 16:12:52 ntpdate[25246]: no server suitable for synchronization found
[root@master ~]# vim /etc/ntp.conf
...
disable monitor
fudge 127.127.1.0 stratum 10 //设置本机时间层级为10级
server 127.127.1.0 //设置本机为时间同步源
②.开启ntp服务,关闭防火墙和安全功能
[root@master ~]# systemctl stop firewalld.service
[root@master ~]# systemctl start ntpd
[root@master ~]# setenforce 0
两台slave服务器配置相同
[root@slave1 ~]# ntpdate 192.168.233.105
18 Jul 22:09:56 ntpdate[8719]: adjust time server 192.168.233.105 offset -0.060583 sec
[root@slave1 ~]# crontab -e
*/10 * * * * /usr/sbin/ntpdate 192.168.233.105 //每十分钟与master同步一次时间
2.配置主从同步
主MySQL配置文件修改
[root@master etc]# vim /etc/my.cnf
[client]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysql]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
port = 3306
character_set_server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket = /usr/local/mysql/mysql.sock
server-id = 11
log-bin=master-bin
log_slave_updates=true
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
配置规则
[root@master ~]# mysql -uroot -p password
mysql> grant replication slave on *.* to 'myslave'@'192.168.233.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.32 sec
//设置权限:给从服务器提权,允许使用slave的身份复制master的所有数据库的所有表。并指定密码为123456
mysql> flush privileges; //刷新权限表
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 154 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
//以上可见产生了master-bin.000001的日志文件,定位为154
//从服务器需要定位到此处进行复制
从MySQL配置文件修改
[root@slave1 ~]# vim /etc/my.cnf
server-id = 22
log-bin=mysql-bin
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
//另一个slave将server-id修改为33
开启从服务功能
[root@slave2 ~]# mysql -uroot -p123456
mysql> change master to master_host='192.168.233.105',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=154;
mysql> start slave; //启动同步
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status; //查看slave状态
......
Slave_IO_Running: Yes //IO和SQL的running显示yes时表示同步成功
Slave_SQL_Running: Yes
......
Master_Server_Id: 11
验证主从复制
在master上添加一个新的库
mysql> create database xzw;
//创建xzw库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| xzw |
+--------------------+
slave上查看库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| xzw |
+--------------------+
6 rows in set (0.00 sec)
MySQL读写分离
MySQL读写分离原理
- 只在主服务器上写,只在从服务器上读
- 主数据库处理事务性查询,从数据库处理SELECT查询
- 数据库复制用于将事务性查询的变更同步到集群中的从数据库
读写分离方案
基于程序代码内部实现
在代码中根据 select、insert进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;缺点是需要开发人员来实现,运维人员无从下手。
但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程
序代码中实现读写分离对代码改动就较大。
基于中间代理层实现
代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库
-
MySQL-Proxy
MySQL-Proxy为 MySQL 开源项目,通过其自带的 lua脚本进行sgL 判断。 -
Amoeba
Amoeba由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。
搭建MySQL读写分离
1.安装Java环境
将jdk-6u14-linux-x64.bin放到/usr/local目录下。
给jdk文件提权
[root@localhost local]# chmod +x jdk-6u14-linux-x64.bin
[root@localhost local]# ./jdk-6u14-linux-x64.bin //运行,空格加载,输入yes,按enter。
修改jdk文件名
[root@localhost local]# mv jdk1.6.0_14/ /usr/local/jdk1.6
添加环境变量
[root@localhost local]# vim /etc/profile
.......
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
加载
[root@localhost local]# source /etc/profile
查看版本
[root@localhost local]# java -version
2.安装Amoeba
[root@localhost local]# mkdir /usr/local/amoeba
[root@localhost local]# tar xzvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@localhost local]# chmod -R 755 /usr/local/amoeba/
[root@localhost local]# /usr/local/amoeba/bin/amoeba
amoeba start|stop
//如果显示amoeba start | stop 说明安装成功
3.配置Amoeba读写分离
先在master和两个slave的MySQL上开放权限给Amoeba访问
mysql> grant all on *.* to test@'192.168.233.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.01 sec)
修改amoeba主配置文件
[root@localhost local]# cd amoeba/conf/
[root@localhost conf]# vim amoeba.xml
30 <property name="user">amoeba</property>
31
32 <property name="password">123456</property>
......
115 <property name="defaultPool">master</property>
......
117 <!-- -->
118 <property name="writePool">master</property>
119 <property name="readPool">slaves</property>
修改数据库配置文件
[root@localhost conf]# vim dbServers.xml
23 <property name="schema">mysql</property>
24
25 <!-- mysql user -->
26 <property name="user">test</property>
......
28 <!-- mysql password -->
29 <property name="password">123.com</property>
......
45 <dbServer name="master" parent="abstractServer">
.....
48 <property name="ipAddress">192.168.233.105</property> //修改master的服务器IP
......
52 <dbServer name="slave1" parent="abstractServer">
53 <factoryConfig>
54 <!-- mysql ip -->
55 <property name="ipAddress">192.168.233.103</property>
59 <dbServer name="slave2" parent="abstractServer">
60 <factoryConfig>
61 <!-- mysql ip -->
62 <property name="ipAddress">192.168.233.104</property>
63 </factoryConfig>
64 </dbServer>
......
66 <dbServer name="slaves" virtual="true">
.......
72 <property name="poolNames">slave1,slave2</property>
启动amoeba
[root@localhost conf]# /usr/local/amoeba/bin/amoeba start&
[root@localhost ~]# netstat -antp | grep 8066
tcp6 0 0 :::8066 :::* LISTEN 3866/java
tcp6 0 0 192.168.233.106:8066 192.168.233.101:46544 ESTABLISHED 3866/java
客户端测试
下载mariadb
[root@client ~]# yum -y install mariadb
[root@client ~]# systemctl stop firewalld.service
[root@client ~]# setenforce 0
[root@client ~]# mysql -u amoeba -p 123456 -h 192.168.233.106 -P8066
Enter password: 123456
MySQL [123456]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| xzw |
+--------------------+
5 rows in set (0.62 sec)
4.测试读写分离
测试一
测试amoeba服务器是否关联后端MySQL
[root@client ~]# mysql -u amoeba -p 123456 -h 192.168.233.106 -P8066
Enter password:
MySQL [xzw]> show tables;
Empty set (0.01 sec) //此时库中没有表
MySQL [xzw]> create table test1(id int); //创建表
Query OK, 0 rows affected (0.37 sec) //创建成功
测试二
读写分离架构,关闭两台slave主从同步,测试amoeba读写分离
关闭slave的同步
slave1和slave2:
mysql> stop slave;
客户端添加信息
MySQL [xzw]> insert into test1 values(3); //在test1中添加3
Query OK, 1 row affected (0.01 sec
master服务器查看
mysql> select * from test1;
+------+
| id |
+------+
| 3 |
+------+
//主服务器已经更新信息
从服务器查看
mysql> select * from test1;
+------+
| id |
+------+
| 1 |
+------+
//只有从服务器自己添加的数字,没有最新的信息
测试三
读写分离架构,对于‘读’的任务操作
分别在slave1和slave2的test1表插入不同数据。然后用客户端进行查询。
slave1:
mysql> insert into hello value(2);
Query OK, 1 row affected (0.01 sec)
slave2
mysql> insert into hello value(3);
Query OK, 1 row affected (0.20 sec)
客户端访问
MySQL [(none)]> use xzw;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [xzw]> select * from hello;
+------+
| id |
+------+
| 1 |
| 3 |
+------+
2 rows in set (0.00 sec)
MySQL [xzw]> select * from hello;
+------+
| id |
+------+
| 1 |
| 2 |
+------+