Mysql的主从复制与读写分离

前言

MySQL使用主从复制与读写分离的原因:

  • 在企业应用中,成熟的业务通常数据量都比较大
  • 单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求
    (myisam基于表级锁定;innodb基于行级锁定 --存储引擎不能满足并发读、写的需求)
  • 配置多台主从数据库服务器以实现读写分离

一、MySQL主从复制原理

1.1 MySQL的复制类型

  • 基于语句的复制
  • 基于行的复制
  • 混合类型的复制(语句、行、日志文件)

1.2 MySQL主从复制的工作过程

在这里插入图片描述

二、MySQL读写分离原理

  • 只在主服务器上写,只在从服务器上读

  • 主数据库处理事务性查询,从数据库处理select查询

  • 数据库复制用于将事务性查询的变更同步到集群中的从数据库
    读写分离原理示意图
    在这里插入图片描述

  • 复制的基本过程如下

  1. Master将用户对数据库更新的操作以二进制格式保存到Binary Log日志文件中;
  2. Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
  3. Master接收来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取制定日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置;
  4. Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清除的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”;
  5. SlaveSql进程检测到relay-log中新增了内容后,会马上解析relay-log的内容称为在Master端真实执行时候的那些可执行的内容,并在自身执行。

三、MySQL读写分离环境

三台装有MySQL5.7版本的服务器,角色分配如下:
master:10.0.0.40
slave-1:10.0.0.41
slave-2:10.0.0.42
一台Amoeba代理服务器
Amoeba:10.0.0.49

四、MySQL主从同步以及读写分离步骤

先把服务器的防火墙和核心防护全部关闭。

[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0

4.1 主从同步部分

  • 主服务器:
  1. 时间同步
[root@master ~]# yum -y install ntp ntpdate
[root@master ~]# ntpdate ntp.aliyun.com
[root@master ~]# vi /etc/ntp.conf 
server 127.127.1.0             #本地是时钟源
fudge 127.127.1.0 stratum 8    #设置时间层级为8
[root@master ~]# systemctl start ntpd
  1. mysql主服务器配置
[root@master ~]# vi /etc/my.cnf
server-id = 1               #指定id号,服务器的唯一标识,不能相同
log-bin=master-bin           #主服务器日志文件
log-slave-updates=true       #从服务器更新二进制日志
[root@master ~]# systemctl restart mysqld
[root@master ~]# mysql -u root -pqwe123
mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'10.0.0.%' IDENTIFIED BY 'abc123';
mysql> flush privileges;
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000006 |      120 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
# 特别注意File和Position对应的master-bin.000006以及120两个参数,从服务器同步时需要用到
  • 从服务器
  1. 时间同步
[root@slave-1 ~]# yum -y install ntpdate
[root@slave-1 ~]# ntpdate 10.0.0.40
  1. mysql主服务器配置
[root@slave-1 ~]# vi /etc/my.cnf
server-id = 12       
relay-log=relay-log-bin     #从主服务器上同步日志文件记录到本地  
relay-log-index=slave-relay-bin.index   #定义relay-log的位置和名称
[root@slave-1 ~]# systemctl restart mysqld
[root@slave-1 ~]# mysql -u root -pqwe123
mysql> change master to master_host='10.0.0.40',master_user='myslave',master_password='abc123',master_log_file='master-bin.000006',master_log_pos=120;
mysql> start slave;    #开启从服务 
mysql> show slave status\G;    #查看状态
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.40
                  Master_User: myslave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000004
          Read_Master_Log_Pos: 120
               Relay_Log_File: localhost-relay-bin.000002
                Relay_Log_Pos: 284
        Relay_Master_Log_File: master-bin.000004
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 120
              Relay_Log_Space: 461
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: d67a9e7a-189b-11eb-8dfe-000c29302649
             Master_Info_File: /usr/local/mysql/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
1 row in set (0.00 sec)

实验验证

  • 主服务器
mysql> create database follow;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| follow             |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
  • 从服务器
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| follow             |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)

4.2 读写分离部分

  1. 安装jdk环境
[root@amoeba packages]# tar zxf jdk-8u91-linux-x64.tar.gz
[root@amoeba packages]# mv jdk1.8.0_91/ /usr/local/java
[root@amoeba packages]# vi /etc/profile
#末尾添加
export JAVA_HOME=/usr/local/java    
export JRE_HOME=/usr/local/java/jre
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$JAVA_HOME/bin:$AMOEBA_HOME/bin
[root@amoeba packages]# source /etc/profile
  1. 安装amoeba代理
[root@amoeba packages]# unzip amoeba-mysql-3.0.5-RC-distribution.zip
[root@amoeba packages]# mv amoeba-mysql-3.0.5-RC /usr/local/amoeba
[root@amoeba ~]# chmod -R 755 /usr/local/amoeba/
[root@amoeba ~]# vi /usr/local/amoeba/jvm.properties
 32 #JVM_OPTIONS="-server -Xms256m -Xmx1024m -Xss196k -XX:PermSize=16m -XX:MaxPe    rmSize=96m"
 33 JVM_OPTIONS="-server -Xms1024m -Xmx1024m -Xss256k"
  1. 在三台MySQL上添加权限开放给amoeba访问
mysql> grant all on *.* to 'test'@'10.0.0.%' identified by 'abc123';
  1. 修改amoeba主配置文件
[root@amoeba ~]# vi /usr/local/amoeba/conf/amoeba.xml
#26,28行修改如下 修改客户端连接amoeba前端服务器时使用的用户名和密码
<property name="user">amoeba</property>
<property name="password">123123</property>

#83行修改如下(去掉注释)
<property name="defaultPool">master</property>
<property name="writePool">master</property>
<property name="readPool">slaves</property>
  1. 修改dbServers.xml 文件
[root@amoeba ~]# vi /usr/local/amoeba/conf/dbServers.xml 
指定为amoeba创建的允许读取数据库的用户名和密码
22                         <!-- mysql schema -->
23                         <property name="schema">mysql</property> ###5.7版本没有默认的test数据库
24                         <!-- mysql user -->
25                         <property name="user">test</property>
26                         <!-- mysql password -->
27                         <property name="password">abc123</property>

配置三个服务器主机名和地址
         <dbServer name="master"  parent="abstractServer">
                 <factoryConfig>
                         <property name="ipAddress">10.0.0.40</property>
                 </factoryConfig>
         </dbServer>

         <dbServer name="slave1"  parent="abstractServer">
                 <factoryConfig>
                         <property name="ipAddress">10.0.0.41</property>
                 </factoryConfig>
         </dbServer>
 
         <dbServer name="slave2"  parent="abstractServer">
                 <factoryConfig>
                         <property name="ipAddress">10.0.0.42</property>
                 </factoryConfig>
         </dbServer>

指定名为slaves的poolNames中pools的主机名
         <dbServer name="slaves" virtual="true">
                         <property name="poolNames">slave1,slave2</property>
         </dbServer>

额外需要注意!!
阿米巴做读写分离的时候:5.7版本没有test默认数据库
#23行需要注意!!!mysql5.7版本,默认没有test数据库所以修改为mysql数据库,5.5版本可忽略

  1. 启动amoeba服务器准备测试
[root@amoeba ~]# /usr/local/amoeba/bin/launcher
[root@amoeba ~]# netstat -anpt | grep 8066
tcp6       0      0 :::8066                 :::*                    LISTEN      3226/java
  1. 验证
  • 在master新建库和表
mysql> create database amoeba;
mysql> use amoeba;
mysql> create table test(id int(2),name varchar(64));
  • 在两台从服务器上停止服务
mysql> stop slave;
  • 在主服务上插入内容不会同步(通过amoeba操作)

主服务器

mysql> insert into test values(1,'alice');

从服务器

mysql> select * from amoeba.test;
Empty set (0.00 sec)
  • 在从服务器1上直接插入内容
mysql> insert into amoeba.test values(2,'ben');
mysql> select * from amoeba.test;
+------+------+
| id   | name |
+------+------+
|    2 | ben  |
+------+------+
  • 在从服务器2上直接插入内容
mysql> insert into amoeba.test values(3,'chalice');
mysql> select * from amoeba.test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
+------+---------+
  • 在客户端amoeba上测试读操作
[root@localhost ~]# mysql -uamoeba -p123123 -h 10.0.0.49 -P 8066
mysql> use amoeba;
mysql> select * from test;
+------+------+
| id   | name |
+------+------+
|    2 | ben  |
+------+------+
1 row in set (0.01 sec)

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
+------+---------+
1 row in set (0.00 sec)

第一次向从服务器1读数据,第二次向从服务器2读数据,不会读取到主服务器的数据

  • 在客户端测试写操作
客户端
mysql> insert into test values(4,'david');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test;
+------+------+
| id   | name |
+------+------+
|    2 | ben  |
+------+------+
1 row in set (0.00 sec)

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
+------+---------+
1 row in set (0.00 sec)

主:
mysql> select * from amoeba.test;
+------+-------+
| id   | name  |
+------+-------+
|    1 | alice |
|    4 | david |
+------+-------+
2 rows in set (0.00 sec)

在客户端上看不到新插入的数据,只能在主服务器端看到,说明写操作在主服务器上,证明已经实现读写分离。

  • 在客户端amoeba上看不到新插入的数据,因为同步没有开启,只有主服务器上可以看到数据
mysql> select * from test;
+------+------+
| id   | name |
+------+------+
|    2 | ben  |
+------+------+

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
+------+---------+
1 row in set (0.01 sec)
  • 开启同步
从1:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from amoeba.test;
+------+-------+
| id   | name  |
+------+-------+
|    2 | ben   |
|    1 | alice |
|    4 | david |
+------+-------+
3 rows in set (0.00 sec)

从2:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from amoeba.test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
|    1 | alice   |
|    4 | david   |
+------+---------+
3 rows in set (0.00 sec)

主:
mysql> select * from test;
+------+-------+
| id   | name  |
+------+-------+
|    1 | alice |
|    4 | david |
+------+-------+
2 rows in set (0.00 sec)


客户端:
mysql> select * from test;
+------+-------+
| id   | name  |
+------+-------+
|    2 | ben   |
|    1 | alice |
|    4 | david |
+------+-------+
3 rows in set (0.00 sec)

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | chalice |
|    1 | alice   |
|    4 | david   |
+------+---------+
3 rows in set (0.01 sec)

开启同步后,主服务器上的数据会同步到各从服务器上中,但从服务器上的自己增加的数据不会同步,只有本地保存

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值