mysql主从复制读写分离

主从复制和读写分离

主从复制 核心原理

必须记住 3 个核心组件

  1. binlog(二进制日志) ------ 主库
  2. IO 线程 ------ 从库
  3. SQL 线程 ------ 从库
    完整流程
  4. 主库执行增删改(insert/update/drop)
  5. MySQL 把这些操作记录到 binlog 日志文件
  6. 从库的 IO 线程连接主库,请求 binlog
  7. 主库的 dump 线程把 binlog 发给从库
  8. 从库 IO 线程将内容写到本地 relay log(中继日志)
  9. 从库 SQL 线程读取中继日志,重放 SQL 语句
  10. 两个 Yes 代表正常:IO_Running、SQL_Running
  11. 从库数据和主库完全一致

计划拓扑图

配置时间同步

通过时间戳实现业务的一致性

bash 复制代码
# 所有节点
ntpdate ntp.aliyun.com
date -R
systemctl disable firewalld --now
setenforce 0

mysql主从服务器配置

mysql主服务器配置

bash 复制代码
[root@mysql-master ~]# vim /etc/my.cnf
server-id = 11
log-bin = master-bin      #主服务器日志文件
log-slave-updates = true   #从服务器更新二进制日志

[root@mysql-master ~]# systemctl restart mysqld
##登陆mysql
[root@mysql-master ~]# mysql -u root -p

mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.108.%' IDENTIFIED BY
'123456';
Query OK, 0 rows affected, 1 warning (0.01 sec)

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 | 604 | | |
|
+-------------------+----------+--------------+------------------+---------------
----+
1 row in set (0.00 sec)

#检查有没有master-bin.000001
[root@mysql-master ~]# ls /usr/local/mysql/data
auto.cnf ibdata1 ib_logfile1 master-bin.000001 mysql
sys ib_buffer_pool ib_logfile0 ibtmp1 master-bin.index performance_schema

mysql从服务器配置

mysql-slave01,mysql-slave02都要做如下操作

bash 复制代码
#主从是克隆的要做这个操作,否则UUID一致
[root@mysql-slave01 ~]# systemctl stop mysqld
[root@mysql-slave01 ~]# rm -f /usr/local/mysql/data/auto.cnf
[root@mysql-slave01 ~]# systemctl start mysqld
[root@mysql-slave01 ~]# vim /etc/my.cnf
server-id = 22 #另外一台为23
relay-log = relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index = slave-relay-bin.index #定义relay-log的位置和名称
[root@mysql-slave01 ~]# systemctl restart mysqld
[root@mysql-slave01 ~]# mysql -u root -p
Enter password:

mysql> change master to master_host='192.168.108.101',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=604;
#master_log_file,master_log_pos与前面查询的相同
Query OK, 0 rows affected, 2 warnings (0.03 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.108.101
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 604
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 321
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes    #Yes
Slave_SQL_Running: Yes     #Yes   确保有2个yes
Replicate_Do_DB:
Replicate_Ignore_DB:
...

slave02节点也是一样操作
##注意配置文件修改,其他一样
[root@mysql-slave02 ~]# vim /etc/my.cnf
server-id = 23
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index

验证主从同步

bash 复制代码
# 主服务器上:
[root@mysql-master ~]# mysql -uroot -phuawei

mysql> create database school;
Query OK, 1 row affected (0.01 sec)

mysql> use school;

mysql> CREATE TABLE student (
id int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
age tinyint UNSIGNED,
#height DECIMAL(5,2),
gender ENUM('M','F') default 'M'
)ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4;

mysql> insert student (name,age)values('路飞',20);

# 去从服务器上 show databases;
[root@mysql-slave01 ~]# mysql -uroot -phuawei
mysql> select * from school.student;
+----+--------+------+--------+
| id | name | age | gender |
+----+--------+------+--------+
| 10 | 路飞 | 20 | M |
+----+--------+------+--------+
1 row in set (0.00 sec)

amoeba服务器

读写分离 核心原理

基于 主从复制:

  1. 主库写入数据 → 自动同步到从库
  2. 应用程序收到 SQL:
    insert/update/delete → 走主库
    select → 走从库

Amoeba 是一款基于 Java 开发的 MySQL 数据库代理中间件,核心定位是SQL 路由

1.应用 ↔ Amoeba ↔ MySQL 主从集群,Amoeba 是中间 "SQL 路由器"

2.核心能力:自动识别 SQL 类型,写(INSERT/UPDATE/DELETE)走主库,读(SELECT)走从库,并对从库做负载均衡。

3.依赖前提:必须先搭好 MySQL 主从复制,Amoeba 只负责路由,不负责数据同步

工作流程(读写分离)

  1. 应用连接 Amoeba 代理(默认端口 8066),而非直接连 MySQL。
  2. Amoeba 解析 SQL:
    写操作 → 转发到配置的 主库池(writePool)。
    读操作 → 转发到配置的 从库池(readPool),并按轮询 / 权重做负载均衡。
  3. 主从复制保证从库数据与主库一致,应用无感知。

核心组件(配置文件)

amoeba.xml 代理核心配置:端口、认证、读写池、路由规则、线程池

dbServers.xml 定义后端 MySQL 节点(主 / 从)、连接信息、连接池

bash 复制代码
#普通linux克隆得出amoeba
[root@amoeba ~]# hostnamectl set-hostname amoeba
[root@amoeba ~]# systemctl stop firewalld.service
[root@amoeba ~]# setenforce 0

[root@amoeba ~]# chmod +x jdk-6u14-linux-x64.bin
[root@amoeba ~]# ./jdk-6u14-linux-x64.bin
#到yes的时候,输入yes按enter

[root@amoeba ~]# mv jdk1.6.0_14/ /usr/local/jdk1.6

[root@amoeba ~]# vim /etc/profile
最下面加
export JAVA_HOME=/usr/local/jdk1.6    #java家目录
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib  #类环境和jre
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba    #指定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 start|stop说明安装成功
[root@amoeba ~]# /usr/local/amoeba/bin/amoeba
amoeba start|stop

在三台mysql上添加权限开放给amoeba访问

bash 复制代码
#amooba访问数据库的账号
#mysql-master
mysql> grant all on *.* to test@'192.168.108.%' identified by '123.com';

#mysql-slave01
mysql> grant all on *.* to test@'192.168.108.%' identified by '123.com';

#mysql-slave02
mysql> grant all on *.* to test@'192.168.108.%' identified by '123.com';

回到amoeba服务器

bash 复制代码
[root@amoeba ~]# cd /usr/local/amoeba/
[root@amoeba amoeba]# vim conf/amoeba.xml
---30行--
<property name="user">amoeba</property  #客户端访问amoeba账号

----32行---------
<property name="password">123456</property>  #客户端访问ameoba密码

---117和120-去掉注释115行 <property name="defaultPool">master</property>
116
117
118行<property name="writePool">master</property>
119行<property name="readPool">slaves</property>
120

####################################################################################
[root@amoeba amoeba]# vim conf/dbServers.xml #数据库配置
---23--注意!!!(mysql5.7,默认没有test数据库所以需要修改为mysql数据库)-(mysql5.5直接忽
略)--
<!-- mysql schema -->
<property name="schema">mysql</property>
--25行到30行,第30行-->移动到28行后面
25 <!-- mysql user -->
26 <property name="user">test</property>
27
28 <!-- mysql password -->
29 <property name="password">123.com</property>
30

-----45到50行主服务器地址---
45行<dbServer name="master" parent="abstractServer">
48行<property name="ipAddress">192.168.108.101</property>

--52到57行从服务器主机名52行
<dbServer name="slave1" parent="abstractServer">
<property name="ipAddress">192.168.108.102</property>
---52到57行复制一份在58行后面
<dbServer name="slave2" parent="abstractServer">
 <property name="ipAddress">192.168.108.103</property>

---仅跟在上面的配置后面,multiPool行(本来就有,修改)
<dbServer name="slaves" virtual="true">
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool #不改
<property name="poolNames">slave1,slave2</property>
</poolConfig> #不改

[root@amoeba ~]# /usr/local/amoeba/bin/amoeba start&
[1] 33499
[root@amoeba ~]# netstat -anpt | grep java
tcp6 0 0 :::8066 :::* LISTEN
33499/java
tcp6 0 0 127.0.0.1:21128 :::* LISTEN
33499/java
tcp6 0 0 192.168.108.110:41754 192.168.108.101:3306 ESTABLISHED
33499/java
tcp6 0 0 192.168.108.110:41722 192.168.108.102:3306 ESTABLISHED
33499/java
tcp6 0 0 192.168.108.110:36956 192.168.108.103:3306 ESTABLISHED
33499/java

测试客户端

bash 复制代码
[root@mysql-client ~]# yum install -y mysql
[root@mysql-client ~]# mysql -u amoeba -p123456 -h 192.168.108.110 -P8066
 #连接amoeba服务器,8086端口在amoeba上执行netstat -anpt|grep java看

在MASTER上

bash 复制代码
[root@mysql-master ~]# mysql -u root -p
Enter password:

mysql> use school;
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> insert student (name,age)values('鸣人',20);
Query OK, 1 row affected (0.00 sec)


#此时会同步
#mysql-slave01
mysql> select * from student;
+----+--------+------+--------+
| id | name | age | gender |
+----+--------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
+----+--------+------+--------+
2 rows in set (0.00 sec)
#mysql-slave02
mysql> select * from student;
+----+--------+------+--------+
| id | name | age | gender |
+----+--------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
+----+--------+------+--------+
2 rows in set (0.00 sec)

在两台从上关闭,客户端上插入数据,内容不会同步

bash 复制代码
# mysql-slave01
mysql> stop slave;
# mysql-slave02
mysql> stop slave;

#mysql-client上添加,由于不会同步,只有mysql-master192.168.108.101节点有该记录
# mysql-client
MySQL [school]> insert student (name,age)values('卡卡西',30);

#mysql-slave01
mysql> use school;
mysql> insert student (name,age)values('卡卡西',31);

# mysql-slave02
mysql> use school;
mysql> insert student (name,age)values('卡卡西',32);

验证主从复制

在mysql-slave01和mysql-slave02上查看

bash 复制代码
# mysql-slave01
mysql> select * from student;
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
| 12 | 卡卡西 | 31 | M |
+----+-----------+------+--------+
3 rows in set (0.00 sec)
#mysql-slave02
mysql> select * from student;
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
| 12 | 卡卡西 | 32| M |
+----+-----------+------+--------+
3 rows in set (0.00 sec)

并没有将客户端写入的insert student (name,age)values('卡卡西',30);同步

bash 复制代码
# mysql-master
mysql> select * from student;
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
| 12 | 卡卡西 | 30 | M |
+----+-----------+------+--------+
3 rows in set (0.00 sec)

验证读写分离

在客户端上测试,第一次会向从服务器1读数,据-第二次会向从2读取

bash 复制代码
#mysql-client
MySQL [(none)]> select * from school.student;
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
| 12 | 卡卡西 | 31 | M |
+----+-----------+------+--------+
3 rows in set (0.02 sec)
MySQL [(none)]> select * from school.student;
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 10 | 路飞 | 20 | M |
| 11 | 鸣人 | 20 | M |
| 12 | 卡卡西 | 32 | M |
+----+-----------+------+--------+
3 rows in set (0.00 sec)
#都是从从节点读取的,读写分离,由实验结果可知:客户端的读取内容会从mysql-slave01和mysqlslave02上轮询得到。
相关推荐
唐青枫2 天前
MySQL JSON 实战详解:从存储、查询、更新到 JSON_TABLE 与索引
sql·mysql
小满8782 天前
5.Mysql事务隔离级别与锁机制
mysql
元Y亨H3 天前
技术笔记:MySQL 字符集排序规则与大小写敏感性问题解决方案
mysql
这个DBA有点耶4 天前
GROUP BY优化全解:如何写出既不丢数据又飞快的分组查询
数据库·mysql·架构
掉头发的王富贵4 天前
【StarRocks】极限十分钟入门StarRocks
数据库·sql·mysql
SamDeepThinking4 天前
一条UPDATE语句在MySQL 8.0中到底加了几把锁?
后端·mysql·程序员
李白客6 天前
KES新版MySQL兼容能力再升级意味着什么?
mysql·国产数据库
Jim6008 天前
【吃透 MySQL InnoDB连载】第 1 章・解密线上数据库高频故障
mysql
GreatSQL8 天前
gt-checksum v4.0.0 新功能解读系列文章(4):SSL 加密连接——数据校验传输安全再升级
mysql