一、背景描述及其方案设计

1、业务背景描述

时间:2014.6.-2015.9

发布产品类型:互联网动态站点 商城

用户数量: 10000-12000(用户量猛增)

PV : 100000-500000(24小时访问次数总和)

QPS: 50-100*(每秒访问次数)

DAU: 2000(每日活跃⽤户数)

之前是单台MySQL提供服务,使用多台MySQL数据库服务器,降低单台压力,实现集群架构的稳定性和高可用性 数据的一致性 完整性 replication

通过业务比对和分析发现,随着用户活跃增多,读取数据的请求变多,故着重解决读取数据的压力

2、模拟运维设计方案

img

根据以上业务需求,在之前业务架构的基础上实现数据的读写分离

img

二、MySQL读写分离介绍

读写分离 读写操作,分发不同的服务器,读分发到对应的服务器(slave),写分发到对应的服务器(master)

1、读写分离的目的

读写分离 将读写业务分配到不同的服务器上,让服务器做特定的操作,不需要不断的切换工作模式,使工作效率提高 写主服务器,读从服务器

同时降低主服务器的压力,在正常业务下,也是读比较多的情况,写相对读少一些。

大约比例在写1/7读

读写分离:

①M-S下,读写必须分离,如果不分离,业务不可用出问题

②M-M 在此架构中,虽然可以随意读写操作,特定的操作交由特定的服务器操作,工作效率更高

2、读写分离的实现基础和原理

实现基础:通过主从复制机制实现数据的一致性 完整性

mysql的读写分离的基本原理是:

让master(主数据库)来响应事务性操作(create,update,delete,drop)

让slave(从数据库)来响应select非事务性操作

然后再采用主从复制来把master上的事务性操作同步到slave数据库中

没有主从复制,就无法实现业务上的读写分离

3、读写分离常见的实现方式

①业务代码的读写分离

需要在业务代码中,判断数据操作是读还是写,读连接从数据服务器操作,写连接主数据库服务器操作

以当前LNMP为例,就需要使用PHP代码实现读写分离

②中间件代理方式的读写分离

在业务代码中,数据库的操作,不直接连接数据库,而是先请求到中间件服务器(代理)

由代理服务器,判断是读操作去从数据服务器,写操作去主数据服务器

MySQL ProxyMySQL官方 测试版 不再维护
Atlas奇虎360 基于MySQL Proxyhttps://github.com/Qihoo360/Atlas/wiki/Atlas%E7%9A%84%E5%AE%89%E8%A3%85
DBProxy美团点评
Amoeba早期阿里巴巴
cobar阿里巴巴
MyCat基于阿里开源的Cober
kingsharedgo语言开发https://github.com/flike/kingshard

也就是如下图示架构

img

问:如何选择?

①业务上实现更加方便,成本低一下,如果使用的开发框架不支持分布式数据库的部署模式,

业务的SQL需要修改,改代码

②中间件代理服务器 更加适合管理更多的数据库服务器集群,查看到服务器是否可用,

不只可以实现读写分离,使用中间件实现分库、分表的操作

三、MySQL读写分离案列实现

0、搭建M-S复制

主 master 192.168.19.102

从 slave 192.168.19.106

主从复制的原理 :主服务器开启bin-log(记录了写操作) 从服务器获取到主服务器的bin-log 记录到relay-log中。从服务器在通过异步的线程方式,对于relay-log进行重放操作。

主服务器: bin-log

从服务器: relay-log

1、简单业务代码实现

在php普通脚本使用分布式数据库中,可以进行封装一个mysql操作类(OOP面向对象化编程)。建立两个或者多个数据库连接。通过判断操作类型,执行连接操作对应的数据库服务器。

示列代码:

class Mysql{

//封装连接属性

//单例模式 单例模式只存在一个实体对象,节省资源内存

// static 直接类名调用 常驻内存

//构造方法

public function __construct()

{

$master = mysql_connect(主数据库信息);

$slave = mysql_connect(从数据库信息);

}

//sql语句执行方法

public function query($sql)

{

//判断是读操作

if(strpos($sql,’select’) !== false){

mysql_query($sql,$slave);

}

else{

//判断是写操作

mysql_query($sql,$master);

}

}

}

①php连接数据库示例

img

img

②读写分离的基本代码原理

img

2、框架配置实现

①通过查看thinkphp5手册找到处理方案

支持分布式

img

支持读写分离

如果是双主架构,可以不开启读写分离

img

tp框架实现原理代码段源码

img

img

img

②操作实现

一定要先去确定主从数据库的数据一致(tp5shop),用户名称和密码可以进行登录使用

shell > vim /usr/local/nginx/html/tp5shop/application/database.php

img

img

测试可以down主库,看从库是否可以访问。thinkphp5中,如果slave宕机,master提供读服务。

3、MyCAT

3.1、介绍

img

原理流程图

img

准备一台服务器,作为数据库的中间件服务器,配置基本环境,网卡、FQDN

server01 web1 192.168.17.101

server02 master 192.168.17.102

server06 slave 192.168.17.106

server07 mycat 192.168.17.107

Mycat 数据库中间件

国内最活跃的、性能最好的开源数据库中间件!

官方网址:http://www.mycat.io/

https://github.com/MyCATApache/MyCAT-Server/

因为mycat是由java语言开发,必须使用java的允许环境进行启动和操作

3.2、jdk安装

java 静态编译的编程语言 代码编译成机器码 执行机器码输出结果。

编译jdk javac 编译java代码

运行 jre 编译好的机器码(可以执行文件) java

问:公司服务器部署的java环境是jdk还是jre?

答:jre java解析运行环境 一般情况编译过的可执行的java程序 ,jre就够用了。

jdk javac 编译的环境 如果服务器上传是源代码文件 就可以编译,之后再执行。

实际业务环境中,如果存在需要编译的情况,就选择jdk。

①下载安装jdk

https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

img

上传mycat和jdk到soft目录下

shell > tar xvf jdk-8u192-linux-x64.tar.gz
shell > mkdir /usr/local/java
shell > mv jdk1.8.0_192  /usr/local/java/

②配置环境变量

shell > vim /etc/profile

添加以下内容

img

使配置生效

shell > source /etc/profile

img

3.3、mycat安装和测试启动

①解压安装MyCAT

shell > tar xvf Mycat-server-1.6.5-release-20180122220033-linux.tar.gz -C /usr/local

实际解压到目录即可,无需安装

②查看软件目录

img

logs目录可以查看到错误日志

img

默认情况下mycat是可以启动的

shell > /usr/local/mycat/bin/mycat console
#确认mycat是否真的启动,查看它的端口 9066 8066
shell > netstat -lntp|grep 8066

1558949925341

如果mycat启动不能够看到成功字样

默认wrapper.conf不需要修改,但是如果启动卡在日志以下位置

img

因为系统不能够在规定时间内,启动mycat,可以设置启动等待时间延长

部署好mycat之后,先启动一下,是否能够正常启动。就不需要修改。

img

img

###3.4、配置读写分离

conf里的配置文件使用

img

server.xml对外提供的用户等的设置

schema.xml配置后端数据库服务器相关信息

①修改配置文件

默认server.xml可以不用修改

配置中间件的登录用户名称和用户密码 对应映射的虚拟库的名称

编辑

img

修改server.xml

配置mycat对外的使用用户信息

img

修改schema.xml

schema标签里配置name的server.xml里的虚拟数据库名称,dataNode 填写后面使用的dataNode名称

dataNode标签和dataHost指定配置使用

dataHost标签里配置writeHost和readHost(密码,地址,用户名称)

这个文件可以使用分享给大家的精简的,方便使用和操作,注意给予执行权限

1558951361758

注意修改第7行,真实数据库的名称

②启动mycat服务

shell > /usr/local/mycat/bin/mycat start

通过查看端口或者进程的方式,确认是否启动

img

Tip:如果配置之后,启动mycat,不能够启动

通过查看/usr/local/mycat/logs/wrapper.log

查看具体报错信息

img

以上操作完成MyCAT的读写分离配置

配置完成服务启动不了:

①master和slave没有对应用户给mycat操作 user password host

②配置文件语法错误 wrapper.log查看错误解决

3.5、mycat客户端和管理端

①测试查看代理客户端 8066

img

img

img

②测试查看管理监控端 9066

img

可以查看各数据库服务器的状态

img

mysql > show @@help;  //查看管理监控端的所有帮助命令
mysql > show @@heartbeat;  //查看服务器状态

img

3.6、关于balance属性和writeType属性

Tip:负载均衡属性简单说明

balance 属性

负载均衡类型,目前的取值有 3 种:

1、balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。 2、balance="1", 全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载均衡。 3、balance="2", 所有读操作都随机的在 writeHost、readhost 上分发。 4、balance="3", 所有读请求随机的分发到 writerHost 对应的 readhost 执行,writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有,1.3 没有。

writeType 属性

负载均衡类型,目前的取值有 3 种:

1、writeType="0", 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准. 2、writeType="1",所有写操作都随机的发送到配置的 writeHost,1.5 以后废弃不推荐

switchType 属性

-1 表示不自动切换

1 默认值,自动切换

2 基于 MySQL 主从同步的状态决定是否切换

3.7、业务代码配置

①确定服务都可用

server07的mycat可用

server02 sever06的mysql可用

②修改配置业务代码

使用mycat进行访问数据库,业务代码要和之前连接单服务器数据库操作一样

修改database.php配置

img

img

注意业务代码,不直接连接真实数据库服务器了,连接mycat代理服务器

①balance =2 读分发随机w和r

②两个writehost可以解决 w对应的master不可用时,slave可读

img