文章 78
评论 0
浏览 8357
9-MySQL集群架构-读写分离

9-MySQL集群架构-读写分离

6.2 MySQL 中间件代理服务器

6.2.1 关系型数据库和 NoSQL 数据库

数据库主要分为两大类:关系型数据库与 NoSQL 数据库。

关系型数据库,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库中的数据。主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。

NoSQL 数据库,全称为 Not Only SQL,意思就是适用关系型数据库的时候就使用关系型数据库,不适用的时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键值存储(memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库(MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase),每种 NoSQL 都有其特有的使用场景及优点。

Oracle,mysql 等传统的关系数据库非常成熟并且已大规模商用,为什么还要用 NoSQL 数据库呢?主要是由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺陷,即单机(单库)性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足日益增长的海量数据存储及其性能要求,所以才会出现了各种不同的 NoSQL 产品,NoSQL 根本性的优势在于在云计算时代,简单、易于大规模分布式扩展,并且读写性能非常高

RDBMS和NOSQL的特点及优缺点:

clipboard.png

6.2.2 数据切分

简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机) 上面,以达到分散单台设备负载的效果。

数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

一种是按照不同的表(或者 Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据 表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小, 业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。 根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。

水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据库中, 对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。

6.2.2.1 垂直切分

clipboard.png
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:

clipboard.png

系统被切分成了,用户,订单交易,支付几个模块。 一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。

但是往往系统之有些表难以做到完全独立,存在着跨库 join 的情况,对于这类表,就需要去做平衡,是数据库让步业务,共用一个数据源,还是分成多个库,业务之间通过接口来做调用。在系统初期,数据量比较 少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到了一定的规模,负载很大的情况,就需要必须去做分割。

一般来讲业务存在着复杂 join 的场景是难以切分的,往往业务独立的易于切分。如何切分,切分到何种程度是考验技术架构的一个难题。

垂直切分的优缺点

优点:

  • 拆分后业务清晰,拆分规则明确
  • 系统之间整合或扩展容易
  • 数据维护简单

缺点:

  • 部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度
  • 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高
  • 事务处理复杂

由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。

6.2.2.2 水平切分

clipboard.png

对应shard中查询相关数据

clipboard.png

相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分 到一个数据库,而另外的某些行又切分到其他的数据库中,如图:

clipboard.png

拆分数据就需要定义分片规则。关系型数据库是行列的二维模型,拆分的第一原则是找到拆分维度。比如: 从会员的角度来分析,商户订单交易类系统中查询会员某天某月某个订单,那么就需要按照会员结合日期来拆分, 不同的数据按照会员 ID 做分组,这样所有的数据查询 join 都会在单库内解决;如果从商户的角度来讲,要查询某个商家某天所有的订单数,就需要按照商户 ID 做拆分;但是如果系统既想按会员拆分,又想按商家数据,则会有 一定的困难。如何找到合适的分片规则需要综合考虑衡量。

几种典型的分片规则包括:

  • 按照用户 ID 求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中
  • 按照日期,将不同月甚至日的数据分散到不同的库中
  • 按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中

如图,切分原则都是根据业务找到适合的切分规则分散到不同的库,下面用用户 ID 求模举例:

clipboard.png

既然数据做了拆分有优点也就优缺点。

优点:

  • 拆分规则抽象好,join 操作基本可以数据库做
  • 不存在单库大数据,高并发的性能瓶颈
  • 应用端改造较少
  • 提高了系统的稳定性跟负载能力

缺点:

  • 拆分规则难以抽象
  • 分片事务一致性难以解决
  • 数据多次扩展难度跟维护量极大
  • 跨库 join 性能较差

前面讲了垂直切分跟水平切分的不同跟优缺点,会发现每种切分方式都有缺点,但共同特点缺点有:

  • 引入分布式事务的问题
  • 跨节点 Join 的问题
  • 跨节点合并排序分页问题
  • 多数据源管理问题

6.2.3 MySQL 中间件各种应用

clipboard.png

6.2.4 Mycat

6.2.4.1 Mycat 介绍

在整个IT系统架构中,数据库是非常重要,通常又是访问压力较大的一个服务,除了在程序开发的本身做优化,如:SQL语句优化、代码优化,数据库的处理本身优化也是非常重要的。主从、热备、分表分库等都是系统发展迟早会遇到的技术问题问题。Mycat是一个广受好评的数据库中间件,已经在很多产品上进行使用了。

在整个IT系统架构中,数据库是非常重要,通常又是访问压力较大的一个服务,除了在程序开发的本身做优化,如:SQL语句优化、代码优化,数据库的处理本身优化也是非常重要的。主从、热备、分表分库等都是系统发展迟早会遇到的技术问题问题。Mycat是一个广受好评的数据库中间件,已经在很多产品上进行使用了。

Mycat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQLServer、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度

Mycat 可以简单概括为

  • 一个彻底开源的,面向企业应用开发的大数据库集群
  • 支持事务、ACID、可以替代MySQL的加强版数据库
  • 一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群
  • 一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server
  • 结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
  • 一个新颖的数据库中间件产品

Mycat 官网:http://www.mycat.org.cn/

Mycat 关键特性

  • 支持SQL92标准
  • 遵守MySQL 原生协议,跨语言,跨平台,跨数据库的通用中间件代理
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
  • 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
  • 基于Nio实现,有效管理线程,高并发问题
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页
  • 支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join
  • 支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
  • 支持多租户方案
  • 支持分布式事务(弱xa)
  • 支持全局序列号,解决分布式下的主键生成问题
  • 分片规则丰富,插件化开发,易于扩展
  • 强大的web,命令行监控
  • 支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉
  • 支持密码加密
  • 支持服务降级
  • 支持IP白名单
  • 支持SQL黑名单、sql注入攻击拦截
  • 支持分表(1.6)
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)

为什么要用MyCat

这里要先搞清楚Mycat和MySQL的区别(Mycat的核心作用)。我们可以把上层看作是对下层的抽象,例如操作系统是对各类计算机硬件的抽象。那么我们什么时候需要抽象?假如只有一种硬件的时候,我们需要开发一个操作系统吗?再比如一个项目只需要一个人完成的时候不需要leader,但是当需要几十人完成时,就应该有一个管理者,发挥沟通协调等作用,而这个管理者对于他的上层来说就是对项目组的抽象

同样的,当我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心作用。所以可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象

Mycat工作原理

clipboard.png

Mycat的原理中最重要的一个动词是"拦截",它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户

Mycat应用场景

Mycat适用的场景很丰富,以下是几个典型的应用场景

  • 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
  • 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
  • 多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多租户化
  • 报表系统,借助于Mycat的分表能力,处理大规模报表的统计
  • 替代Hbase,分析大数据
  • 作为海量数据实时查询的一种简单有效方案,比如100亿条频繁查询的记录需要在3秒内查询出来结果,除了基于主键的查询,还可能存在范围查询或其他属性查询,此时Mycat可能是最简单有效的选择
  • Mycat长期路线图
  • 强化分布式数据库中间件的方面的功能,使之具备丰富的插件、强大的数据库智能优化功能、全面的系统监控能力、以及方便的数据运维工具,实现在线数据扩容、迁移等高级功能
  • 进一步挺进大数据计算领域,深度结合Spark Stream和Storm等分布式实时流引擎,能够完成快速的巨表关联、排序、分组聚合等 OLAP方向的能力,并集成一些热门常用的实时分析算法,让工程师以及DBA们更容易用Mycat实现一些高级数据分析处理功能

Mycat不适合的应用场景

  • 设计使用Mycat时有非分片字段查询,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时有分页排序,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果要进行表JOIN操作,要确保两个表的关联字段具有相同的数据分布,否则请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果有分布式事务,得先看是否得保证事务得强一致性,否则请慎重使用Mycat,可以考虑放弃!

MyCat的高可用性:

需要注意: 在生产环境中, Mycat节点最好使用双节点, 即双机热备环境, 防止Mycat这一层出现单点故障.可以使用的高可用集群方式有:

  • Keepalived+Mycat+Mysql
  • Keepalived+LVS+Mycat+Mysql
  • Keepalived+Haproxy+Mycat+Mysql

6.2.4.2 Mycat 安装

下载安装JDK

[19:03:59 root@centos8 ~]#yum -y install java
#确认安装成功
[19:05:07 root@centos8 ~]#java -version
openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-b01)
OpenJDK 64-Bit Server VM (build 25.275-b01, mixed mode)

下载安装mycat

[19:07:42 root@centos8 ~]#wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz
[19:08:04 root@centos8 ~]#mkdir /apps
[19:08:14 root@centos8 ~]#tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz -C /apps/
[19:08:36 root@centos8 ~]#ls /apps/mycat/
bin  catlet  conf  lib  logs  version.txt

mycat安装目录结构:

  • bin mycat命令,启动、重启、停止等
  • catlet catlet为Mycat的一个扩展功能
  • conf Mycat 配置信息,重点关注
  • lib Mycat引用的jar包,Mycat是java开发的
  • logs 日志文件,包括Mycat启动的日志和运行的日志
  • version.txt mycat版本说明

logs目录:

  • wrapper.log mycat启动日志
  • mycat.log mycat详细工作日志

Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:

  • server.xml Mycat软件本身相关的配置文件,设置账号、参数等
  • schema.xml Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、节点控制
  • rule.xml Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等

启动和连接

[19:08:47 root@centos8 ~]#vim /etc/profile.d/mycat.sh
PATH=/apps/mycat/bin:$PATH
[19:11:15 root@centos8 ~]#source /etc/profile.d/mycat.sh
#启动
[19:12:57 root@centos8 bin]#mycat start
#查看日志,确定成功
[19:13:03 root@centos8 bin]#cat /apps/mycat/logs/wrapper.log
INFO   | jvm 1    | 2021/03/06 19:13:07 | MyCAT Server startup successfully. see logs in logs/mycat.log
#连接mycat:
[19:13:03 root@centos8 bin]mysql -uroot -p123456 -h 127.0.0.1 -P8066

6.2.4.3 Mycat 主要配置文件说明

server.xml

存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等

server.xml文件中配置的参数解释说明:

  • user 用户配置节点
  • name 客户端登录MyCAT的用户名,也就是客户端用来连接Mycat的用户名。
  • password 客户端登录MyCAT的密码
  • schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如:db1,db2
  • privileges 配置用户针对表的增删改查的权限
  • readOnly mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false

注意:

  • server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录mycat时使用的账号信息
  • 逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
  • 这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用户名和密码,那么就需要在schema.xml文件中定义多个对应的库

schema.xml

是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理服务器,此文件就是用来连接MySQL服务器的

schema.xml文件中配置的参数解释说明:

  • schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应
  • dataNode 分片信息,也就是分库相关配置
  • dataHost 物理数据库,真正存储数据的数据库

配置说明

  • name属性唯一标识dataHost标签,供上层的标签使用。
  • maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数
  • minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小

每个节点的属性逐一说明

schema:

  • name 逻辑数据库名,与server.xml中的schema对应
  • checkSQLschema 数据库前缀相关设置,这里为false
  • sqlMaxLimit select 时默认的limit,避免查询全表

table

  • name 表名,物理数据库中表名
  • dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
  • primaryKey 主键字段名,自动生成主键时需要设置
  • autoIncrement 是否自增
  • rule 分片规则名,具体规则下文rule详细介绍

dataNode

  • name 节点名,与table中dataNode对应
  • datahost 物理数据库名,与datahost中name对应
  • database 物理数据库中数据库名

dataHost

  • name 物理数据库名,与dataNode中dataHost对应
  • balance 均衡负载的方式
  • writeType 写入方式
  • dbType 数据库类型
  • heartbeat 心跳检测语句,注意语句结尾的分号要加

schema.xml文件中有三点需要注意:balance="1",writeType="0" ,switchType="1"

schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类

型,目前的取值有 4 种:

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

writeHost和readHost 标签

这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。

唯一不同的是:writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。

在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去

注意:

Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的主从复制将数据复制到readhost

6.2.4.4 实战案例:利用 Mycat 实现 MySQL 的读写分离

clipboard.png

所有主机的系统环境:

cat /etc/centos-release
CentOS Linux release 8.0.1905 (Core)

服务器共三台

mycat-server 192.168.10.83 #内存建议2G以上
mysql-master 192.168.10.81 MySQL 8.0 或者Mariadb 10.3.17
mysql-slave  192.168.10.82 MySQL 8.0 或者Mariadb 10.3.17

关闭SELinux和防火墙

systemctl stop firewalld
setenforce 0
时间同步
  1. 创建 MySQL 主从数据库

掠过不会请查看之前文档

  1. 在MySQL代理服务器10.0.0.8安装mycat并启动
[19:38:02 root@centos8 ~]#yum install java wget mariadb
#确认安装
[19:38:25 root@centos8 ~]#java -version
openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-b01)
OpenJDK 64-Bit Server VM (build 25.275-b01, mixed mode)
#下载并安装
[19:38:28 root@centos8 ~]#wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz
[19:39:10 root@centos8 ~]#mkdir /apps
[19:39:17 root@centos8 ~]#tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz -C /apps/
#配置环境变量
[19:39:37 root@centos8 ~]#echo 'PATH=/apps/mycat/bin:$PATH' >/etc/profile.d/mycat.sh
[19:40:19 root@centos8 ~]#source /etc/profile.d/mycat.sh
#查看端口
[19:40:23 root@centos8 ~]#ss -ntl
State     Recv-Q    Send-Q        Local Address:Port         Peer Address:Port
LISTEN    0         128                 0.0.0.0:22                0.0.0.0:*
LISTEN    0         128                 0.0.0.0:111               0.0.0.0:*
LISTEN    0         128                    [::]:22                   [::]:*
LISTEN    0         128                    [::]:111                  [::]:*
#启动mycat
[19:40:39 root@centos8 ~]#file /apps/mycat/bin/mycat
/apps/mycat/bin/mycat: POSIX shell script, ASCII text executable
[19:40:58 root@centos8 ~]#mycat
Usage: /apps/mycat/bin/mycat { console | start | stop | restart | status | dump }
#注意: 此步启动较慢,需要等一会儿,另外如果内存太小,会导致无法启动
[19:41:06 root@centos8 ~]#mycat start
Starting Mycat-server...
#可以看到打开多个端口,其中8066端口用于连接MyCAT
[19:41:37 root@centos8 ~]#ss -ntl
State     Recv-Q    Send-Q       Local Address:Port          Peer Address:Port
LISTEN    0         128                0.0.0.0:22                 0.0.0.0:*
LISTEN    0         1                127.0.0.1:32000              0.0.0.0:*
LISTEN    0         128                0.0.0.0:111                0.0.0.0:*
LISTEN    0         128                   [::]:22                    [::]:*
LISTEN    0         50                       *:1984                     *:*
LISTEN    0         50                       *:32897                    *:*
LISTEN    0         100                      *:8066                     *:*
LISTEN    0         100                      *:9066                     *:*
LISTEN    0         50                       *:38031                    *:*
LISTEN    0         128                   [::]:111                   [::]:*
#查看日志,确定成功,可能需要等一会儿才能看到成功的提示
[19:41:57 root@centos8 ~]#tail /apps/mycat/logs/wrapper.log
STATUS | wrapper  | 2021/03/06 19:41:37 | --> Wrapper Started as Daemon
STATUS | wrapper  | 2021/03/06 19:41:37 | Launching a JVM...
INFO   | jvm 1    | 2021/03/06 19:41:38 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
INFO   | jvm 1    | 2021/03/06 19:41:38 |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
INFO   | jvm 1    | 2021/03/06 19:41:38 |
INFO   | jvm 1    | 2021/03/06 19:41:39 | MyCAT Server startup successfully. see logs in logs/mycat.log
#用默认密码123456来连接mycat
[19:42:39 root@centos8 ~]#mysql -uroot -p123456 -h192.168.10.83 -P8066
MySQL [(none)]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+
MySQL [(none)]> use TESTDB
MySQL [TESTDB]> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| address          |
| travelrecord     |
+------------------+
MySQL [TESTDB]> select * from travelrecord;
ERROR 1105 (HY000): backend connect: java.lang.IllegalArgumentException: Invalid DataSource:0
  1. 在mycat 服务器上修改server.xml文件配置Mycat的连接信息
[19:49:10 root@centos8 ~]#vim /apps/mycat/conf/server.xml
#此处将8066改为3306
<property name="serverPort">3306</property>
<user name="root" defaultAccount="true">      #连接用户名
<property name="password">zhangzhuo</property>           #密码                 
<property name="schemas">TESTDB</property>               #数据库名要和schema.xml相对应
<property name="defaultSchema">TESTDB</property>

这里使用的是root,密码为magedu,逻辑数据库为TESTDB,这些信息都可以自己随意定义,读写权限都有,没有针对表做任何特殊的权限。重点关注上面这段配置,其他默认即可。

  1. 修改schema.xml实现读写分离策略
[19:52:54 root@centos8 ~]#vim /apps/mycat/conf/schema.xm
#最终修改效果
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
	<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
	</schema>
	<dataNode name="dn1" dataHost="localhost1" database="hellodb" />
	<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="host1" url="192.168.10.81:3306" user="mycat"
				   password="123456">
           <readHost host="host2" url="192.168.10.82:3306" user="mycat"        
                   password="123456" />
		</writeHost>
	</dataHost>
</mycat:schema>
#账户需要在数据库新建授权

上面配置中,balance改为1,表示读写分离。以上配置达到的效果就是10.0.0.18为主库,10.0.0.28为从库

注意:要保证能使用mycat/123456权限成功登录192.168.10.81和192.168.10.82机器上面的mysql数据库。同时,也一定要授权mycat机器能使用mycat/123456权限成功登录这两台机器的mysql数据库!!这很重要,否则会导致登录mycat后,对库和表操作失败!

范例:schema.xml

clipboard.png

  1. 在后端主服务器创建用户并对mycat授权
MariaDB [(none)]> create user 'mycat'@'192.168.10.%' identified by '123456';
MariaDB [(none)]> grant all privileges on *.* to 'mycat'@'192.168.10.%' identified by '123456';
  1. 在Mycat服务器上连接并测试
[20:05:33 root@centos8 ~]#mycat stop
[20:06:05 root@centos8 ~]#mycat start
[20:13:47 root@centos8 ~]#mysql -uroot -pzhangzhuo -h127.0.0.1
MySQL [(none)]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+
MySQL [(none)]> use TESTDB
#写操作是在主节点执行的
MySQL [TESTDB]> create table t1(id int);
#由于下面都是查询语句所以显示都是从节点
MySQL [TESTDB]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          82 |
+-------------+
MySQL [TESTDB]> select @@hostname;
+----------------------+
| @@hostname           |
+----------------------+
| slave1.zhangzhuo.org |
+----------------------+
  1. 通过通用日志确认实现读写分离

在mysql中查看通用日志

MariaDB [(none)]> show variables like 'general_log';    #查看日志是否开启
MariaDB [(none)]> set global general_log=on;            #开启日志功能
MariaDB [(none)]> show variables like 'general_log_file'; #查看日志文件保存位置
+------------------+------------+
| Variable_name    | Value      |
+------------------+------------+
| general_log_file | master.log |
+------------------+------------+

在主和从服务器分别启用通用日志,查看读写分离

[20:30:57 root@master ~]#tail /var/lib/mysql/master.log -f
[20:30:59 root@slave1 ~]#tail -f /var/lib/mysql/slave1.log
MySQL [TESTDB]> insert into t1 values(1);
MySQL [TESTDB]> select * from t1;
+------+
| id   |
+------+
|    1 |
+------+
  1. 停止从节点,MyCAT自动调度读请求至主节点
[20:32:11 root@slave1 ~]#systemctl stop mariadb
MySQL [TESTDB]> select @@hostname;
+----------------------+
| @@hostname           |
+----------------------+
| master.zhangzhuo.org |
+----------------------+
#停止主节点,MyCAT不会自动调度写请求至从节点
MySQL [TESTDB]> insert teachers values(5,'wang',30,'M');
ERROR 1184 (HY000): java.net.ConnectException: Connection refused
  1. MyCAT对后端服务器的健康性检查方法select user()
#开启通用日志
[20:39:22 root@master ~]#mysql
MariaDB [(none)]> set global general_log=1;
#查看通用日志
[20:38:30 root@master ~]#tail -f /var/lib/mysql/master.log
210306 20:38:40	    11 Query	select user()
210306 20:38:50	    14 Query	select user()

6.2.5 ProxySQL

6.2.5.1 ProxySQL 介绍

ProxySQL: MySQL中间件

  • 两个版本:官方版和percona版,percona版是基于官方版基础上修改
  • C++语言开发,轻量级但性能优异,支持处理千亿级数据
  • 具有中间件所需的绝大多数功能,包括:
  • 多种方式的读/写分离
  • 定制基于用户、基于schema、基于语句的规则对SQL语句进行路由
  • 缓存查询结果
  • 后端节点监控

官方站点:https://proxysql.com/

官方手册:https://github.com/sysown/proxysql/wiki

6.2.5.2 ProxySQL 安装

基于YUM仓库安装

cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\$releasever
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
EOF

#基于RPM下载安装:https://github.com/sysown/proxysql/releases
yum install proxysql

ProxySQL组成

  • 服务脚本:/etc/init.d/proxysql
  • 配置文件:/etc/proxysql.cnf
  • 主程序:/usr/bin/proxysql
  • 基于SQLITE的数据库文件:/var/lib/proxysql/

启动ProxySQL:

service proxysql start

启动后会监听两个默认端口

  • 6032:ProxySQL的管理端口
  • 6033:ProxySQL对外提供服务的端口

连接ProxySQL的管理端口

使用mysql客户端连接到ProxySQL的管理接口6032,默认管理员用户和密码都是admin:

mysql -uadmin -padmin -P6032 -h127.0.0.1

数据库说明:

  • main 是默认的"数据库"名,表里存放后端db实例、用户验证、路由规则等信息。表名以 runtime开头的表示
  • proxysql当前运行的配置内容,不能通过dml语句修改,只能修改对应的不以 runtime_ 开头的(在内存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盘以供下次重启加载
  • disk 是持久化到硬盘的配置,sqlite数据文件
  • stats 是proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询种类汇总/执行时间,等等
  • monitor 库存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查

说明:

  • 在main和monitor数据库中的表, runtime开头的是运行时的配置,不能修改,只能修改非runtime表
  • 修改后必须执行LOAD … TO RUNTIME才能加载到RUNTIME生效
  • 执行save … to disk 才将配置持久化保存到磁盘,即保存在proxysql.db文件中
  • global_variables 有许多变量可以设置,其中就包括监听的端口、管理账号等
  • 参考:https://github.com/sysown/proxysql/wiki/Global-variables

7.2.5.3 实战案例:利用 ProxySQL 实现读写分离

  1. 环境准备:yum安装只可以在centos7,centos8没有这个包

准备三台主机,一台ProxySQL服务器:192.168.8.7,另外两台主机实现主从复制192.168.8.17,27注意:slave节点需要设置read_only=1

  1. 安装ProxySQL,并向ProxySQL中添加MySQL节点,以下操作不需要use main也可成功
[11:54:48 root@proxysql ~]#cat < [proxysql_repo]
> name= ProxySQL YUM repository
> baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\$releasever
> gpgcheck=1
> gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
> EOF
> [12:29:13 root@proxysql ~]#yum install  proxysql mariadb
> [12:27:59 root@proxysql ~]#service proxysql start
> [12:30:01 root@proxysql ~]#mysql -uadmin -padmin -h127.0.0.1 -P6032
> MySQL [(none)]> show tables;
> MySQL [(none)]> select * from sqlite_master where name='mysql_servers'\G
> MySQL [(none)]> select * from mysql_servers;
> MySQL [(none)]> insert into mysql_servers (hostgroup_id,hostname,port) values(10,'192.168.10.72',3306);
> MySQL [(none)]> insert into mysql_servers (hostgroup_id,hostname,port) values(20,'192.168.10.73',3306);
> MySQL [(none)]> load mysql servers to runtime;
> MySQL [(none)]> save mysql servers to disk;
  1. 添加监控后端节点的用户,连接每个节点的read_only值来自动调整主从节点是属于读组还是写组
#在master上执行
MariaDB [(none)]> grant replication client on *.* to monitor@'192.168.10.%' identified by '123456';
#ProxySQL上配置监控
MySQL [(none)]> set mysql-monitor_username='monitor';
MySQL [(none)]> set mysql-monitor_password='123456';
#加载到RUNTIME,并保存到disk
MySQL [(none)]> load mysql variables to runtime;
MySQL [(none)]> save mysql variables to disk;
  1. 查看监控

监控模块的指标保存在monitor库的log表中

#查看监控连接是否正常的 (对connect指标的监控),如果connect_error的结果为NULL则表示正
常
MySQL [(none)]> select * from mysql_server_connect_log;
#查看监控心跳信息 (对ping指标的监控):
MySQL [(none)]> select * from mysql_server_ping_log;
  1. 设置分组信息

需要修改的是main库中的mysql_replication_hostgroups表,该表有3个字段:

writer_hostgroup,reader_hostgroup,comment, 指定写组的id为10,读组的id为20

MySQL [(none)]> insert into mysql_replication_hostgroups values(10,20,"test");
#将mysql_replication_hostgroups表的修改加载到RUNTIME生效
MySQL [(none)]> load mysql servers to runtime;
MySQL [(none)]> save mysql servers to disk;
#Monitor模块监控后端的read_only值,按照read_only的值将节点自动移动到读/写组
MySQL [(none)]> select hostgroup_id,port,status,weight from mysql_servers;
+--------------+------+--------+--------+
| hostgroup_id | port | status | weight |
+--------------+------+--------+--------+
| 10           | 3306 | ONLINE | 1      |
| 20           | 3306 | ONLINE | 1      |
+--------------+------+--------+--------+
  1. 配置访问数据库的SQL 用户
#在master节点上创建访问用户
MariaDB [(none)]> grant all on *.* to sqluser@'192.168.10.%' identified by '123456';
#在ProxySQL配置,将用户sqluser添加到mysql_users表中, default_hostgroup默认组设置
为写组10,当读写分离的路由规则不符合时,会访问默认组的数据库
MySQL [(none)]> insert into mysql_users(username,password,default_hostgroup) values('sqluser','123456',10);
MySQL [(none)]> load mysql users to runtime;
MySQL [(none)]> save mysql users to disk;
#使用sqluser用户测试是否能路由到默认的10写组实现读、写数据
[13:10:08 root@proxysql ~]#mysql -usqluser -p123456 -P6033 -h127.0.0.1 -e'select @@server_id'
[13:10:48 root@proxysql ~]#mysql -usqluser -p123456 -P6033 -h127.0.0.1 -e'create database testdb'
[13:11:07 root@proxysql ~]#mysql -usqluser testdb -p123456 -P6033 -h127.0.0.1 -e'create table t(id int)'
  1. 在proxysql上配置路由规则,实现读写分离

与规则有关的表:mysql_query_rules和mysql_query_rules_fast_routing,后者是前者的扩展表,1.4.7之后支持

插入路由规则:将select语句分离到20的读组,select语句中有一个特殊语句SELECT...FOR

UPDATE它会申请写锁,应路由到10的写组

MySQL [(none)]> insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) values(1,1,'^SELECT.*FOR UPDATE$',10,1),(2,1,'^SELECT',20,1);
MySQL [(none)]> load mysql query rules to runtime;
MySQL [(none)]> save mysql query rules to disk;
#注意:因ProxySQL根据rule_id顺序进行规则匹配,select ... for update规则的rule_id必须要小于普通的select规则的rule_id
  1. 测试ProxySQL
#读操作是否路由给20的读组
[13:16:49 root@proxysql ~]#mysql -usqluser  -p123456 -P6033 -h127.0.0.1 -e'select @@server_id'
#测试写操作,以事务方式进行测试
[13:17:49 root@proxysql ~]#mysql -usqluser  -p123456 -P6033 -h127.0.0.1 \

> -e 'start transaction;select @@server_id;commit;select @@server_id'
> [13:18:45 root@proxysql ~]#mysql -usqluser  -p123456 -P6033 -h127.0.0.1 -e'insert testdb.t values (1)'
> [13:19:37 root@proxysql ~]#mysql -usqluser  -p123456 -P6033 -h127.0.0.1 -e'select * from testdb.t'
> #路由的信息:查询stats库中的stats_mysql_query_digest表
> MySQL [(none)]> select hostgroup hg,sum_time,count_star,difest_text from stats_mysql_query_digest order by sum_time DESC;

标题:9-MySQL集群架构-读写分离
作者:Carey
地址:HTTPS://zhangzhuo.ltd/articles/2021/03/07/1615116951453.html

生而为人

取消