MySQL主从复制同步与读写分离
前言
- 在企业应用中,成熟的业务通常数据量比较大
- 单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求
一:主从复制因何产生与解决方法
1.1:原因
- 在企业网站中,后端MySQL数据库只有一台时,会有以下问题:
- 遇到单点故障,服务不可用
- 无法处理大量的并发数据请求
- 数据丢失将会造成很大损失
1.2:解决方法
- 增加MySQL数据库服务器,对数据进行备份,形成主备
- 确保主备MySQL数据库服务器数据是一样的
- 主服务器宕机了,备份服务器继续工作,数据有保障
- MySQL主从复制与读写分离是密切相关的
-
通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力
-
Amoeba:是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy,外号变形虫
读取请求发送给从服务器时,采用轮询调度算法
-
主服务器挂掉,我们会采用MHA解决(此实验用不到)
-
此实验涉及到的账号权限
- 主从同步账号
- 节点服务器开放调度账号
- Amoeba代理账号
1.4:MySQL主从复制的类型
- 基于语句的复制(默认)
- 在主服务器上执行的语句,从服务器执行同样的语句
- 基于行的复制
- 把改变的内容复制到从服务器
- 混合类型的复制
- 一旦发现基于语句无法精确复制时,就会采用基于行的复制
1.5:主从复制的工作过程
先找位置,匹配到位置后I/o线程去找二进制日志,进行读取更新,再写入中继日志,从服务器读取中继日志,从而进行相对应操作
二:主从复制实操
2.1:环境
- 四台centos7服务器
- 一台做client
- 一台做mysql主服务器
- 两台做从服务器
2.2:实验目的
- 实现主从复制
2.3:实验步骤
2.3.1:关闭防火墙
- 所有服务器关闭 Firewall或者进行规则设置
systemctl stop firewalld.service
setenforce 0
2.3.2:建立时间同步环境
- 在主服务器上安装配置NTP时间同步服务器
- 使用yum安装NTP服务
- 修改 ntp. conf,设置主服务器为时间同步源
[root@master ~]# yum install ntp -y
[root@master ~]# vim /etc/ntp.conf
...省略内容
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
'添加一下两段'
server 127.127.195.0 '本地是时钟源'
fudge 127.127.195.0 stratum 8 '设置时间层级为8'
...省略内容
[root@master ~]# systemctl start ntpd
- 在从服务器上进行时间同步
- 使用yum安装 ntpdate并进行时间同步
[root@slave1 ~]# yum install ntp ntpdate -y
[root@slave1 ~]# systemctl start ntpd
[root@slave1 ~]# /usr/sbin/ntpdate 20.0.0.51
'两台从服务器都这样设置'
2.3.3:编译安装mysql
- 三台mysql数据库都要进行编译安装mysql
2.3.4:配置mysql主服务器
- 修改/etc/my.cnf配置文件,增加服务器id,配置二进制日志选项
[root@master ~]# setenforce
[root@master ~]# iptables -F
[root@master ~]# vim /etc/my.cnf
'mysqld字段下面修改'
server-id = 11
log-bin=master-bin
log-slave-updates=true
[root@master ~]# systemctl start mysqld
- 登陆mysql服务,授权所有从服务器复制二进制日志的权限
[root@master ~]# mysql -uroot -p
Enter password: 'ab123'
mysql> grant replication slave on *.* to 'myslave'@'20.0.0.%' identified by '123456';
'20.0.0.0段的从服务器拥有复制权限,可以使用myslave身份123456密码复制所有的库和表'
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges; '刷新'
mysql> show master status; '查看日志位置'
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 599 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
2.3.5:配置两台从服务器
- 修改/etc/my.cnf配置文件,增加服务器id,配置二进制日志选项
[root@slave1 ~]# vim /etc/my.cnf
'mysqld字段下面修改'
server-id = 22 '修改为22,另一台从服务器的id设为23,三个id不可相同'
relay-log=relay-log-bin '设置二进制日志名'
relay-log-index=slave-relay-bin.index '从服务器更新二进制日志'
[root@master ~]# systemctl restart mysqld.service '重启mysql服务'
- 登陆mysql服务,配置主从同步
[root@slave1 ~]# mysql -uroot -p
Enter password: '密码为ab123'
mysql> change master to master_host='20.0.0.51',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=599;
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
2.4:测试
- 主服务器创建一个库
[root@master ~]# mysql -uroot -p
Enter password:
mysql> create database student;
Query OK, 1 row affected (0.00 sec)
- 查看两台从服务器是否同步
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| student | '成功同步'
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
三:读写分离
3.1:读写分离因何产生
-
在企业应用中,在大量的数据请求下,单台数据库将无法承担所有的读写操作
- 配置多台数据库服务器以实现读写分离
-
读写分离建立在主从复制的基础上
-
因为在表(Myisam)或者行(innodb)被锁了,只能读而不能写,只能写而不能读
3.2:原理
- 读写分离就是只在主服务器上写,只在从服务器上读
- 主数据库处理事务性査询,而从数据库处理 select査询
- 数据库复制被用来把事务性査询导致的变更同步到集群中的从数据库
3.3:读写分离的注意点
- 主从复制必须有权限设置
-
主服务器要开一个主从复制的权限账户(第一个账号)
-
变形虫(代理服务器)把写的操作给master,读的操作给slave,轮询读取,先读取slave1,再读slave2,再读slave1…减轻负担
-
读写分离账户(第二个账号)
-
Client找amoeba进行访问,访问amoeba账号(第三个账号)
四:读写分离实操
4.1:环境
-
基于主从复制环境
-
另外再加一台centos7服务器作为Amoeba服务器
4.2:实验目的
- 通过向mysql主服务器和从服务器写东西,验证
- 客户机通过amoeba服务器写入是写入mysql主服务器
- 客户机通过amoeba服务器读取数据是从两个slave从服务器上轮询读取数据的
4.3:实验过程
4.3.1:关闭防火墙
systemctl stop firewalld.service
setenforce 0
4.3.2:Amoeba服务器环境安装
- 安装jdk(因为amoeba是Java写的,所以我们需要安装jdk)
- 这边我已经下载好了,直接拖进shell就可以了
[root@localhost ~]# iptables -F
[root@localhost ~]# setenforce 0
[root@localhost ~]# hostnamectl set-hostname amoeba
[root@localhost ~]# su
[root@amoeba ~]# cd /opt/
[root@amoeba opt]# rz -E
rz waiting to receive.
[root@amoeba opt]# ls
30.txt httpd-2.4.25 jdk-6u14-linux-x64.bin opt.zip
amoeba-mysql-binary-2.2.0.tar.gz httpd-2.4.25.tar.gz opt
[root@amoeba opt]# cp jdk-6u14-linux-x64.bin /usr/local/
[root@amoeba opt]# cd /usr/local/
[root@amoeba local]# chmod +x jdk-6u14-linux-x64.bin
[root@amoeba local]# ./jdk-6u14-linux-x64.bin
...期间一直空格,直到要输入yes
Do you agree to the above license terms? [yes or no] yes '输入yes'
'遇到它,按回车'
Press Enter to continue.....
Done.
[root@amoeba local]# mv jdk1.6.0_14/ jdk1.6 '重命名一下'
[root@amoeba 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@amoeba local]# source /etc/profile
[root@amoeba local]# mkdir /usr/local/amoeba
[root@amoeba local]# cd /opt/
[root@amoeba opt]# tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@amoeba opt]# cd /usr/local/
[root@amoeba local]# ls amoeba/
benchmark bin changelogs.txt conf lib LICENSE.txt README.html
[root@amoeba local]# chmod -R 755 /usr/local/amoeba/ '设置权限'
[root@amoeba local]# /usr/local/amoeba/bin/amoeba '查看是否安装成功'
amoeba start|stop
4.3.4:配置Amoeba读写分离,两个slave读负载均衡
- 三台mysql服务器添加权限和用户开放给amoeba访问
grant all on *.* to ‘kevin’@'20.0.0.%' identified by '123.com';
flush privileges;
'通过192.168.79.0段的kevin用户拥有所有权限对于所有的库和表都可以使用123.com来访问'
- 配置amoeba服务器文件
[root@amoeba ~]# cd /usr/local/amoeba/
[root@amoeba amoeba]# vim conf/amoeba.xml '编辑amoeba主配置文件'
30 <property name="user">amoeba</property> '第30行开始修改用户名'
32 <property name="password">123456</property> '使用123456密码访问amoeba服务器'
'移动到117行,开启读写功能池设定'
115 <property name="defaultPool">master</property> '115行修改为master'
116
117 <!-- --> '117行取消注释'
118 <property name="writePool">master</property> '118行修改为master'
119 <property name="readPool">slaves</property> '119行修改为slaves'
[root@amoeba amoeba]# vim conf/dbServers.xml '编辑数据库配置文件'
23 <property name="schema">mysql</property> '23行test修改为mysql'
24 '设置amoeba访问mysql数据库的用户和密码'
25 <!-- mysql user -->
26 <property name="user">test</property> '26行修改用户名'
27
28 <!-- mysql password-->
29 <property name="password">123.com</property> '29行修改密码'
45 <dbServer name="master" parent="abstractServer"> '45行主mysql服务器名称修改为master'
46 <factoryConfig>
47 <!-- mysql ip -->
48 <property name="ipAddress">20.0.0.51</property> '48行修改主服务器IP'
49 </factoryConfig>
50 </dbServer>
51
52 <dbServer name="slave1" parent="abstractServer"> '52行修改从服务器名称'
53 <factoryConfig>
54 <!-- mysql ip -->
55 <property name="ipAddress">20.0.0.52</property> '55行修改从服务器IP'
56 </factoryConfig>
57 </dbServer>
'第一个从服务器段后插入第二个从服务器配置'
58 <dbServer name="slave2" parent="abstractServer">
59 <factoryConfig>
60 <!-- mysql ip -->
61 <property name="ipAddress">20.0.0.48</property>
62 </factoryConfig>
63 </dbServer>
'修改数据库从服务器池'
65 <dbServer name="slaves" virtual="true"> '66行修改数据库服务器为slaves'
66 <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
67 <!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
68 <property name="loadbalance">1</property>
69
70 <!-- Separated by commas,such as: server1,server2,server1 -- >
71 <property name="poolNames">slave1,slave2</property> '72行添加两个从服务器名称slave1,slave2'
4.3.5:查看端口并启动Amoeba
'在打开另一个会话,查看8066端口'
[root@amoeba ~]# netstat -natp | grep java
tcp6 0 0 127.0.0.1:39263 :::* LISTEN 10638/java
tcp6 0 0 :::8066 :::* LISTEN 10638/java
[root@amoeba amoeba]# /usr/local/amoeba/bin/amoeba start&
/conf/log4j.xml
2020-08-26 21:45:43,280 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.2.0
log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf
2020-08-26 21:45:43,526 INFO net.ServerableConnectionManager - Amoeba for Mysql listening on 0.0.0.0/0.0.0.0:8066.
2020-08-26 21:45:43,530 INFO net.ServerableConnectionManager - Amoeba Monitor Server listening on /127.0.0.1:39263.
'此时处于持续监控状态,不要动,否则会改变之前position位置点'
4.4:测试
4.4.1:客户端安装mysql
- 由于是用来验证,所以可以直接用yum安装
'先关闭防火墙,且确认所有服务器的防火墙都已关闭'
[root@client ~]# systemctl stop firewalld.service
[root@client ~]# setenforce 0
[root@client ~]# yum install mysql -y
[root@client ~]# mysql -u amoeba -p123456 -h 20.0.0.51 -P8066
MySQL [(none)]> create database school; '创建一个库'
'进入主从服务器查看,发现mysql主从服务器都已经自动同步'
- 测试读写分离,关闭主从复制功能
'两台从服务器关闭slave功能'
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
...省略内容
Slave_IO_Running: No '发现功能已被关闭'
Slave_SQL_Running: No
...省略内容
- 从服务器配置数据,验证读写分离
MySQL [(none)]> create database student; '//客户端创建库'
'会发现主服务器有,但是从服务器没有,说明主从复制功能已经关闭'
'slave1从服务器设置:都有benet的库,所以各自在benet创建yibiao并插入不同数据'
mysql> use benet;
Database changed
mysql> create table yibiao (id int not null,name char(10));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into yibiao values(1,'zhangsan'); '添加zhangsan记录'
Query OK, 1 row affected (0.02 sec)
mysql> select * from yibiao;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
'slave1从服务器设置:'
mysql> use benet;
Database changed
mysql> create table yibiao(id int not null,name char(10));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into yibiao values(2,'lisi'); '添加lisi记录'
Query OK, 1 row affected (0.02 sec)
mysql> select * from yibiao;
+----+------+
| id | name |
+----+------+
| 2 | lisi |
+----+------+
1 row in set (0.00 sec)
- 验证
'进入客户端测试'
MySQL [(none)]> use benet; '进入库'
Database changed
MySQL [benet]> select * from yibiao;
+----+------+
| id | name |
+----+------+
| 2 | lisi |
+----+------+
1 row in set (0.01 sec)
MySQL [benet]> select * from yibiao;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.01 sec)
'发现每一次查询都会轮询在slave1和slave2上查询数据,如果开启主从复制,则数据都会相同'
'读写分离试验成功'