官方文档:https://shardingsphere.apache.org/document/
目录
一、规则配置
二、引入依赖
三、启动服务
四、使用ShardingSphere-Proxy
五、问题总结
ps:
实操前置条件:需要自行实现mysql集群的搭建,以及主从数据同步
可以参考我的前一篇文章:MySQL主从同步(一)
一、规则配置
定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL 版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据。
避免业务端直接访问数据库层还需要对业务代码进行改造,以适配sharding规则
我的工作路径:/Users/yw/workspace/shardingdock
规则配置文件:/Users/yw/workspace/shardingdock/conf
接下来要构建的数据库层级大致如下:
- server.yaml
authentication:
users:
root:
password: root
sharding:
password: root
#authorizedSchemas对应的是后续config配置中的schemaName。多个用逗号分隔。
authorizedSchemas: ebook
- config-sharding.yaml
schemaName: ebook # 逻辑数据库名字
dataSourceCommon: #数据源公共配置
username: root
password: root
connectionTimeoutMilliseconds: 30000 # 连接超时毫秒数
idleTimeoutMilliseconds: 60000 # 空闲连接回收超时毫秒数
maxLifetimeMilliseconds: 1800000 # 连接最大存活时间毫秒数
maxPoolSize: 50 # 最大连接数
minPoolSize: 1
maintenanceIntervalMilliseconds: 30000
dataSources: #数据源别名,多个往下边追加
ds_0_master_0: # ds_0_master_0, ds_0_slave_0, ds_0_slave_2 三个库实现1主2从,组成逻辑库ds_0
url: jdbc:mysql://192.168.3.12:3310/ebook0?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
ds_0_slave_0:
url: jdbc:mysql://192.168.3.12:3312/ebook0?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
ds_0_slave_1:
url: jdbc:mysql://192.168.3.12:3313/ebook0?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
ds_1: # 由 ds_0,ds_1组成分库
url: jdbc:mysql://192.168.3.12:3314/ebook1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
rules:
# 配置分片规则
- !SHARDING
tables: # 多个表就往下边追加
test: # 逻辑表的名字
actualDataNodes: ds_${0..1}.test_${0..2} # 数据源名称 `ds` 使用读写分离配置的逻辑数据源名称
tableStrategy: #分表策略
standard:
shardingColumn: created_at
shardingAlgorithmName: sharding_by_time # 使用下面分片算法中的 sharding_by_time
keyGenerateStrategy:
column: id # 分布式主键
keyGeneratorName: snowflake # SNOWFLAKE 分布式主键类型
bindingTables:
- test
#默认分库策略
defaultDatabaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database_inline
defaultTableStrategy:
none:
keyGenerators: # 分布式主键配置
snowflake:
type: SNOWFLAKE
props:
worker-id: 1
shardingAlgorithms: # 配置分片算法
database_inline:
type: INLINE
props:
algorithm-expression: ds_${id % 2}
sharding_by_time:
# 分片类型
type: auto_interval
props:
# 分片开始时间 要加""不然会被解析为非字符串类型导致拿不到值
datetime-lower: "2021-03-13 00:00:00"
# 分片秒数 这里是一天一张表 所以秒数为86400秒 要加""不然会被解析为非字符串类型导致拿不到值
sharding-seconds: "86400"
# 分片结束时间 要加""不然会被解析为非字符串类型导致拿不到值
datetime-upper: "2021-03-15 00:00:00"
# ps:测试的时候记得核对时间,避免创建数据时写不进分片
#配置读写分离规则
- !REPLICA_QUERY
dataSources:
ds_0:
name: ds_0 # 读写分离的逻辑数据源名称 `ds_0` 用于在数据分片中使用
primaryDataSourceName: ds_0_master_0 # writeDataSourceName 使用真实存在的数据源名称 `ds_0_master_0`
replicaDataSourceNames:
- ds_0_slave_0 # 使用真实存在的数据源名称 `ds_0_slave_0`
- ds_0_slave_1 # 使用真实存在的数据源名称 `ds_0_slave_1`
loadBalancerName: roundRobin
loadBalancers:
roundRobin:
type: ROUND_ROBIN
二、引入依赖
- 下载mysql驱动,并让如
ext-lib
# mysql5.7
wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar
# mysql8.0
wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.23/mysql-connector-java-8.0.23.jar
三、启动服务
- 获取
sharding-proxy v5.0.0
镜像
目前latest最新的是sharding-proxy:5.0.0-alpha
,5.x和4.x配置文件由一定改动,注意不要混用。
docker pull apache/sharding-proxy:latest
- 启动容器
docker run -d -v /Users/yw/workspace/shardingdock/conf:/opt/sharding-proxy/conf -v /Users/yw/workspace/shardingdock/ext-lib:/opt/sharding-proxy/ext-lib -e PORT=3308 -p13308:3308 apache/sharding-proxy:4.1.1
- 主要是映射
conf
和ext-lib
两个路径,conf路径必须挂载 - 可以自定义端口 3308 和 13308。3308 表示 docker 容器端口, 13308 表示宿主机端口
四、使用ShardingSphere-Proxy
- 使用laravel进行读取写入测试
修改.env
配置数据库连接sharding-proxy,13308是映射的容器内部3308端口,ebook是server.yaml
配置的逻辑数据库
DB_CONNECTION=mysql
DB_HOST=192.168.3.12
DB_PORT=13308
DB_DATABASE=ebook
DB_USERNAME=root
DB_PASSWORD=root
修改config/database.php
,关闭mysql strict模式
connections.mysql.strict => false
添加Test模型,进行测试
public function test()
{
$datetime = Carbon::now()->toDateTimeString();
for ($i = 0; $i < 10; $i++) {
Test::create(['name' => $i, 'created_at' => $datetime]);
}
$res = Test::get();
dd($res->toArray());
}
可以看到,查询结果,自动将多库多表的数据进行的聚合
- 确认数据库数据
当前时间为2021-03-13
,根据时间分片算法应该写入test_1
表
五、问题总结
- 多个库写入相同数据
错误示例:
- !SHARDING
tables: # 多个表就往下边追加
test: # 逻辑表的名字
actualDataNodes: ds_${0..1}.test_${0..2} # 数据源名称 `ds` 使用读写分离配置的逻辑数据源名称
# databaseStrategy: #分库策略 #分库策略写在这里会导致多个库插入相同的数据,而不是按策略分库插入,原因暂时不清楚
# standard:
# shardingColumn: id
# shardingAlgorithmName: ds_inline
解决:使用默认分库策略
defaultDatabaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database_inline
- 报错:invalid tag: !READ_WRITE_SPLITTING
原因:官方在线文档没更新,这种写法当场去世(下载的PDF看起来是最新的)
错误写法示例:
# - !READ_WRITE_SPLITTING
# dataSources:
# ds_0:
# name: ds_0 # 读写分离的逻辑数据源名称 `ds_0` 用于在数据分片中使用
# writeDataSourceName: ds_0_master_0 # writeDataSourceName 使用真实存在的数据源名称 `ds_0_master_0`
# readDataSourceNames: # readDataSourceNames
# - ds_0_slave_0 # 使用真实存在的数据源名称 `ds_0_slave_0`
# - ds_0_slave_1 # 使用真实存在的数据源名称 `ds_0_slave_1`
# loadBalancerName: roundRobin
# loadBalancers:
# roundRobin:
# type: ROUND_ROBIN
解决:REPLICA_QUERY标签
- 报错:Packets out of order. Expected 1 received 0. Packet size=103
原因:这里是查询带分区的表产生配置的问题
解决:修改 PDO::ATTR_EMULATE_PREPARES => true
文件所在目录:vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php