跳到主要内容
Apache ShardingSphere 高性能架构实践:读写分离与分片详解 | 极客日志
Java java
Apache ShardingSphere 高性能架构实践:读写分离与分片详解 综述由AI生成 MySQL 高并发场景下常面临单表性能瓶颈,需引入分布式架构优化。Apache ShardingSphere 提供了读写分离、垂直与水平分片等成熟方案。通过 Docker 部署 ShardingSphere-Proxy,可透明屏蔽底层复杂性。实战中配置主从节点、分片规则及负载均衡策略,实现数据自动路由。测试表明,该架构能有效分散压力,提升查询效率与系统扩展性,适用于大规模业务数据存储需求。
Kubernet 发布于 2026/3/16 更新于 2026/4/26 3 浏览
环境说明
MySQL 版本:8.0.44
Linux 操作系统版本:Ubuntu 24.04 LTS
Apache ShardingSphere 版本:5.3.2
JDBC 驱动程序版本:8.0.30
1. 理论 - 高性能架构模式
1.1 读写分离
将读操作和写操作分配到不同的数据库节点上,分散数据库压力。
1.2 数据分片
随着业务数据积累,单表数据量膨胀会导致 B+ 树高度增加,查询效率下降。集中式数据库在高并发下易成瓶颈,必须实施数据分片(Sharding),将数据分散存储到多个节点。
1.2.1 垂直分片
核心是按业务功能或数据属性进行纵向拆分。将一个宽表或多张表按维度拆分成不同的数据库或表组。
垂直分表
垂直分库
1.2.2 水平分片
核心是按数据记录进行横向拆分。将大表按规则(如 ID、哈希、时间)分散到多个结构相同的库或表中。
水平分库 :单表切分后若单台服务器仍无法满足性能,需将多表分散在不同服务器上。
水平分表 :将一张表的数据拆分到多张表中,尽量放在同一数据库以避免跨库事务。有效降低 B+ 树高度,减少磁盘 I/O。
1.3 读写分离和数据分片结合
2. 实践方式 - 高性能架构模式
2.1 代码封装 直接将分片逻辑写在业务代码中,侵入性强,维护困难。变更策略需修改代码并重新发布。
2.2 中间件封装 通过中间件统一管理分片逻辑,应用层无感知。
3. Apache ShardingSphere Apache ShardingSphere 是一款开源的分布式数据库解决方案,旨在不替换底层数据库的前提下,通过插件化架构增强数据处理与治理能力。目前主要提供 ShardingSphere-JDBC 和 ShardingSphere-Proxy 两款产品。
3.1 ShardingSphere-JDBC 定位为轻量级 Java 框架,在 JDBC 层提供额外服务。
3.2 ShardingSphere-Proxy 定位为独立的透明化数据库代理服务。通过原生实现数据库二进制网络协议,屏蔽后端集群复杂性,为客户端提供统一入口(支持多种语言)。可理解为'数据库网关',应用程序像操作普通 MySQL 一样操作它,分布式逻辑由 Proxy 内部处理。
客户端发送 SQL 到 ShardingSphere-Proxy。
Proxy 解析 SQL 类型(select, insert 等)。
路由引擎根据分片规则计算目标物理分片。
转发至底层真实数据库执行,返回结果。
Proxy 合并数据并返回给客户端。
3.3 Docker 安装 ShardingSphere-Proxy
3.3.1 创建 Docker 容器
docker run -d \
-p 3307:3307 \
-v /org/shardingsphere/proxy/conf:/opt/shardingsphere-proxy/conf \
-v /org/shardingsphere/proxy/ext-lib:/opt/shardingsphere-proxy/ext-lib \
-v /org/shardingsphere/proxy/logs:/opt/shardingsphere-proxy/logs \
-e JVM_OPTS="-Xms256m -Xmx256m -Xmn128m" \
--name ss-proxy \
apache/shardingsphere-proxy:5.3.2
创建后需在 conf 和 ext-lib 目录下添加配置文件(yaml)和驱动包(jar)。建议从官网下载二进制包提取配置,避免手动编写。
3.3.2 配置 server.yaml 在 conf 目录下配置 server.yaml:
mode:
type: Standalone
authority:
users:
- root@%:
password: 123456
privilege:
type: ALL_PERMITTED
props:
sql-show: true
proxy-mysql-default-version: 8.0 .44
3.3.3 上传 MySQL 驱动
3.3.4 日志配置 在 conf 目录下配置 logback.xml:
<?xml version="1.0" ?>
<configuration >
<appender name ="SHARDING_FILE" class ="ch.qos.logback.core.rolling.RollingFileAppender" >
<file > ./logs/shardingsphere.log</file >
<encoder >
<pattern > [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern >
</encoder >
<rollingPolicy class ="ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
<fileNamePattern > shardingsphere.%d{yyyy-MMdd}.%i.log</fileNamePattern >
<timeBasedFileNamingAndTriggeringPolicy class ="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
<maxFileSize > 100MB</maxFileSize >
</timeBasedFileNamingAndTriggeringPolicy >
</rollingPolicy >
</appender >
<root level ="INFO" >
<appender-ref ref ="SHARDING_FILE" />
</root >
</configuration >
3.3.5 测试连接
docker restart ss-proxy
docker ps
mysql -h 127.0.0.1 -P 3307 -u root -p123456
4. 实践 - 读写分离
4.1 架构图
4.2 服务器规划 数据库服务器 容器名 端口号 主服务器 org-mysql-master 53306 从服务器 1 org-mysql-slave1 53307 从服务器 2 org-mysql-slave2 53308
4.3 创建数据库服务器 参考相关文档创建一个主服务器和两个从服务器,并开启主从复制。
4.4 配置读写分离 在 /org/shardingsphere/proxy/conf 目录下配置 config-readwrite-splitting.yaml:
databaseName: org_proxy_db
dataSources:
write_ds:
url: jdbc:mysql://YOUR_IP_ADDRESS:53306/org_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
read_ds_0:
url: jdbc:mysql://YOUR_IP_ADDRESS:53306/org_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
read_ds_1:
url: jdbc:mysql://YOUR_IP_ADDRESS:53306/org_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
staticStrategy:
writeDataSourceName: write_ds
readDataSourceNames:
- read_ds_0
- read_ds_1
loadBalancerName: random
loadBalancers:
random:
type: RANDOM
round_robin:
type: ROUND_ROBIN
weight:
type: WEIGHT
props:
read_ds_0: 2.0
read_ds_1: 1.0
4.5 启动 ShardingSphere
docker start ss-proxy
docker ps
mysql -h 127.0.0.1 -P 3307 -u root -p
4.6 测试
docker exec -it ss-proxy env LANG=C.UTF-8 /bin/bash
tail -f /opt/shardingsphere-proxy/logs/shardingsphere.log
查看日志输出确认路由情况。
注意:如果在事务中查询数据,所有 SQL 操作都会被路由到主服务器,避免跨库事务问题。
mysql> use org_proxy_db;
Database changed
mysql> INSERT INTO t_user VALUES (1 ,'张三' ),(2 ,'李四' ),(3 ,'王五' );
Query OK, 3 rows affected (0.01 sec)
mysql> SELECT * FROM t_user;
+
| id | name |
+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+
3 rows in set (0.01 sec)
mysql> SELECT * FROM t_user;
+
| id | name |
+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+
3 rows in set (0.01 sec)
5. 实践 - 垂直分片
5.1 架构图
5.2 服务器规划 数据库服务器 容器名 端口号 用户服务器 server-user 53310 订单服务器 server-order 53311
5.3 创建 server-user 容器 CREATE DATABASE IF NOT EXISTS user_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE user_db;
CREATE TABLE IF NOT EXISTS t_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (20 )
);
docker exec -it server-user env LANG=C.UTF-8 /bin/bash
mysql -uroot -p
SET PASSWORD = '123456' ;
docker run -d \
-p 53310:3306 \
-v /org/mysql/user/conf:/etc/mysql/conf.d \
-v /org/mysql/user/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-user \
mysql:8.0.44
5.4 创建 server-order 容器 CREATE DATABASE IF NOT EXISTS order_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE order_db;
CREATE TABLE IF NOT EXISTS t_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR (30 ) COMMENT '订单号' ,
amount DECIMAL (12 ,2 ) COMMENT '订单金额' ,
user_id BIGINT COMMENT '用户编号'
);
docker exec -it server-order env LANG=C.UTF-8 /bin/bash
mysql -uroot -p
SET PASSWORD = '123456' ;
docker run -d \
-p 53311:3306 \
-v /org/mysql/order/conf:/etc/mysql/conf.d \
-v /org/mysql/order/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order \
mysql:8.0.44
5.5 垂直分库配置 在 /org/shardingsphere/proxy/conf 目录下配置 config-sharding.yaml:
databaseName: sharding_db
dataSources:
server_user:
url: jdbc:mysql://YOUR_IP_ADDRESS:53310/user_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
server_order:
url: jdbc:mysql://YOUR_IP_ADDRESS:53311/order_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHARDING
tables:
t_user:
actualDataNodes: server_user.t_user
t_order:
actualDataNodes: server_order.t_order
5.6 启动 ShardingSphere docker start ss-proxy
docker ps
mysql -h 127.0.0.1 -P 3307 -u root -p
6. 实践 - 水平分片
6.1 架构图 水平分库 + 水平分表
6.2 服务器规划 数据库服务器 容器名 端口号 订单服务器 server-order0 63310 订单服务器 server-order1 63311
6.3 创建 server-order 容器
docker run -d \
-p 63310:3306 \
-v /org/mysql/order0/conf:/etc/mysql/conf.d \
-v /org/mysql/order0/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order0 \
--restart always \
mysql:8.0.44
docker run -d \
-p 63311:3306 \
-v /org/mysql/order1/conf:/etc/mysql/conf.d \
-v /org/mysql/order1/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order1 \
--restart always \
mysql:8.0.44
6.4 进入 Docker 容器 docker exec -it server-order0 env LANG=C.UTF-8 /bin/bash
mysql -uroot -p
SET PASSWORD = '123456' ;
6.5 创建数据库 CREATE DATABASE IF NOT EXISTS order_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE order_db;
CREATE TABLE IF NOT EXISTS t_order0 (
id BIGINT PRIMARY KEY ,
order_no VARCHAR (30 ) COMMENT '订单号' ,
amount DECIMAL (12 ,2 ) COMMENT '订单金额' ,
user_id BIGINT COMMENT '用户编号'
);
CREATE TABLE IF NOT EXISTS t_order1 (
id BIGINT PRIMARY KEY ,
order_no VARCHAR (30 ) COMMENT '订单号' ,
amount DECIMAL (12 ,2 ) COMMENT '订单金额' ,
user_id BIGINT COMMENT '用户编号'
);
6.6 水平分片配置 databaseName: sharding_db
dataSources:
server_order0:
url: jdbc:mysql://81.69.218.112:63310/order_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
server_order1:
url: jdbc:mysql://81.69.218.112:63311/order_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: server_order${0..1}.t_order${0..1}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: alg_db_inline_userid
tableStrategy:
standard:
shardingColumn: order_no
shardingAlgorithmName: alg_hash_mod
shardingAlgorithms:
alg_db_inline_userid:
type: INLINE
props:
algorithm-expression: server_order${user_id % 2 }
alg_hash_mod:
type: HASH_MOD
props:
sharding-count: 2
6.7 启动 ShardingSphere docker start ss-proxy
docker ps
mysql -h 127.0.0.1 -P 3307 -u root -p
6.8 测试 docker exec -it ss-proxy env LANG=C.UTF-8 /bin/bash
tail -f /opt/shardingsphere-proxy/logs/shardingsphere.log
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (1 ,'BIT001' ,1 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (2 ,'BIT002' ,1 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (3 ,'BIT003' ,1 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (4 ,'BIT004' ,1 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (1 ,'BIT001' ,2 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (2 ,'BIT002' ,2 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (3 ,'BIT003' ,2 ,20.00 );
INSERT INTO t_order (id, order_no, user_id, amount) VALUES (4 ,'BIT004' ,2 ,20.00 );
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online