目录
MySQL主从复制与读写原理
MySQL的主从复制和MySQL的读写分离两者有着紧密联系,首先要部署主从复制,只有主从复制完成了,才能在此基础上进行数据的读写分离
MySQL支持的复制类型
- 基于语句的复制。在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高
- 基于行的复制。把改变的内容复制过去,而不是把命令在从服务器上执行一遍
- 混合类型的复制。默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制
- 全局事务标识符GTID
MySQL主从复制的工作过程
- 在每个事务更新完成之前,Master将这些改变记录进二进制日志。写入二进制日志完成后,Master通知存储引擎提交事务
- Slave将Master的Binary log复制到其中继日志(Relay log)。首先,Slave开始一个工作线程----I/O线程,I/O线程在Master上打开一个普通的连接,然后开始Binlog dump process。Binlog dump process从Master的二进制日志中读取事件,如果已经跟上Master,它会睡眠并等待Master产生新的事件。I/O线程将这些事件写入中继日志。
- SQLslave thread(SQL从线程)处理该过程的最后一步。SQL线程中继日志读取事件,并重放其中的事件而更新Slave数据,将其与Master中的数据保持一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。复制过程有一个很重要的限制,即复制在Slave上是串行化的,也就是说Master上的并行更新操作不能在Selave上并行操作。
配置MySQL主从复制
配置三台虚拟机安装mysql环境
192.168.10.101
192.168.10.102
192.168.10.103
配置102.103的mysql环境
[root@localhost ~]# bash install_mysql5.7.28_bin.sh
[root@localhost ~]# ./install_mysql5.7.28_bin.sh
建立时间同步环境
[root@localhost ~]# yum -y install ntp
[root@localhost ~]# vi /etc/ntp.conf
server 127.127.1.0
fudge 127.127.1.0 stratum 8
[root@localhost ~]#systemctl restart ntpd
[root@localhost ~]#systemctl enable ntpd
在从节点上进行时间同步
[root@localhost ~]# yum -y install ntp
[root@localhost ~]#ntpdate 192.168.10.102
MySQL主服务器设置
[root@localhost ~]# vim /etc/my.cnf
server-id=11
log-bin=master-bin
binlog-format=MIXED
replicate-ignore-db=test
binlog-ignore-db=test
binlog-cache-size=1M
expire-logs-days=3
[root@localhost ~]# systemctl restart mysqld
- server-id=11
- 这个参数指定了MySQL服务器的唯一标识符,用于在复制环境中区分不同的服务器。每个服务器在复制拓扑中必须有唯一的 server-id。
- log-bin=master-bin
- 这个参数启用了二进制日志(Binary Log)。二进制日志记录了所有对MySQL数据库的修改操作,包括数据变更和结构变更。master-bin 是二进制日志文件的基本名称,实际文件名会在后面加上一个序列号。
- binlog-format=MIXED
- 这个参数指定了二进制日志的格式。MIXED 格式是一种混合格式,根据具体的操作来决定使用 STATEMENT、ROW 或 MIXED 格式。不同的格式有不同的优劣,MIXED 格式通常能在大多数情况下提供最佳的性能和兼容性。
- replicate-ignore-db=test
- 这个参数指定了在复制过程中忽略的数据库。在这个例子中,test 数据库中的操作将不会被复制到从服务器上。
- binlog-cache-size=1M
- 这个参数设置了二进制日志缓存的大小。二进制日志缓存用于临时存储写入的日志事件,以提高性能。在这里,缓存大小设置为 1MB。
- expire-logs-days=3
- 这个参数指定了二进制日志文件的过期时间。即在三天后,MySQL会自动删除旧的二进制日志文件,以释放磁盘空间。
- log-slave-updates=true
- 这个参数指定了在从服务器上是否记录复制操作。设置为 true 表示在从服务器上记录复制事件,这对于链式复制和复杂的复制拓扑结构非常有用。
为服务器创建一个账户,便于从服务器从主服务器进行日志进步
[root@localhost ~]# mysql -uroot -ppwd123
mysql> grant replication slave on *.* to 'myslave'@'192.168.10.%' identified by '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 | 451 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
从服务器设置
打开102.103主机点击所有会话设置
[root@localhost ~]# vim /etc/my.cnf #102设置
server-id=22
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# vim /etc/my.cnf #103设置
server-id=33
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
[root@localhost ~]# systemctl restart mysqld
建立连接写入到102.103中
mysql> change master to master_host='192.168.10.101',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=451;
在服务器上设置到哪里去同步日志文件,使用的账号与密码,以及同步的位置点
mysql> start slave; #开启从服务器的同步功能
mysql> show slave status\G;
两个线程服务开启,说明已经开始同步
测试主从同步
创建一个新的auth
mysql> create database auth;
mysql> use auth
mysql> show databases; #到102.103依次去查看是否有auth查询的到
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
不想同步把数据写到从服务器当中
101
mysql> create table t1(id int(10),name char(20));
mysql> insert into t1 values(1,'zhangsan');
[root@localhost ~]# vim /etc/my.cnf #102设置
server-id=22
relay-log=relay-log-bin
replicate-ignore-db=test
relay-log-index=slave-relay-bin.index
[root@localhost ~]# systemctl restart mysqld
mysql> select * from test.t1;
+------+----------+
| id | name |
+------+----------+
| 1 | zhangsan |
+------+----------+
103没设置依旧同步
mysql> select * from test.t1;
+------+----------+
| id | name |
+------+----------+
| 1 | zhangsan |
| 1 | zhangsan |
+------+----------+
2 rows in set (0.00 sec)
主服务器可以读可以写
从服务器可以写但不可以读
在102主机上模拟故障
mysql> stop slave; #只能在关闭的情况下进行修改
搭建MySQLD读写分离
MySQL读写分离原理
- 只在主服务器上写,只在从服务器上读
- 主数据库处理事务性查询,从数据库处理SELECT查询
- 数据库复制用于将事务性查询的变更同步到集群中的从数据库
- 读写分离方案
- 基于程序代码内部实现
- 基于中间代理层实现(MySQL-Proxy Amoeba)
主机结构
除了三台服务器,还需要一台amoeba主机作为代理服务器和一台客户端主机作为测试机
这里再打开两台虚拟机,一共就是五台主机
搭建MySQL读写分离
安装JDK
来到104主机
安装这俩个安装包
因为amoeba是java开发的,所以导入amoeba的tar包和jdk的二进制文件
因为他是二进制的文件所以有一个执行权
[root@localhost ~]# chmod +x jdk-6u14-linux-x64.bin
[root@localhost ~]# ./jdk-6u14-linux-x64.bin
Do you agree to the above license terms? [yes or no]
yes
Press Enter to continue..... #回车继续
将安装的目录移动到 /usr/local 下重命名为jdk1.6
[root@localhost ~]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@localhost ~]# vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
[root@localhost jdk1.6]# source /etc/profile #重新加载并执行
[root@localhost jdk1.6]# java -version #查看版本,确认java安装成功
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)
安装amoeba
解压amoeba安装包创建一个目录解压到一个目录下
[root@localhost ~]# mkdir /usr/local/amoeba
[root@localhost ~]# tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@localhost ~]# chmod -R 755 /usr/local/amoeba/
[root@localhost amoeba]# amoeba
amoeba start|stop #说明可以正常使用
来到101分别在主、从服务器上授权
mysql> grant all on *.* to 'test'@'192.168.10.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
配置amoeba配置文件
[root@localhost conf]# vi amoeba.xml
<property name="user">amoeba</property> #将用户名修改为amoeba给客户端使用 大概在30行
<property name="password">123456</property>
#将密码修改为123456 #大概在32行
<property name="defaultPool">master</property> #改为master大概在115行
<property name="writePool">master</property> #读的功能给master取消117行注释修改内容
<property name="readPool">slaves</property> #写的功能给slaves
配置连接后台数据库的文件dbServers
<!-- mysql schema -->
<property name="schema">auth</property> #修改成为你101所创建的库大概在23行
<!-- mysql user -->
<property name="user">test</property> #修改为test 就是在101提权上你所设置的参数
<property name="password">123.com</property> #取消注释大该在28行修改为123.com
<dbServer name="master" parent="abstractServer"> #大概在45行修改成为master
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.10.101</property> #修改端口号
</factoryConfig>
</dbServer>
<dbServer name="slave1" parent="abstractServer"> #修改成为slave1
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.10.102</property> #添加端口号
</factoryConfig>
</dbServer>
<dbServer name="slave2" parent="abstractServer"> #复制上一个修改成为slave2
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.10.103</property> #添加端口号
</factoryConfig>
</dbServer>
<dbServer name="slaves" virtual="true"> #修改成为slaves
<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> #修改成为slave1,slave2
</poolConfig>
</dbServer>
启动amoeba软件
[root@localhost ~]# amoeba start &
#启动后按回车
[root@localhost ~]# netstat -anpt | grep java
tcp6 0 0 :::8066 :::* LISTEN 11755/java
tcp6 0 0 127.0.0.1:28683 :::* LISTEN 11755/java
tcp6 0 0 192.168.10.104:39608 192.168.10.103:3306 ESTABLISHED 11755/java
tcp6 0 0 192.168.10.104:38982 192.168.10.102:3306 ESTABLISHED 11755/java
tcp6 0 0 192.168.10.104:55988 192.168.10.101:3306 ESTABLISHED 11755/java
[root@localhost ~]# systemctl stop firewalld
测试
[root@localhost ~]# yum -y install mysql
mysql> use auth;
MySQL [auth]> create table users(name char(20),pass char(50));
MySQL [auth]> insert into users values('bbb','123456');
MySQL [auth]> select * from users;
+------+--------+
| name | pass |
+------+--------+
| bbb | 123456 |
+------+--------+
1 row in set (0.01 sec)
来到102主机上
mysql> insert into users values('1','123456');
mysql> select * from users;
+------+--------+
| name | pass |
+------+--------+
| bbb | 123456 |
| 1 | 123456 |
+------+--------+
2 rows in set (0.00 sec)
在来到105测试主机上,显示的数据一有一无
MySQL [auth]> select * from users;
+------+--------+
| name | pass |
+------+--------+
| bbb | 123456 |
+------+--------+
MySQL [auth]> select * from users;
+------+--------+
| name | pass |
+------+--------+
| bbb | 123456 |
| 1 | 123456 |
+------+--------+
2 rows in set (0.01 sec)