MySQL主从复制与读写分离
案例概述
- 在企业应用中,成熟的业务通常数据量都比较大
- 单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求
- 配置多台主从数据库服务器以实现读写分离
案例前置知识点
MySQL主从复制原理
- MySQL的复制类型
- 基于语句的复制
- 基于行的复制
- 混合类型的复制
- MySQL主从复制的工作过程
MySQL读写分离原理
- 只在主服务器上写,只在从服务器上读
- 主数据库处理事务性查询,从数据库处理SELECT查询
- 数据库复制用于将事务性查询的变更同步到集群中的从数据库
- 读写分离方案
- 基于程序代码内部实现
- 基于中间代理层实现
- MySQL-Proxy
- Amoeba
案例环境
案例实施(主从复制)
主服务器(master)
关闭防火墙和核心防护
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
修改用户名
[root@localhost ~]# hostnamectl set-hostname master
同步阿里云服务器
[root@master ~]# ntpdate ntp1.aliyun.com
[root@master ~]# date -R
mysql主服务器配置
[root@master ~]# vi /etc/my.cnf
server-id = 11
log-bin = master-bin ##主服务器日志文件
log-slave-updates ##从服务器更新二进制日志
[root@master ~]# systemctl restart mysqld
[root@master ~]# ls /usr/local/mysql/data/ #检查是否产生日志文件
[root@master ~]# mysql -uroot -p
mysql> grant replication slave on *.* To 'myslave'@'20.0.0.%' identified by '123456';
mysql> select host,user from mysql.user; #创建成功20.0.0.%
+-----------+---------------+
| host | user |
+-----------+---------------+
| 20.0.0.% | myslave |
| localhost | mysql.session |
| localhost | mysql.sys |
| localhost | root |
+-----------+---------------+
mysql> flush privileges;
mysql> show master status; #主从复制是依赖日志和定位599
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 599 | | | |
+-------------------+----------+--------------+------------------+-------------------+
从服务器(slave1)
关闭防火墙和核心防护
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
修改用户名
[root@localhost ~]# hostnamectl set-hostname slave1
同步阿里云服务器
[root@slave1 ~]# ntpdate ntp1.aliyun.com
[root@slave1 ~]# date -R
[root@slave1 ~]# vi /etc/my.cnf
server-id = 22
relay-log = relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index = slave-relay-bin.index #定义relay-log的位置和名称
[root@slave1 ~]# systemctl restart mysqld
[root@slave1 ~]# mysql -uroot -p
mysql> change master to master_host='20.0.0.26',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=599;
mysql> start slave; #开启
mysql> show slave status\G #查看主从同步的状态 “\G”:将查询到的横向表格纵向输出,方便阅读
...
Slave_IO_Running: Yes #IO和SQL是否是yes模式
Slave_SQL_Running: Yes
...
从服务器(slave2)
关闭防火墙和核心防护
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
修改用户名
[root@localhost ~]# hostnamectl set-hostname slave2
同步阿里云服务器
[root@slave2 ~]# ntpdate ntp1.aliyun.com
[root@slave2 ~]# date -R
[root@slave2 ~]# vi /etc/my.cnf
server-id = 33
relay-log = relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index = slave-relay-bin.index #定义relay-log的位置和名称
[root@slave2 ~]# systemctl restart mysqld
[root@slave2 ~]# mysql -uroot -p
mysql> change master to master_host='20.0.0.26',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=599;
mysql> start slave; #开启
mysql> show slave status\G #查看主从同步的状态 “\G”:将查询到的横向表格纵向输出,方便阅读
...
Slave_IO_Running: Yes #IO和SQL是否是yes模式
Slave_SQL_Running: Yes
...
验证主从复制效果
登录20.0.0.26(master)
[root@localhost ~]# mysql -uroot -p
mysql> create database school;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
登录20.0.0.25(slave1)
[root@localhost ~]# mysql -uroot -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
登录20.0.0.29(slave2)
[root@localhost ~]# mysql -uroot -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
上述说明新建的school数据库同步成功
案例实施(读写分离)
服务器(amoeba)
关闭防火墙和核心防护
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
修改用户名
[root@localhost ~]# hostnamectl set-hostname amoeba
- 导入jdk-6u14-linux-x64.bin文件
- 授予执行权限:chmod +x jdk-6u14-linux-x64.bin
- 执行二进制文件:./jdk-6u14-linux-x64.bin
(一路按回车就行、yes、回车)
[root@amoeba ~]# mv jdk1.6.0_14/ /usr/local/jdk1.6 #移到/usr/local/jdk1.6目录下
[root@amoeba ~]# vi /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@amoeba ~]# source /etc/profile #执行
[root@amoeba ~]# mkdir /usr/local/amoeba
[root@amoeba ~]# tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@amoeba ~]# chmod -R 755 /usr/local/amoeba #授予权限
检验amoeba是否能执行
[root@amoeba ~]# ls /usr/local/amoeba/bin/
amoeba amoeba.classworlds benchmark.bat
amoeba.bat benchmark benchmark.classworlds
[root@amoeba ~]# /usr/local/amoeba/bin/amoeba
显示amoeba start|stop说明安装成功
在三台MySQL上添加权限开发给amoeba访问
mysql> grant all on *.* to test@'20.0.0.%' identified by '123.com'; #20.0.0网段授予权
mysql> flush privileges; #刷新
回到amoeba服务器
[root@amoeba ~]# cd /usr/local/amoeba/conf/
[root@amoeba conf]# vi amoeba.xml
----30行----(账号)
<property name="user">amoeba</property>
----32行----(密码)
<property name="password">123456</property>
----115行----(只是定义一个名称)
<property name="defaultPool">master</property>
----117行去掉注释----(只是定义一个名称)
<property name="writePool">master</property>(写)
<property name="readPool">slaves</property>(读取)
<property name="needParse">true</property>
[root@amoeba conf]# vi dbServers.xml
----23行----(注意!!mysql5.7,默认没有test数据库所以需要修改为mysql数据库) - (mysql5.5、5.6直接忽略,因为有test数据库)
<property name="schema">mysql</property>
----26-29行----
<property name="user">test</property>
<!-- mysql password -->
<property name="password">123.com</property>
----45-50行主服务器----
<dbServer name="master" parent="abstractServer"> #主服务器主机名
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress"20.0.0.26></property> #主服务器地址
</factoryConfig>
</dbServer>
----52-57行从服务器(1)----
<dbServer name="slave1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">20.0.0.25</property>
</factoryConfig>
</dbServer>
----69-64行从服务器(2)----(源文件没有,复制服务器1的)
<dbServer name="slave2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">20.0.0.29</property>
</factoryConfig>
</dbServer>
----65-73行--与amoeba.xml相匹配
<dbServer name="slaves" virtual="true">
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
<property name="loadbalance">1</property>
<!-- Separated by commas,such as: server1,server2,server1 -->
<property name="poolNames">slave1,slave2</property>
</poolConfig>
</dbServer>
[root@amoeba conf]# /usr/local/amoeba/bin/amoeba start& 开启amoeba
jobs 查看SQL 中JOB 的运行状态
[12] Running /usr/local/amoeba/bin/amoeba start & 成功
测试客户端
[root@amoeba conf]# yum install -y mariadb*
[root@amoeba conf]# systemctl start mariadb.service
[root@amoeba conf]# mysql_secure_installation #自定义部署
Set root password? [Y/n]y 设置密码
Remove anonymous users? [Y/n]n 删除匿名用户 ... skipping跳过
Disallow root login remotely? [Y/n]n 禁用远程登录
Remove test database and access to it? [Y/n]n 删除测试数据库
Reload privilege tables now? [Y/n] y 重新加载privilege数据库
[root@amoeba conf]# mysql -uamoeba -p -h 127.0.0.1 -P8066 123456
MySQL [school]> show tables; #查看之前的表
MySQL [school]> create table test (id int(4) not null primary key,name varchar(10)); #创建一个新的表
MySQL [school]> insert into test values ('1','T1');
MySQL [school]> select * from test; #查看不了数据,因为从服务器关闭了
Empty set (0.04 sec)
master (20.0.0.26)
[root@master ~]# mysql -uroot -p
mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| test |
+------------------+
mysql> select * from test; #主服务器可以看到
+----+------+
| id | name |
+----+------+
| 1 | T1 |
+----+------+
MySQL [school]> select * from test; #读的slave2服务器
+----+------+
| id | name |
+----+------+
| 3 | T3 |
+----+------+
MySQL [school]> select * from test; #读的slave1服务器
+----+------+
| id | name |
+----+------+
| 2 | T2 |
+----+------+
在slave1、slave2服务器中轮询读取数据。
slave1(20.0.0.25)
[root@slave1 ~]# mysql -uroot -p
mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| test |
+------------------+
mysql> stop slave;
mysql> select * from test;
Empty set (0.00 sec)
mysql> insert into test values ('2','T2');
mysql> select * from test;
+----+------+
| id | name |
+----+------+
| 2 | T2 |
+----+------+
slave2(20.0.0.29)
[root@slave2 ~]# mysql -uroot -p
mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| test |
+------------------+
mysql> stop slave;
mysql> insert into test values ('3','T3');
mysql> select * from test;
+----+------+
| id | name |
+----+------+
| 3 | T3 |
+----+------+
可能遇到的问题:
/usr/local/amoeba/bin/amoeba start&开启失败
org.xml.sax.SAXParseException: Element type "property" must be followed by either attribute specifications, ">" or "/>".
解决:
property附加语句不规范,缺少">" or “/>”,需要自己在修改过的配置文件(dbServers.xml和amoeba.xml)中找咯!!