1.现实中的问题
我们知道数据库的数据,基本80%的业务是查询,20%的业务涵盖了增删改,经过长期的业务变更和积累数据库的数据到达了一定的数量之后,直接影响的是用户与系统的交互,查询时的速度,插入数据时的流畅度,系统的可用性,这些指标对用户体验都是会有影响的,不说用户,你自己用是什么感觉?我经历过且常见的无非以下几个解决方案,从用户,代码,数据库,不知道有没有人跟我有相似的经历
1.最简单粗暴的就是从用户下手,也就是通过业务的手段来约束,限定查询时间,限定查询条件,大批量需要申请后台工程师导出,不是说对这些方法嗤之以鼻,在某些场景下这样也是不错的方法.
2.检查代码,查询语句什么的能优化的做下优化,这一点确实也是比较关键的,再好的架构和服务器,也顶不住递归死循环查询这些.
3.结合一些数据库监控工具或者对常用查询的表,做一些数据库基本的属性设定,例如数据库加索引,分分区.
虽然确实可以使用这些技术手段来提升本身的查询速度,但是达到一定量级,这些手段得到的改善也不是很大,因为数据的量是实实在在的存在,假设此时加上并发量的增大,数据库引擎在查询或者计算时,使用的是服务器的CPU和内存,当资源消耗过高时,直接降低系统可用性,往往这个时候就需要通过整体业务上的变通或者技术架构的转换上来着手解决问题了。
然而现实中业务上的改变,可能在落实上会存在很大的问题,但是可以从技术架构上来尝试解决,主要在代码整体架构或者数据库存储架构解决了,我们主要介绍数据架构层面的方案。
1.分库
-
在水平分库中,就是将数据库中的表,存到不同的数据库,但是不同库的表数量和结构是一样的,只是每个库的数据都不一样,没有交集,库的并集是全量数据
-
在垂直分库中,以表为依据,按照业务归属不同,将不同的表拆分到不同的库中,不同的库存储的可能是不同的表,库的并集是全量数据
2.分表
-
水平分表就是将一张表分为多张表,表的结构都一样,每个表的数据都不一样,没有交集,所有表的并集是全量数据;
-
垂直分表将一张表字段拆分为不同的表,合并起来就是整个全量数据,但是这种可以归属于设计之初的设计缺陷
虽然使用分库分表可以一定程度解决上面所说的问题,但是分了之后也有可能再变大,总不能一直无脑拆分下去把,此时应该使用读写分离,也就是说读写分离应该是在分库分表的基础之上来实施的。
2.什么是ShardingSphere-Proxy?
在ShardingSphere
中一共有3个核心组件 ShardingSphere-JDBC
定位是一个Java的框架 、ShardingSphere-Proxy
、ShardingSphere-Sidecar
还在开发中,我们主要介绍ShardingSphere-Proxy和ShardingSphere-Proxy的实际应用。
ShardingSphere-Proxy定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持,主要目的对数据库实现分库分表和读写分离,应用场景不管是传统的单体项目,或者现有流行的微服务项目中都可以使用,但是目前只支持 MySQL 和 PostgreSQL
, 它在整个系统架构中定位是一个数据库中间件
。
在这里我们选择使用ShardingSphere-Proxy
中间件,来作为我们实现分库分表的工具,写这个的目的主要是记录ShardingSphere-Proxy的使用和一些基本的概念,至于说具体分成什么样,如果您只想知道到底是分表,还是分库,又或者是分库分表,我可能帮不了什么,但是您可以按照现在所困扰的问题展开分析,然后使用ShardingSphere-Proxy落地。
3.分库分表方案
实现分库分表的方案根据不同的需求可能会延伸出很多,但是我们在逻辑上抽象出2种,一种是进程内
和业务系统集成,一种是拆分出分库分表作为独立进程
,
1.进程内方案
进程内的方案通常是将分库分表实现业务放到系统内部,通常存在以下缺陷
-
1.系统和分库分表会存在资源竞争
-
2.一个异常的话,另外一个也会异常,依赖性太强。
-
3.无法适应异构,对其他语言的支持
2.进程外方案
进程外方案将分库分表逻辑拆分,使用单独的工具实现客户端将请求发送到系统, 系统通过数据库中间件在内部进行分库分表逻辑,然后存储数据库,通常存在以下缺陷
-
1.维护量上升
-
2.相对进程内,性能会差一点,但是如果内网部署基本可以接受
4.ShardingSphere-Proxy基本概念
使用ShardingSphere-Proxy
在进行实现分库分表或者查询时,主要有6个阶段,这整个阶段中的核心步骤是由中间件来实现的。
-
1.选择具体数据库
-
2.sql解析将中间件连接成为真实数据库连接
-
3.sql路由,选择一个真实数据库执行
-
4.sql重写优化
-
5.sql执行真实数据库获取结果
-
6.结果合并从多个表或者库中获取结果
用户主要是针对路由规则
的配置,实现将数据分片
到不同表以及不同的库,那我们应该思考如何对数据进行分片呢,需要哪些条件?
-
1.分片键:数据表中的字段,选择以哪个字段作为分片的条件。
-
2.分片算法:它的作用就是根据分片数据字段如何去实现数据的分片。
5.项目环境及搭建
ShardingSphere-Proxy
是由java开发,所以首先我们需要准备java
的基本环境。
1.环境准备
- 1.下载Mysql
- 2.下载jdk1.8 提取码:wgl2
- 3.下载mysql-connector-java-5.1.47.jar
- 4.下载ShardingSphere-Proxy
- 4.1 使用tar命令解压 tar zxvf apache-shardingsphere-5.0.0-shardingsphere-proxy-bin.tar.gz
- 4.2 将下载的mysql-connector-java-5.1.47.jar 拷贝到lib目录下
6.分库分表配置
1.ShardingSphere-Proxy 分表
1.以数据采集数据库的电源信息数据表为例,如果没有数据库就创建数据库
2.在ShardingSphere-Proxy
中的conf下找到config-sharding.yaml
配置文件进行配置
3.在config-sharding.yaml
中配置数据库连接
dataSources:
dataacquisitionsources_0:
url: jdbc:mysql://localhost:3306/dataacquisition?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
4.配置表和数据的分片规则
-
- actualDataNodes节点用来配置分成几张表{0..1}就是2张,如果配置10张那就{0..9}
-
- 如果多张表分表就使用多个逻辑表名和节点,注意一定要注意配置格式
rules:
- !SHARDING
tables:
powerinformation:# 逻辑表名
actualDataNodes: dataacquisitionsources_0.powerinformation_${0..1} #分表
tableStrategy: #数据分表策略
standard:
shardingColumn: id #分表字段
shardingAlgorithmName: powerinformation_MOD
shardingAlgorithms:
powerinformation_MOD:
type: MOD
props:
sharding-count: 2
5.配置客户端连接虚拟数据库,一般和真实库名对应
schemaName: dataacquisition
6.打开配置目录的server.yaml配置文件,来设置用户和密码
rules:
- !AUTHORITY
users:
- root@%:root
- sharding@:sharding
provider:
type: ALL_PRIVILEGES_PERMITTED
7.启动bin目录下的start.bat
,如果出现以下画面,那么恭喜你中间件被成功配置
8.使用客户端连接虚拟服务器3307端口
9.执行脚本在虚拟服务器上创建表结构,那么中间件会默认按照预定的规则分表
create table powerinformation
(
id int not null AUTO_INCREMENT PRIMARY key,
Station Text,
voltage DECIMAL,
resistance DECIMAL,
electricity DECIMAL,
createDate DATETIME
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;
10.打开客户端查看真实库已经分表成功
2.ShardingSphere-Proxy 分库
1.创建2个数据库分别取名为dataacquisition_0和dataacquisition_1
2.打开配置文件,对代理配置不同数据库连接
dataSources:
dataacquisitionsources_0:
url: jdbc:mysql://127.0.0.1:3306/dataacquisition_0?serverTimezone=UTC&useSSL=false #连接库0
username: root
password: sa@123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
dataacquisitionsources_1:
url: jdbc:mysql://127.0.0.1:3306/dataacquisition_1?serverTimezone=UTC&useSSL=false #连接库1
username: root
password: sa@123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
3.配置分库规则,由于现在是2个不同的库,所以不需要配置数据分到表的规则
rules:
- !SHARDING
tables:
powerinformation:
actualDataNodes: dataacquisitionsources_${0..1}.powerinformation #库名表达式
databaseStrategy: #数据分库策略
standard:
shardingColumn: id
shardingAlgorithmName: powerinformation_MOD
shardingAlgorithms:
powerinformation_MOD:
type: MOD
props:
sharding-count: 2
4.在虚拟库中添加表和数据将会分配到2个不同的库
3.ShardingSphere-Proxy 分库分表
1.按照分库的操作执行,分库配置不变
2.配置文件配置分库分表的规则
rules:
- !SHARDING
tables:
powerinformation:
actualDataNodes: dataacquisitionsources_${0..1}.powerinformation_${0..1}
tableStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: powerinformation_MOD
databaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: powerinformation_MOD
shardingAlgorithms:
powerinformation_MOD:
type: MOD
props:
sharding-count: 2
7.搭建常见问题
1.由于是yaml文件,一定要注意对应节点的格式对齐
2.建议使用大于等于5.0.0+版本 折腾4.0.0版本被恶心吐了
3.如果出现 near 0这种错误就是在配置中使用了特殊符号 建议使用 下划线的"_"