一、分库分表概念
1.分表
(1)垂直分表
表中的字段较多,一般将不常用的、 数据较大、长度较长的拆分到“扩展表“。一般情况加表的字段可能有几百列,此时是按照字段进行数竖直切。注意垂直分是列多的情况。
(2)水平分表
单表的数据量太大。按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。这种情况是不建议使用的,因为数据量是逐渐增加的,当数据量增加到一定的程度还需要再进行切分。比较麻烦
2.分库
(1)垂直分库
一个数据库的表太多。此时就会按照一定业务逻辑进行垂直切,比如用户相关的表放在一个数据库里,订单相关的表放在一个数据库里。注意此时不同的数据库应该存放在不同的服务器上,此时磁盘空间、内存、TPS等等都会得到解决。
(2)水平分库
水平分库理论上切分起来是比较麻烦的,它是指将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。
二、为什么要分库分表
1.为什么要分库
按一般的经验来说,一个单库最多支持并发量到2000,且最好保持在1000。如果有20000并发量的需求,这时就需要扩容了,可以将一个库的数据拆分到多个库中,访问的时候根据一定条件访问单库,缓解单库的性能压力。
2.为什么要分表
分表也是一样的,如果单表的数据量太大,就会影响SQL语句的执行性能。分表就是按照一定的策略将单表的数据拆分到多个表中,查询的时候也按照一定的策略去查询对应的表,这样就将一次查询的数据范围缩小了。比如按照用户id来分表,将一个用户的数据就放在一个表中,crud先通过用户id找到那个表在进行操作就可以了。这样就把每个表的数据量控制在一定范围内,提升SQL语句的执行性能。
三、使用哪些分库分表中间件好
这里主要讲解 sharding中的 sharding -proxy并且是单独启动的服务,无需在项目中结合。
1.Sharding-Proxy的安装
我们可以在Sharding-Proxy官网上找的下载目录,再找到Sharding-Proxy的下载链接,下载最新版本的二进制包。然后把二进制包(tar.gz)上传到服务器的目录中,然后解压
2.配置sharding-Proxy的分片规则
进入到sharding-proxy的conf目录,这个目录sharding-proxy的配置目录,我们所有的数据源、分片规则、读写分离等都在此目录下配置。
-
logback.xml是日志的配置。
-
server.yaml是Sharding-Proxy的一些基础配置,比如:账号、密码、注册中心等。
-
剩下的所有以config开头的yaml文件,都是一个逻辑数据源,我们可以看到最常见的两个config-sharding.yaml(分片的配置),config-master_slave.yaml(读写分离的配置)。注意,如果我们要配置分片+读写分离,要不要在两个配置文件中配置呢?不需要的,我们只需要在config-sharding.yaml中配置就可以了,如果要配置单独的读写分离,则需要按照config-master_slave.yaml配置。单独的读写分离和分片+读写分离在配置上,还是有一些区别的。
这里主要讲解配置分片
在这里我们的数据库使用的是MySQL,我们要将mysql-connector-java.jar这个jar包放入lib目录
3.配置config-sharding.yaml
# 配置虚拟出来的数据库名,在server.yaml中会用到
schemaName: sharding_db
#配置数据源
dataSources:
test0:
url: jdbc:mysql://localhost:3306/test0?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=Asia/Shanghai
username: root
password: 1754
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
test1:
url: jdbc:mysql://localhost:3306/test1?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=Asia/Shanghai
username: root
password: 1754
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
#配置分片规则
shardingRule:
tables:
#配置表分片策略为复合策略
table_one:
actualDataNodes: test.table_one20${1..4}
tableStrategy:
complex:
shardingColumns: ctstamp
#com.sinosoft.dea.sharding.algorithm.WjwTableByDateAlg 是java包,需要另行开发打包成jar包放到lib目录下
algorithmClassName: com.sinosoft.dea.sharding.algorithm.WjwTableByDateAlg
bindingTables:
- table_one
#配置默认分库策略为行表达式分片策略 用户id模2 得出 0或1作为数据库test的后缀
defaultDatabaseStrategy:
inline:
shardingColumn: user_id
algorithmExpression: test${user_id % 2}
defaultTableStrategy:
none:
4.配置server.yaml
authentication:
#配置用户名密码 root 1234
users:
root:
password: 1234
tcmuser:
password: tcmuser
#在config-sharding中配置的虚拟出来的库名
authorizedSchemas: sharding_db
#
props:
max.connections.size.per.query: 1
acceptor.size: 16 # The default value is available processors count * 2.
executor.size: 16 # Infinite by default.
proxy.frontend.flush.threshold: 128 # The default value is 128.
# # LOCAL: Proxy will run with LOCAL transaction.
# # XA: Proxy will run with XA transaction.
# # BASE: Proxy will run with B.A.S.E transaction.
proxy.transaction.type: LOCAL
proxy.opentracing.enabled: false
query.with.cipher.column: true
sql.show: true
allow.range.query.with.inline.sharding: false
5.启动
windows下运行bin目录下的start.bat linux运行start.sh
四、分片策略介绍
1.标准分片策略
对应StandardShardingStrategy。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
2.复合分片策略
对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
3.行表达式分片策略
对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8}
表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0
到t_user_7
。
4.Hint分片策略
对应HintShardingStrategy。通过Hint而非SQL解析的方式分片的策略。
5.不分片策略
对应NoneShardingStrategy。不分片的策略。
五、实战定义分片策略
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.0.0-RC3</version>
</dependency>
public class AdminIdShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> {
@Override
public Collection<String> doSharding(Collection<String> tables, ComplexKeysShardingValue<String> shardingValue) {
// 获取用到的参数名比如插入时 id name password 等
Map<String, Collection<String>> valueMap = shardingValue.getColumnNameAndShardingValuesMap();
//获取范围,这儿以获取时间范围为例
Map<String, Range<String>> rangeMap = shardingValue.getColumnNameAndRangeValuesMap();
Range<String> datatime=rangeMap.get("ctstamp");
System.out.println("获取条件中的时间"+datatime);
String startDate = datatime.lowerEndpoint();
System.out.println("获取条件中的最小时间"+startDate);
String endDate = datatime.upperEndpoint();
System.out.println("获取条件中的最大时间"+endDate);
//拿到数据库操作的参数名,比如查询时 where中的id,插入时id的值等。根据自己的需求计算出
//相应的数据库后缀名
//比如: 现在表名有两张 test0和test1
//那么我这边插入时 id%2 得出的是1的话,那么我这边就将相应的库名返回,即test1。
//这样就不会对test0做操作
//查询时也相同道理,根据要查的id =4 的话,我这边拿到这个值,4%2=0,那么我就知道去test0查询
//不用在去test1查询
//这边最后返回的就是你业务逻辑满足的表名,不单单只会是一张表
//tables就是数据库中实际存在的所有分表,如果配置了10张那么这个值就包含了所有的名称
//这儿是分片对表操作,也有相应的策略对库进行操作。但逻辑都是大同小异
return tables;
}
}
有不足指出还望大佬指出!!!