接上文《架构设计:系统存储(11)——MySQL 主从方案业务连接透明化(上)》
在上文中我们介绍了 MySQL 读写分离集群的持续优化方式。按照这样的方式,集群中负责读写分离的 mysql 节点基本上能够分别实现真对上层业务系统访问的透明化。这样的 MySQL 集群方式已经可以承载读者遇到的大部分业务系统的结构化数据规模,但整个集群方案还有一些明显的问题:首先就是业务开发人员始终还是需要分配一定的精力去分别管理读操作会话和写操作会话的数据库连接;其次这个集群方案主要解决的是单张数据表数据量不大条件下的 MySQL 读写性能(千万级数据,还有一个前提是数据表本身拥有符合业务要求的索引结构且数据节点的性能配置合理),如果数据库中单张数据表的规模达到了亿级(甚至以上),那么查询压力集中在一个读节点上也不会再有助于查询性能提升。
所以在必要的情况下,我们还需要继续对上文给出的 MySQL 集群方案进行改进,让其能够适应更庞大的结构化数据规模。具体的思路就是在保持读写分离方案的基础上,对业务系统中结构化数据量达到或者超过亿级规模的若干张业务表进行拆分工作。本篇文章向读者介绍一个由国人开发并完全免费发布的数据库中间件,MyCat。它不但可以作为之前介绍的读写分离方案的替换方案,更重要的是它还能独立创建和管理数据表的拆分工作。
在实际运行的业务系统中,如果其承载的结构化数据量超过了亿级,那么最可能的情况是数据库中某一张或者某几张数据表的承载规模超过亿级,其它大多数数据表的数据量并不会太大。所以实际工作中架构师和 DBA 只需要针对这几张数据表和直接关联的数据表设计数据拆分方案。
MyCat 是一款数据库中间件,它基于阿里的一款数据库中间件 Cobar 而研发。"数据库中间件" 这在整个专题的文章中都是一个新词语,但从 "中间件" 这个关键词来看我们至少可以知道:MyCat 并不真正处理数据库操作而是作为一个中间层存在于业务系统和真实的数据存储系统之间。
上图来源于 MyCat 官网(http://www.mycat.org.cn/)。是的,MyCat 数据库中渐渐最关键的一个动词是 "拦截",它拦截了用户发送过来的 SQL 语句,对 SQL 语句做一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。MyCat 数据库中间件不只可以作为 MySQL(MariaDB)的最佳搭配,还可以提供对 Oracle、DB2、SQL Server、MongoDB 的支持。只不过 MyCat 对这几个关系型数据库的支持是基于 JDBC 规范,将它们模拟为 MySQL,而对 mongodb 的支持(Version 1.3 + 的版本支持)是封装了 MongoDB API 基于 JDBC 的实现。MyCat 最关键的功能特性还包括:
在正式介绍 MyCat 使用之前,为了便于读者能够更好的理解后续的技术方案,需要首先向读者介绍一些和下文示例有关的 MyCat 基础定义。如果读者需要深入了解 MyCat 的工作原理和技术实现,可以到其官网上下载更多资料。
数据的拆分方式一般分为两种:横向(水平)和纵向(垂直)。纵向(垂直)拆分方式从技术层面上来说相对简单且便于维护,其基本原理是将原本存在于同一个数据库中的属于不同业务模块的数据表分别拆分到不同的数据库中进行存储(这些数据库可能在同一操作系统上也可能不在同一操作系统上,可能在同一个数据库集群上也可能不在同一个数据库集群上)。纵向(垂直)拆分其操作目标是数据表,要完成这样的拆分动作,技术团队至少应该保证这些业务模块存在极少的耦合度。横向(水平)拆分是指为了限制 / 减少将某张数据表中的数据规模,按照某种规则将这张数据表拆分成字段相同的多张数据表,并存储到不同的数据库中(这些数据库一般不在同一个操作系统上)。 横向(水平)拆分操作目标是数据表中的数据,其目的是在结构化数据达到一定规模时(达到千万级别),将针对数据表的某一次操作请求的压力分配到若干个服务节点上。可见真正能够进一步解决关系型数据库性能问题的办法,还需要对数据表进行横向(水平)拆分,而 MyCat 的数据组织结构主要就是为了支持数据表的横向(水平)拆分。
作为快速上手也为了继续优化之前文章中介绍的 MySQL 读写分离方案,本小节我们首先通过 MyCat 配置一个最简的、单纯的读写分离集群。配置过程的是指也很简单:不需要对逻辑表进行分片,也就是说只需要配置一个分片表和分片节点;只使用读写分离功能,也就是说只需要在这唯一的一个分片节点配置读节点和写节点以及节点健康的检查策略。
您可以在 MyCat 官网上下载 MyCat 的 Linux 版本,在本文发表时 MyCat 稳定版本为 V 1.6.1。MyCat 数据库中间件的工作目录下的 conf 文件夹中存放着所有需要的配置文件,其中有几个配置文件比较重要,它们是:schema.xml、rule.xml 和 server.xml。rule.xml 描述了逻辑表和逻辑节点 / 分片节点的关联规则,也即是数据的分片规则;server.xml 描述了 MyCat 服务的访问规则和用户授权规则。最重要的是 schema.xml 文件,其中描述了上文中我们提到的几个关键概念,逻辑库、逻辑表、分片节点和节点主机。一般来说我们要实现单纯的读写分离集群,只需要对 schema.xml 文件进行更改:
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <!-- 首先是逻辑库的定义,逻辑库名叫做qiangSchema。其中定义了两个逻辑表 -->
- <schema name="qiangSchema" checkSQLschema="false" sqlMaxLimit="100">
- <!-- 逻辑表要和物理表的名字一样,大小写也最好一样。关于type属性的定义后文会详细描述 两张逻辑表都对应一个逻辑节点/分片节点——dn1。也就是说两张逻辑表都不做水平拆分
- -->
- <table name="myuser" primaryKey="Id" type="global" dataNode="dn1" />
- <table name="t_user" primaryKey="uid" type="global" dataNode="dn1" />
- </schema>
- <!-- 逻辑节点/分片节点的定义,注意其使用的节点主机定义 -->
- <dataNode name="dn1" dataHost="dataHost" database="qiang" />
- <!-- 节点主机中包括两个物理节点,其中一个是读节点另一个是写节点 -->
- <dataHost name="dataHost" maxCon="1000" minCon="10" balance="1" writeType="0"
- dbType="mysql" dbDriver="native" switchType="2">
- <heartbeat>
- select user()
- </heartbeat>
- <!-- MyCat支持一个节点主机下定义多个读节点和多个写节点 -->
- <writeHost host="hostM1" url="192.168.61.140:3306" user="root" password="123456">
- <!-- can have multi read hosts -->
- <readHost host="hostS1" url="192.168.61.141:3306" user="root" password="123456"
- />
- </writeHost>
- </dataHost>
- </mycat:schema>
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1 2 3 4
- 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
这里要注意一个关键点,请在由 linux For MyCat 控制的各个 MySQL 节点上设置 "lower_case_table_names = 1",否则使用 MyCat 的时候会提示找不到表的错误。以上代码段落示意了 MyCat 中实现的最简单的读写分离集群最关键的配置信息,这里对配置信息进行一些必要的说明(部分说明直接摘自 MyCat 官方文档):
配置完成 schema.xml 文件并且保存后,就可以用过 "mycat console" 命令启动了。"mycat console" 命令可以用于测试配置效果使用,因为这样的启动方式 MyCat 将会把日志直接输出到屏幕上。
- #mycat console Running Mycat - server...wrapper | -->Wrapper Started as Console wrapper | Launching a JVM...jvm 1 | Wrapper(Version 3.2.3) http: //wrapper.tanukisoftware.org
- jvm 1 | Copyright 1999 - 2006 Tanuki Software,
- Inc.All Rights Reserved.jvm 1 | jvm 1 | 2016 - 11 - 10 00 : 03 : 25,
- 369[INFO][WrapperSimpleAppMain] total resouces of dataHost dataHost is: 2(io.mycat.backend.datasource.PhysicalDBPool: PhysicalDBPool.java: 100)......jvm 1 | 2016 - 11 - 10 00 : 03 : 26,
- 874[INFO][WrapperSimpleAppMain] === ============================================(io.mycat.MycatServer: MycatServer.java: 266) jvm 1 | 2016 - 11 - 10 00 : 03 : 26,
- 874[INFO][WrapperSimpleAppMain] MyCat is ready to startup... (io.mycat.MycatServer: MycatServer.java: 267) jvm 1 | 2016 - 11 - 10 00 : 03 : 26,
- 874[INFO][WrapperSimpleAppMain] Startup processors...,
- total processors: 2,
- aio thread pool size: 4 jvm 1 | each process allocated socket buffer pool bytes,
- a page size: 2097152 a page 's chunk number(PageSize/ChunkSize) is:512 buffer page's number is: 40(io.mycat.MycatServer: MycatServer.java: 279)......jvm 1 | 2016 - 11 - 10 00 : 03 : 28,
- 396[INFO][WrapperSimpleAppMain] using nio network handler(io.mycat.MycatServer: MycatServer.java: 381) jvm 1 | 2016 - 11 - 10 00 : 03 : 28,
- 513[INFO][WrapperSimpleAppMain] $_MyCatManager is started and listening on 9066(io.mycat.MycatServer: MycatServer.java: 397) jvm 1 | 2016 - 11 - 10 00 : 03 : 28,
- 515[INFO][WrapperSimpleAppMain] $_MyCatServer is started and listening on 8066(io.mycat.MycatServer: MycatServer.java: 401) jvm 1 | 2016 - 11 - 10 00 : 03 : 28,
- 515[INFO][WrapperSimpleAppMain] === ============================================(io.mycat.MycatServer: MycatServer.java: 403) jvm 1 | 2016 - 11 - 10 00 : 03 : 28,
- 515[INFO][WrapperSimpleAppMain] Initialize dataHost... (io.mycat.MycatServer: MycatServer.java: 407)......1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
可以看到 MyCat 启动成功了,接下来就可以使用 mysql 的客户端进行连接并测试读写操作执行了。
- // 连接到mycat,mycat的端口为8066
- #mysql - h 192.168.61.144 - P 8066 - u root - p Enter password: Welcome to the MySQL monitor.Commands end with;
- or\g.Your MySQL connection id is 1 Server version: 5.6.29 - mycat - 1.6 - RELEASE - 20161028204710 MyCat Server(OpenCloundDB)......
- // 接下来执行一个insert语句:
- > insert into myuser(Id, user_name, usersex, user_number) values(24, 'user24', 0, '242424');
- // 从读节点查询刚才插入的数据
- > select * from myuser; + ----+-----------+---------+-------------+|Id | user_name | usersex | user_number | +----+-----------+---------+-------------+|1 | 用户1 | 1 | 11111 | |22 | 用户22 | 0 | 220220 | |23 | 用户23 | 1 | 232323 | |24 | user24 | 0 | 242424 | +----+-----------+---------+-------------+1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
需要注意 MyCat 并不负责节点主机中设置的写节点和读节点间的数据同步过程,所以您还是需要使用 MySQL Replicaion 机制完成读写节点的同步工作。另外注意,某些 MySQL 第三方客户端由于不支持 NIO 方式,所以连接 MyCat 还有一些问题,例如 MySQL-Front。接下来的文章我们来实际搭建一个 MyCat 对数据库集群横向拆分和纵向拆分的支持。
百度搜索 "就爱阅读", 专业资料, 生活学习, 尽在就爱阅读网 92to.com, 您的在线图书馆!
来源: http://www.92to.com/bangong/2017/07-24/25640720.html