MySQL数据库的主从复制和读写分离!
Posted handsomeboy-东
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL数据库的主从复制和读写分离!相关的知识,希望对你有一定的参考价值。
这里写目录标题
一、主从复制
在实际生产环境中,如果对数据库的读写都在同一个数据库服务器中操作,无论是在安全性。高可用性,还是高并发等各个方面都是完成不能满足实际需求的,因此需要通过主从复制的方式来同步数据,再通过读写分离和高可用来提升数据库的并发负载能力
1.1mysql支持的复制类型
- 基于语句的复制(statement,MySQL默认复制类型),在主服务器执行SQL语句在从服务器执行同样的语句
- 基于行的复制,把改变的内容复制过去,而不是把命令在从服务器上执行一遍
- 混合类型复制,默认会采用基于语句的复制,当发现基于语句复制无法精确复制时,就会采用基于行的复制
1.2MySQL主从复制核心原理
- master服务器上的dump线程会监听二进制日志的更新,如果有更新内容就会提示slave服务器的I/O线程
- slave服务器的I/O线程会向master服务器申请同步二进制日志的更新
- master服务器的dump线程就会把同步的二进制日志的更新内容给予slave服务器,slave服务器的I/O线程就会将同步内容写入自己的中继日志
- slave服务器的sql线程会把中继日志中的更新语句执行到数据库中,以达到和master服务器趋近一致
搭建MySQL的主从复制
设备准备:一台MySQL-master,两台MySQL-slave
- 关闭所有服务器的防火墙及安全防护
systemctl stop firewalld.service
setenforce 0
- 设置主从服务器的时间同步,master服务器配置
[root@master ~]# yum -y install ntp #下载ntp时间同步服务器
[root@master ~]# vim /etc/ntp.conf #配置ntp,在最后添加如下内容
……………………
server 127.127.1.0 #设置本机为时间同步源,是向其他服务器提供时间同步源的意思,不可设置为0级
fudge 127.127.1.0 stratum 10 #设置本机的时间层级为10级,
[root@master ~]# systemctl restart ntpd #重启服务
- 安装ntp软件,进行与阿里云的时间同步,master服务器和slave服务器都要执行,master服务器上可以设置周期性任务
[root@master ~]# ntpdate ntp.aliyun.com
18 Jul 16:25:09 ntpdate[65603]: the NTP socket is in use, exiting
[root@master ~]# crontab -e #设置没10分钟进行时间同步
*/10 * * * * /usr/sbin/utpdate ntp.aliyun.com
[root@master ~]# crontab -l #查看周期性任务
*/10 * * * * /usr/sbin/utpdate ntp.aliyun.com
[root@slave2 mysql]# ntpdate ntp.aliyun.com
18 Jul 16:25:38 ntpdate[96615]: adjust time server 203.107.6.88 offset -0.001923 sec
[root@slave1 opt]# ntpdate ntp.aliyun.com
18 Jul 16:26:13 ntpdate[87282]: adjust time server 203.107.6.88 offset 0.003526 sec
- 启动master服务器二进制日志,登录master服务器给slave服务器授权
[root@master mysql]# vim /etc/my.cnf
[mysqld] #在mysqld下添加二进制开启内容
server-id = 11
log-bin=mysql-bin
log-slave-updates=true
[root@master mysql]# systemctl restart mysqld.service #重启服务
Warning: mysqld.service changed on disk. Run 'systemctl daemon-reload' to reload units.
[root@master mysql]# mysql -uroot -p
mysql> grant replication slave on *.* to 'myslave'@'192.168.118.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 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 |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
- 修改从服务器配置文件,登录服务器配置同步
[root@slave1 ~]# vim /etc/my.cnf #给slave1开启中继日志
[mysqld]
server-id = 22
relay-log=relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.insex #定义中继日志的位置和名称
[root@slave1 ~]# systemctl restart mysqld.service
[root@slave1 ~]# mysql -uroot -p
mysql> change master to master_host='192.168.118.200',master_user='myslave',master_password='123456',master_log_file='mysql-bin.000005',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave; #开启同步
Query OK, 0 rows affected (0.00 sec)
[root@slave2 ~]# vim /etc/my.cnf #给slave2开启中继日志
[mysqld]
server-id = 23
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.insex
[root@slave1 ~]# systemctl restart mysqld.service
[root@slave2 ~]# mysql -uroot -p
mysql> change master to master_host='192.168.118.200',master_user='myslave',master_password='123456',master_log_file='mysql-bin.000005',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
- 查看slave状态,确保I/O和SQL两个值为yes
mysql> show slave status \\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.118.200
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 154
Relay_Log_File: relay-log-bin.000009
Relay_Log_Pos: 367
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: Yes #查看是否为yes,表示I/O同步是否成功
Slave_SQL_Running: Yes #查看是否为yes,表示SQL同步是否成功
Last_Errno: 0
Last_Error: #同步失败时返回的错误信息
Skip_Counter: 0
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: 11
Master_UUID: 2757c7a0-e7ea-11eb-b339-000c29b633c1
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 more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: #同步失败时间戳
1 row in set (0.00 sec)
- 在主服务器上创建新库whd,在主从服务器上分别验证是否都有库whd
master:
mysql> create database whd;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| whd |
+--------------------+
6 rows in set (0.00 sec)
slave:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| whd |
+--------------------+
5 rows in set (0.01 sec)
读写分离
基于主从复制基础,只在主服务器上写,只在从服务器上读,主数据库处理事务性查询,从数据库处理select查询,可以解决数据库读写压力不均衡
读写分离方法
- 基于程序代码内部实现:在代码中根据select、insert进行路由分类,优点性能好,不需要增加额外的设备,缺点时需要开发人员来实现
- 基于中间代理服务实现:MySQL-Proxy、Amoeba(变形虫),可实现读写分离和隐藏数据库ip
需要读写分离的原因及适用场景
- 因为数据库的写入相比于读更为耗时,同时读写会影响查询的效率
- 如果程序使用数据库较多,而更新少,查询(select)多的情况下可以使用
搭建读写分离
- 在Amoeba上部署java环境
[root@amoeba opt]# ls
amoeba-mysql-binary-2.2.0.tar.gz jdk-6u14-linux-x64.bin rh
[root@amoeba opt]# cp jdk-6u14-linux-x64.bin /usr/local/
[root@amoeba opt]# chmod +x /usr/local/jdk-6u14-linux-x64.bin
[root@amoeba opt]# /usr/local/jdk-6u14-linux-x64.bin #出现more直接按空格到最后输入yes,然后一组回车即可
[root@amoeba opt]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@amoeba opt]# 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 opt]# source /etc/profile
[root@amoeba opt]# java -version
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)
- 安装并配置amoba软件
[root@amoeba opt]# tar zxf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba
[root@amoeba opt]# chmod -R 755 /usr/local/amoeba/
[root@amoeba opt]# /usr/local/amoeba/bin/amoeba
amoeba start|stop #显示此内容表示安装成功
- master、slave1、slave2服务器配置权限给Amoeba
mysql> grant all on *.* to 'amoeba'@'192.168.118.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
- List item
[root@amoeba opt]# cd /usr/local/amoeba/conf
[root@amoeba conf]# ls
access_list.conf amoeba.xml dbServers.xml functionMap.xml log4j.xml ruleFunctionMap.xml
amoeba.dtd dbserver.dtd function.dtd log4j.dtd rule.dtd rule.xml
[root@amoeba conf]# vim amoeba.xml
[root@amoeba conf]# vim dbServers.xml
- 开启amoeba
[root@amoeba amoeba]# bin/amoeba start& #时间较长,耐心等待
amoeba start|stop
[root@amoeba amoeba]# netstat -antp | grep 8066
tcp6 0 0 :::8066 :::* LISTEN 82238/java
- 在client段上通过amoeba代理访问MySQL
[root@client ~]# yum -y install mariadb #下载MySQL轻量级版本
[root@client ~]# mysql -uamoeba -p -h 192.168.118.88 -P8066 #远程登录amoeba服务器
##创建一个表
MySQL [(none)]> create database xuyi;
Query OK, 1 row affected (0.01 sec)
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| whd |
| xuyi |
+--------------------+
6 rows in set (0.00 sec)
- 在master服务器上查看是否有表xuyi
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| whd |
| xuyi |
+--------------------+
6 rows in set (0.00 sec)
- 测试读写分离
1. 在主服务器xuyi库中添加表,同步在个服务器上,然后关闭从服务器,再在master上text表中添加内容
mysql> use xuyi;
Database changed
mysql> create table text(id int,name varchar(20));
Query OK, 0 rows affected (0.02 sec)
mysql> select * from text;
+------+------+
| id | name |
+------+------+
+------+------+
1 row in set (0.01 sec)
2. 关闭从服务器主从同步
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
3. 分别在各个服务器的text表中添加内容
master
mysql> insert into test values(1,'aa');
Query OK, 1 row affected (0.01 sec)
slave1:
mysql> insert into text values(3,'cc');
Query OK, 1 row affected (0.00 sec)
slave2:
mysql> insert into text values(2,'bb');
Query OK, 1 row affected (0.00 sec)
client:
MySQL [xuyi]> insert into text values(4,'dd');
Query OK, 1 row affected (0.01 sec)
4. 在client端查询text表3次,会发现无法看到master和client的内容,slave服务器读的过程以轮询方式显示
MySQL [xuyi]> select * from text;
+------+------+
| id | name |
+------+------+
| 3 | cc |
+------+------+
2 rows in set (0.01 sec)
MySQL [xuyi]> select * from text;
+------+------+
| id | name |
+------+------+
| 2 | bb |
+------+------+
2 rows in set (0.00 sec)
MySQL [xuyi]> select * from text;
+------+------+
| id | name |
+------+------+
| 3 | cc |
+------+------+
2 rows in set (0.00 sec)
5. 在master服务器上查看表可以显示master服务器和client服务器的内容,说明写的操作在master上,所有的读操作都给了slave,实现了读写分离
mysql> select * from text;
+------+------+
| id | name |
+------+------+
| 1 | aa |
| 4 | dd |
+------+------+
2 rows in set (0.00 sec)
以上是关于MySQL数据库的主从复制和读写分离!的主要内容,如果未能解决你的问题,请参考以下文章