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数据库的主从复制和读写分离!的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 数据库——主从复制与读写分离

MySQL数据库的主从复制和读写分离!

MySQL数据库的主从复制和读写分离!

部署MySQL主从复制与读写分离

MySQL 数据库MySQL 主从复制和 Sharding-JDBC 实现读写分离

MySQL 数据库MySQL 主从复制和 Sharding-JDBC 实现读写分离