温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

MySQL主从复制+读写分离原理及配置实例

发布时间:2020-06-25 21:41:25 来源:网络 阅读:254 作者:张九冫 栏目:系统运维

一、MySQL主从复制原理:

MySQL的主从复制和MySQL的读写分离两者不分家,基于主从复制的架构才可实现数据的读写分离。

1、MySQL支持的复制类型:

(1)基于语句的复制。顾名思义就是在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用这种方式的复制,效率比较高。
(2)基于行的复制。把改变的内容复制过去,而不是把命令再从主服务器上执行一遍。
(3)混合类型的复制。默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。

以上三种复制类型,不需要人为干预,MySQL数据库会自动控制。

2、复制的工作过程,如下图所示:
MySQL主从复制+读写分离原理及配置实例
1、在每个事物更新数据完成之前,master在二进制日志记录这些改变。写入二进制日志完成后,master通知存储引擎提交事务。

2、slave将master的Binary log复制到其中继日志。首先slave开始一个工作线程——I/O线程,I/O线程在master上打开一个普通的连接,然后开始Binlog dump process(Binlog转储过程),Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。

3、SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O现场曾保持一致,中继日志通常存在系统的缓存中,所以中继日志的开销很小。

复制过程有一个很重要的限制,就是在slave上的复制是串行化的,master上时并行化的。说白了就是,有可能一些数据更新是多条SQL语句同时在master上进行的,但slave进行复制时,只能一条一条的执行SQL语句进行数据同步。

二、MySQL读写分离原理:

简单来说,就如下图一样,就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理数据写入、更新操作,而从数据库处理select查询操作。
MySQL主从复制+读写分离原理及配置实例
较为常见的MySQL读写分离分为两种:

1、基于程序代码内部实现:在代码中根据select、insert语句进行路由分类,这类方法目前在生产环境中应用最广泛。优点是性能较好,因为在程序代码中实现,不需要增加额外的设备作为硬件开支;缺点是需要开发人员来实现,我们运维无从下手。

2、基于中间代理实现:代理位于客户端和MySQL服务器之间,代理服务器接到客户端的请求后通过判断后转发到后端数据库。中间代理有两个代表性程序:MySQL-Proxy和amoeba(变形虫)。

二者区别如下:

MySQL-Proxy是MySQL开源项目,通过自带的lua脚本进行SQL判断,虽然是MySQL官方产品,但是MySQL官方并不建议将其应用到生产环境。

amoeba使用Java语言进行开发,阿里巴巴将其用于生产环境,它不支持事务和存储过程。

虽然通过程序代码实现MySQL读写分离是一个很好的选择,但并不是所有的应用都适合在程序代码中实现读写分离,一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码的改动就比较大。所以,大型复杂的应用一般都会考虑使用代理层来实现。
三、搭建MySQL主从复制及读写分离:
环境如下:
MySQL主从复制+读写分离原理及配置实例
.
准备工作:
1、五台 centos 7服务器,主从复制的三台需要安装MySQL。
2、相关软件包:
MySQL 软件包:https://pan.baidu.com/s/1u-gF81Un0ZE5QIIjGwH1Sg 提取码: 4i6x
amoeba软件包:https://pan.baidu.com/s/1sHcMTKAPX3A_gulhhaonyw 提取码: yzbx
3、保证网络流畅、互通、防火墙放行流量。
MySQL安装可参考:https://blog.51cto.com/14227204/2425596
搭建主从复制(建立时间同步环境):
配置主服务器:

[root@mysql /]# yum -y install ntp                        # 安装 ntp
[root@mysql /]# vim /etc/ntp.conf 
........................              // 省略部分内容               添加如下两行
server 127.127.1.0
fudge 127.127.1.0 stratum 8
[root@mysql /]# systemctl restart ntpd
[root@mysql /]# systemctl enable ntpd
[root@mysql /]# vim /etc/my.cnf 
...............................
server_id = 11                       # 修改,ID 要和从服务器区分开来
log_bin = master-bin             # 修改
log-slave-updates = true         # 添加
[root@mysql /]# systemctl restart mysqld                 # 重启服务使配置生效
[root@mysql /]# mysql -u root -p 
Enter password:               # 输入密码
mysql> grant replication slave on *.* to 'myslave'@'192.168.1.%' identified by '123123';
mysql> flush privileges;
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 |      552 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
# file列显示日志名,position 列显示偏移量,在后面配置从服务器时需要使用

配置从服务器:

[root@mysql /]# yum -y instal ntpdate             # 安装 ntpdate 工具
[root@mysql /]# ntpdate 192.168.1.10                  # 进行时间同步
23 Sep 18:06:22 ntpdate[6959]: no server suitable for synchronization found
[root@mysql /]# vim /etc/my.cnf 
................           
server_id = 22                  # ID 记得要和主服务器区分开来
relay-log = relay-log-bin             # 添加
relay-log-index = slave-relay-bin.index            # 添加
[root@mysql /]# systemctl restart mysqld           # 重启使配置生效
[root@mysql /]# mysql -u root -p 
Enter password:                # 登录 mysql 配置同步
mysql> change master to                master_host='192.168.1.10',master_user='myslave',master_password='123123',master_Log_file='master-bin.000001',master_log_pos=552;
# 按主服务器的结果更改上面命令中的mater_log_file和mater_log_pos参数
mysql> start slave;             # 启动同步
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.10
                  Master_User: myslave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 552
               Relay_Log_File: relay-log-bin.000002
                Relay_Log_Pos: 284
        Relay_Master_Log_File: master-bin.000001
             Slave_IO_Running: Yes                       # 确保这两行为yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 

在另一台从服务器上进行相同的配置,同步至主服务器,这里我就不多做解释了
搭建读写分离:
在主机 Amoeba 上安装Java环境:

[root@localhost media]# ls
amoeba-mysql-binary-2.2.0.tar.gz  jdk-6u14-linux-x64.bin
[root@localhost media]# cp * /usr/src/
[root@localhost media]# cd /usr/src/
[root@localhost src]# chmod +x jdk-6u14-linux-x64.bin 
[root@localhost src]# ./jdk-6u14-linux-x64.bin             # 执行之后一直空格键,出现yes后输入yes,回车
..................
Do you agree to the above license terms? [yes or no]
yes
Press Enter to continue.....               # 出现此行回车
Done.                               # 说明成功了
[root@localhost src]# ls                     # 此目录下会多出一个目录
amoeba-mysql-binary-2.2.0.tar.gz  debug  jdk1.6.0_14  jdk-6u14-linux-x64.bin  kernels
[root@localhost src]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@localhost src]# 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@localhost src]# source /etc/profile                # 执行s使配置生效
[root@localhost /]# 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)

master、slave1、slave2 中开放权限给 amoeba 访问:

mysql> grant all on *.* to test@'192.168.1.%' identified by '123.com';

安装并配置 Amoeba 软件:

[root@localhost /]# mkdir /usr/local/amoeba
[root@localhost /]# cd /usr/src/
[root@localhost src]# tar zxf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@localhost /]# chmod -R 755 /usr/local/amoeba/            # 给amoeba目录权限
[root@localhost /]# /usr/local/amoeba/bin/amoeba
amoeba start|stop                       #  显示此内容说明安装成功了
[root@localhost /]# vim /usr/local/amoeba/conf/amoeba.xml           # 编辑配置文件
................................
<property name="authenticator">
                                <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">

                                        <property name="user">amoeba</property>         # 修改客户端登录的用户和密码(搜索user可到)

                                        <property name="password">123456</property>

                                        <property name="filter">
                                                <bean class="com.meidusa.amoeba.server.IPAccessController">
.........................................
<property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
                <property name="LRUMapSize">1500</property>
                <property name="defaultPool">master</property>   # 修改为master

                <property name="writePool">master</property>     # 修改为master
                <property name="readPool">slaves</property>         # 修改为slaves
               # 以上两行被注释过,需要将注释去掉
                <property name="needParse">true</property>
        </queryRouter>

编辑dbServers/xml文件

[root@localhost /]# vim /usr/local/amoeba/conf/dbServers.xml 
............................
<!-- mysql user -->
                        <property name="user">test</property>             # 修改为test

                        <property name="password">123.com</property>    # 设置密码,将注释去掉
                </factoryConfig>
..............................
<dbServer name="master"  parent="abstractServer">            # 修改名称
                <factoryConfig>
                        <!-- mysql ip -->
                        <property name="ipAddress">192.168.1.10</property>      # 设置主机IP
                </factoryConfig>
        </dbServer>

        <dbServer name="slave1"  parent="abstractServer">
                <factoryConfig>
                        <!-- mysql ip -->
                        <property name="ipAddress">192.168.1.20</property>
                </factoryConfig>
        </dbServer>

        <dbServer name="slave2"  parent="abstractServer">
                <factoryConfig>
                        <!-- mysql ip -->
                        <property name="ipAddress">192.168.1.30</property>
                </factoryConfig>
        </dbServer>
<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@localhost /]# /usr/local/amoeba/bin/amoeba start&              # 启动服务

接下来开始测试:
在client主机上安装mysql:

[root@localhost /]# yum -y install mysql
[root@localhost /]# mysql -u amoeba -p123456 -h 192.168.1.40 -P8066      # 登录访问
# 在master主机test库中创建一个表,同步到各从服务器上
mysql> create table zang (id int(10),name varchar(10));
# 然后关掉各从服务器上的slave功能,并插入区别语句
mysql> insert into zang values('3','wangwu');              # 主服务器上
mysql> stop slave;             # 关闭slave功能
mysql> insert into zang values('1','zhangsan');        # 从服务器一
mysql> insert into zang values('2','lisi');          # 从服务器二

测试读操作:

MySQL [test]> select * from zang;                  # 第一次查询
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
+------+----------+
1 row in set (0.05 sec)

MySQL [test]> select * from zang;                # 第二次查询
+------+------+
| id   | name |
+------+------+
|    2 | lisi |
+------+------+
1 row in set (0.00 sec)

MySQL [test]> select * from zang;            # 第三次查询
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
+------+----------+
1 row in set (0.00 sec)

测试写操作:
client 主机上插入一条数据:

MySQL [test]> insert into zang values('4','zholiu');   
Query OK, 1 row affected (0.01 sec)
MySQL [test]> select * from zang;               # 在client上查不到
+------+------+
| id   | name |
+------+------+
|    2 | lisi |
+------+------+
mysql> select * from zang;                             # 只在master主服务上查到了,从服务器因为关闭了salve功能所以同步不到
+------+----------+
| id   | name     |
+------+----------+
|    3 | wangwu   |
|    4 | zholiu   |
+------+----------+
3 rows in set (0.01 sec)

这样,就实现了 MySQL 的读写分离,所有写操作全部在 master主服务器上,用来避免数据的不同步,所有读操作都分摊给了 从服务器,用来分担服务器的压力。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI