一.前言
在企业应用中,成熟的业务通常数据量都比较大
单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求
配置多台主从数据库服务器以实现读写分离。
二.主从复制原理
1.mysql的复制类型
(1)STATEMENT(基于SQL语句):
每一条涉及到被修改的sql 都会记录在binlog中
缺点:日志量过大,如sleep()函数,last_insert_id()>,以及user-defined fuctions(udf)、主从复制等架构记录日志时会出现问题
(2)ROW(基于行)
只记录变动的记录,不记录sql的上下文环境
缺点:如果遇到update…set…where true 那么binlog的数据量会越来越大
(3)MIXED 推荐使用
一般的语句使用statement,函数使用ROW方式存储
2.主从复制的过程详解
(1)核心点
2个日志,3个线程
maser里面是二进制日志bin_log,dump线程
slave里面是中继日志relay_log。i/o线程和sql线程
(2)详细复制过程
① master上的dump线程会监听二进制日志bin_log的更新内容’,如果有更新会通知slave的i/o线程
② slave上的i/o线程会申请更新同步二进制的更新内容
③ dump线程会把日志的更新同步内容给slave,slave的i/o线程会把更新日志内容写入自己的中继日志
④ slave的sql线程会把日志中的更新语句同步执行到数据库内,达到会master数据库内容趋近一致
三.主从复制的策略
1.全同步
master请求服务时,等待slave全部同步之后才会回应client端
2.半同步
master请求服务时,只要任意一个slave同步
3.异步
master请求服务时,只要master同步即回应请求,不管slave的状态;默认的状态
因为主从复制的默认策略是异步,导致的结果就是主从二进制日志和中继日志的保存内存会越来越大
四.搭建主从复制
1.搭建准备
3台linux,centos7版本,一台做mysql主服务器,2台做mysql从服务器。关闭防火墙及核心防护
master:192.168.206.88
slave1:192.168.206.188
slave2:192.168.206.177
2.安装mysql服务器
3台主机同时手工编译安装mysql数据库,这里安装的都是5.7版本。
3.主从服务器时间同步
(1)master配置
① 安装ntp,修改配置文件
[root@master ~]# yum -y install ntp
[root@master ~]# ntpdate ntp.aliyun.com
20 Jul 15:08:10 ntpdate[1651]: adjust time server 203.107.6.88 offset 0.003463 sec
[root@master ~]# vim /etc/ntp.conf
server 127.127.1.0 #设置本机为时间同步源
fudge 127.127.1.0 stratum 10 #设置本机的时间层级为10级,是向其他服务器提供时间同步源的意思,不可设置为0级
[root@master ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@master ~]# crontab -l
*/10 * * * * /usr/sbin/ntpdate 192.168.206.88
② 重启ntp
[root@master ~]# systemctl start ntpd
(2)2台slave配置
[root@slave1 ~]# yum -y install ntp
[root@slave1 ~]# ntpdate ntp.aliyun.com
20 Jul 15:08:10 ntpdate[1651]: adjust time server 203.107.6.88 offset 0.003463 sec
[root@slave2 ~]# yum -y install ntp
[root@slave2 ~]# ntpdate ntp.aliyun.com
20 Jul 15:08:10 ntpdate[1651]: adjust time server 203.107.6.88 offset 0.003463 sec
[root@slave1 ~]# crontab -e
crontab: installing new crontab
[root@slave1 ~]# crontab -l
*/10 * * * * /usr/sbin/ntpdate 192.168.206.88
[root@slave1 ~]# systemctl start ntpd
[root@slave1 ~]# ntpdate 192.168.206.88
20 Jul 17:28:24,从ntpdate[16023]: the NTP socket is in use, exiting
[root@slave2 ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@slave2 ~]# crontab -l
*/10 * * * * /usr/sbin/ntpdate 192.168.206.88
[root@slave2 ~]# systemctl start ntpd
[root@slave2 ~]# ntpdate 192.168.206.88
20 Jul 17:28:47 ntpdate[44686]: the NTP socket is in use, exiting
4.主从分别开启各自日志文件
(1)master主要配置
启动二进制文件,从服务器
[root@master ~]# vim /etc/my.cnf
server-id = 11
log_bin=master-bin
log_slave_updates=true
[root@master ~]# systemctl restart mysqld
(2)slave1配置
[root@slave1 ~]# vim /etc/my.cnf #给slave1开启中继日志
[mysqld]
server-id = 22
relay-log=relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index #定义中继日志的位置和名称
[root@slave1 ~]# systemctl restart mysqld
(3)slave2配置
[root@slave2 ~]# vim /etc/my.cnf #给slave2开启中继日志
[mysqld]
server-id = 33
relay-log=relay-log-bin #从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index #定义中继日志的位置和名称
[root@slave2 ~]# systemctl restart mysqld
5.配置规则
(1)master设置
给从服务器提权grant;用于主从对接
[root@master ~]# mysql -uroot -p #登录数据库
mysql> grant replication slave on *.* to 'myslave'@'192.168.206.%' 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 |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000003 | 1053 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> quit
Bye
[root@master ~]# cd /usr/local/mysql/data
[root@master data]# ls
auto.cnf ib_logfile0 master-bin.000001 master-bin.index sys
ib_buffer_pool ib_logfile1 master-bin.000002 mysql
ibdata1 ibtmp1 master-bin.000003 performance_schema
(2)slave1设置
[root@slave1 ~]# mysql -uroot -pqwer1234 #登录数据库
mysql> change master to master_host='192.168.206.88',master_user='myslave',master_password='123456',master_log_file='master-bin.000003',master_log_pos=1053; #给从服务器提权,允许使用slave的身份复制msater所有数据库的所有表,并制定密码为123456
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G #查看从服务器状态
(3)slave2配置
[root@slave2 ~]# mysql -uroot -pqwer1234 #登录数据库
mysql> change master to master_host='192.168.206.88',master_user='myslave',master_password='123456',master_log_file='master-bin.000003',master_log_pos=1053; #给从服务器提权,允许使用slave的身份复制msater所有数据库的所有表,并制定密码为123456
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G #查看从服务器状态
6.测试是否同步
(1)master创建一个库
(2)slave1上查看是否同步
(2)slave2上查看是否同步
五.读写分离
1.原理
读写分离就是只在主服务器上写,只在从服务器上读
基本的原理是让主数据库处理事务性查询,
而从数据库处理select查询。数据库复制被用来把主数据库上事务性查询导致的变更同步到集群中的从数据库
2.为何要读写分离
因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。
但是数据库的“读”(读10000条数据可能只要5秒钟)
所以读写分离,解决的是,数据库的写入,影响了查询的效率
3.读写分离的好处
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。
利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能
4.实现方式方案
常见的MySQL读写分离分为以下两种:
(1)基于程序代码内部实现
在代码中根据select、insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;
缺点是需要开发人员来实现,运维人员无从下手。
但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。
(2)基于中间代理层实现
代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库;
有以下代表性程序:
① MySQL-Proxy:MySQL-Proxy 为MySQL开源项目,通过其自带的lua脚本(脚本语言)进 行SQL判断。
② Atlas:由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它是在mysql-proxy0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。360内部使用Atlas运行的mysql业务,每天承载的读写请求数达几十亿条。支持事物以及存储过程。
③ Amoeba:由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。
5.Amoeba介绍
Amoeba: 是一 个以MySQL为底层数据存储,并对应提供MySQL协议接口的proxy(代理),外号变形虫
读取请求发送给从服务器是,采用轮询调度算法
amoeba使用的java语言编写,配置文件为xml
amoeba主要负责对外的一个代理IP
访问这个IP时,发送的请求为“写"请求,则会转给主服务器
当发送的请求为“读"时,会通过调度转发给从服务器,使用轮询算法,轮流分配给两台从服务器
amoeba可以视为调度器,如果主服务器挂掉(单点故障),则会有MHA解决这个问题
六.搭建读写分离
读写分离的搭建是建立在主从复制的基础上的。
1.实验准备
5台linux,1台mysql数据库master,2台mysql数据库slave,1台amoeba,1台client端
mysql-master:192.168.206.88
mysql-slave1:192.168.206.188
mysql-slave2:192.168.206.177
amoeba:192.168.206.99
client端:192.168.206.
3台mysql做主从复制
2.安装ameoba
安装java环境,安装jdk(因为amoeba是基于jdk1.5开发的,所以官方推荐使用jkd1.5/jdk1.6,高版本不建议使用)
[root@ameoba ~]# cd /opt
[root@ameoba opt]# ls
anaconda-ks.cfg rh
[root@ameoba opt]# ls #本地上传执行文件和安装包
amoeba-mysql-binary-2.2.0.tar.gz anaconda-ks.cfg jdk-6u14-linux-x64.bin rh
[root@ameoba opt]# cp jdk-6u14-linux-x64.bin /usr/local/
[root@ameoba opt]# cd /usr/local/
[root@ameoba local]# chmod +x jdk-6u14-linux-x64.bin #给执行权限
[root@ameoba local]# ./jdk-6u14-linux-x64.bin #执行
#yes 回车
[root@ameoba local]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@ameoba local]# vim /etc/profile #添加变量
[root@ameoba local]# source /etc/profile #刷新生效
[root@ameoba local]# 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)
[root@ameoba local]# mkdir /usr/local/amoeba #创建目录
[root@ameoba local]# tar zxvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
#解压到创建的目录
[root@ameoba local]# chmod -R 755 /usr/local/amoeba/ #递归给权限
[root@ameoba local]# /usr/local/amoeba/bin/amoeba #服务启动
amoeba start|stop
3.配置amoeba读写分离,2个slave读负载均衡,给数据库权限
在master、slave1、slave2的mysql上开放权限给amoeba
mysql> grant all on *.* to test @'192.168.206.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
4.再配置amoeba
(1)修改主配置文件
[root@ameoba local]# cd /usr/local/amoeba/conf/
[root@ameoba conf]# ls
access_list.conf dbserver.dtd functionMap.xml rule.dtd
amoeba.dtd dbServers.xml log4j.dtd ruleFunctionMap.xml
amoeba.xml function.dtd log4j.xml rule.xml
[root@ameoba conf]# cp amoeba.xml amoeba.xml.bak
[root@ameoba conf]# vim amoeba.xml
(2)修改数据库配置文件
[root@ameoba conf]# cp dbServers.xml dbServers.xml.bak
[root@ameoba conf]# vim dbServers.xml
紧接复制52-57行,粘贴,添加第二台服务器名
这时复制会话另开一个页面查看一下配置文件 (因为amoeba需要一直开启才能查询到端口)
5.开启amoeba
[root@ameoba conf]# /usr/local/amoeba/bin/amoeba start
log4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml
2021-07-21 03:51:56,755 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.2.0
log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf
2021-07-21 03:52:07,034 INFO net.ServerableConnectionManager - Amoeba for Mysql listening on 0.0.0.0/0.0.0.0:8066.
2021-07-21 03:52:07,038 INFO net.ServerableConnectionManager - Amoeba Monitor Server listening on /127.0.0.1:6475.
[root@ameoba conf]# netstat -antp | grep java
tcp6 0 0 127.0.0.1:6475 :::* LISTEN 35067/java
tcp6 0 0 :::8066 :::* LISTEN 35067/java
tcp6 0 0 192.168.206.99:39278 192.168.206.88:3306 ESTABLISHED 35067/java
tcp6 0 0 192.168.206.99:39282 192.168.206.88:3306 ESTABLISHED 35067/java
tcp6 0 0 192.168.206.99:46678 192.168.206.177:3306 ESTABLISHED 35067/java
[root@ameoba conf]# netstat -antp | grep 8066
tcp6 0 0 :::8066 :::* LISTEN 35067/java
6.测试验证
(1)验证amoeba能否关联后端mysql
client端远程访问amoeba的地址,并进入数据库创建新的数据库,验证master和slaves是否同步
client端进入数据库创建表gg,发现master+slave1+slave2已同步创建数据表gg
① 客户端远程登录创建表gg
[root@client ~]# mysql -uamoeba -p123123 -h 192.168.206.99 -P 8066
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1342544436
Server version: 5.1.45-mysql-amoeba-proxy-2.2.0
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database zzz;
Query OK, 1 row affected (0.02 sec)
mysql> use zzz;
No connection. Trying to reconnect...
Connection id: 1342544436
Current database: *** NONE ***
Database changed
mysql> create table gg(id int);
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+---------------+
| Tables_in_zzz |
+---------------+
| gg |
+---------------+
1 row in set (0.00 sec)
② master查看
③ slave查看
(2)验证写
测试mysql的读写分离,2台从服务器关闭主从同步,在客户端数据库的数据表内插入数据验证amoeba读写分离
① 从服务器关闭主从功能
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
②client写入表数据
mysql> show tables;
+---------------+
| Tables_in_zzz |
+---------------+
| gg |
+---------------+
1 row in set (0.00 sec)
mysql> insert into gg values(1);
Query OK, 1 row affected (0.01 sec)
③master查看
master处理写的任务,可以查询到数据表aa
④ slave查看
从服务器处理读的任务,查询看不到数据
(3)验证读
在从服务器上更改表数据,使用客户端验证从服务器读,和轮询的方式读
① slaves1插入一条数据
mysql> insert into gg values(2);
Query OK, 1 row affected (0.00 sec)
②slave2插入一条数据
mysql> insert into gg values(3);
Query OK, 1 row affected (0.00 sec)
③ client端查询表gg的内容
mysql> select * from gg;
+------+
| id |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
mysql> select * from gg;
+------+
| id |
+------+
| 3 |
+------+
1 row in set (0.01 sec)
mysql> select * from gg;
+------+
| id |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
mysql> select * from gg;
+------+
| id |
+------+
| 3 |
+------+
1 row in set (0.01 sec)