深入解析 MySQL:基于 Apache ShardingSphere 的高性能架构详解
基于 Apache ShardingSphere 实现 MySQL 高性能架构方案。涵盖读写分离、垂直与水平分片理论及实践。通过 Docker 部署 ShardingSphere-Proxy,配置主从复制与分片规则,演示分布式环境下的数据库连接管理与数据路由。包含环境搭建、配置文件编写、SQL 测试验证等步骤,帮助开发者理解分库分表策略落地方式。

基于 Apache ShardingSphere 实现 MySQL 高性能架构方案。涵盖读写分离、垂直与水平分片理论及实践。通过 Docker 部署 ShardingSphere-Proxy,配置主从复制与分片规则,演示分布式环境下的数据库连接管理与数据路由。包含环境搭建、配置文件编写、SQL 测试验证等步骤,帮助开发者理解分库分表策略落地方式。

将读操作和写操作分配到不同的数据库节点上,分散数据库读写操作的压力。
单机架构与读写分离架构的区别演示
![架构图]
在关系型数据库中,索引普遍采用 B+ 树结构。随着业务数据不断积累,单表数据量膨胀会导致 B+ 树高度增加,每次查询需要更多的磁盘 I/O,严重拖慢查询效率。此外,集中式数据库在高并发场景下容易成为系统瓶颈。为解决性能与扩展性问题,必须实施数据分片 (Sharding),将数据分散存储到多个数据库节点。
垂直分片的核心是按业务功能或数据属性进行纵向拆分。它将一个包含多个字段的'宽表'或一个包含多张表的数据库,按照功能模块、访问频率、数据类型等维度,拆分成不同的数据库或表组。
垂直分表
![垂直分表示意图]
垂直分库
![垂直分库示意图]
水平分片的核心是按数据记录进行横向拆分。它将单张数据量过大的表,按照某种规则 (如 ID 范围、哈希值、时间等) 将数据行分散存储到多个结构相同的数据库或表中。
水平分库:如果单表切分之后,单台服务器依然无法满足数据库性能要求,那么就需要将多个表分散在不同的数据库服务器上。
![水平分库示意图]
水平分表:将原来一张表中的数据根据某种规则拆分到多个表中,将拆分出的多张表尽量放在同一个数据库,主要是避免跨库事务。水平分表后会有效降低 B+ 树高度,从而减少磁盘 I/O。
![水平分表示意图]
![组合架构图]
![代码封装图]
![中间件封装图]
Apache ShardingSphere 是一款开源的分布式数据库解决方案,旨在不替换底层数据库的前提下,通过插件化架构增强其数据处理与治理能力。截止 2026 年 1 月,它一共推出 ShardingSphere-JDBC 和 ShardingSphere-Proxy 两款产品,分别面向不同的部署与使用场景。
定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
![JDBC 架构图]
定位为独立的透明化数据库代理服务。它通过原生实现数据库二进制网络协议,屏蔽了后端数据库集群的复杂性,为所有客户端提供一个统一的、标准的数据库访问入口 (支持多种语言)。简单来说,可以将 ShardingSphere-Proxy 理解为一个'数据库网关'。应用程序和 DBA 像操作一个普通的、单点的 MySQL 服务器一样去操作它,而背后所有的数据分片、路由等分布式逻辑,则由 Proxy 完全在内部处理并隐藏。
![Proxy 架构图]
工作原理:
![工作流程图]
# JVM_OPTS="-Xms256m -Xmx256m -Xmn128m"
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)。可以从 Apache ShardingSphere 官网下载二进制包,然后提取出配置文件,避免手动创建配置文件。
在 conf 目录下配置 server.yaml。
mode:
type: Standalone # 单机模式
authority:
users:
- user: root@% # 配置一个用户,用户名为 root@%
password: 123456 # 为用户指定密码
privilege:
type: ALL_PERMITTED # 授予用户所有权限
props:
sql-show: true # 显示执行的 SQL 语句
proxy-mysql-default-version: 8.0.44 # MySQL 版本号
ShardingSphere-Proxy 数据库代理服务连接 MySQL 数据库时,需要把 MySQL 驱动包放入宿主机映射扩展目录 /ext-lib 中。
在 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"/>
# 重新启动容器
docker restart ss-proxy
# 查看状态,启动成功
docker ps
# 指定主机和端口号进行连接
mysql -h 127.0.0.1 -P 3307 -u root -p123456
![读写分离架构图]
| 数据库服务器 | 容器名 | 端口号 |
|---|---|---|
| 主服务器 | org-mysql-master | 53306 |
| 从服务器 1 | org-mysql-slave1 | 53307 |
| 从服务器 2 | org-mysql-slave2 | 53308 |
创建一个主服务器和两个从服务器,并开启主从复制。
在 /org/shardingsphere/proxy/conf 目录下配置 config-readwrite-splitting.yaml 文件。
databaseName: org_proxy_db # shardingsphere 中代理的库名
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
# 启动容器
docker start ss-proxy
# 查看容器是否启动成功
docker ps
# 连接 ShardingSphere
mysql -h 127.0.0.1 -P 3307 -u root -p
# 进入容器
docker exec -it ss-proxy env LANG=C.UTF-8 /bin/bash
# 查看 ShardingSphere 的实时日志,以实际目录和文件名为准
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 | 张三 |
李四
王五
( sec)
![垂直分片架构图]
| 数据库服务器 | 容器名 | 端口号 |
|---|---|---|
| 用户服务器 | server-user | 53310 |
| 订单服务器 | server-order | 53311 |
创建数据库:
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 容器:
# 进入 Docker 容器
docker exec -it server-user env LANG=C.UTF-8 /bin/bash
# 运行 Mysql 客户端
mysql -uroot -p
# 修改密码
SET PASSWORD = '123456';
创建 server-user 容器:
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
创建数据库:
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 容器:
# 进入 Docker 容器
docker exec -it server-order env LANG=C.UTF-8 /bin/bash
# 运行 Mysql 客户端
mysql -uroot -p
# 修改密码
SET PASSWORD = '123456';
创建 server-order 容器:
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
在 /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
# 启动容器
docker start ss-proxy
# 查看容器是否启动成功
docker ps
# 连接 ShardingSphere
mysql -h 127.0.0.1 -P 3307 -u root -p
水平分库 + 水平分表
![水平分片架构图]
| 数据库服务器 | 容器名 | 端口号 |
|---|---|---|
| 订单服务器 | server-order0 | 63310 |
| 订单服务器 | server-order1 | 63311 |
# 创建 server-order0
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
# 创建 server-order1
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
# 进入 Docker 容器
docker exec -it server-order0 env LANG=C.UTF-8 /bin/bash
# docker exec -it server-order1 env LANG=C.UTF-8 /bin/bash
# 运行 Mysql 客户端
mysql -uroot -p
# 修改 root 用户密码
SET PASSWORD = '123456';
-- 在两个 Docker 容器都执行相同的 SQL 语句
CREATE DATABASE IF NOT EXISTS order_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE order_db;
-- 创建订单表 t_order0
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 '用户编号'
);
-- 创建订单表 t_order1
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 '用户编号'
);
databaseName: sharding_db
dataSources:
server_order0:
url: jdbc:mysql://YOUR_IP_ADDRESS: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://YOUR_IP_ADDRESS: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
# 启动容器
docker start ss-proxy
# 查看容器是否启动成功
docker ps
# 连接 ShardingSphere
mysql -h 127.0.0.1 -P 3307 -u root -p
# 进入容器
docker exec -it ss-proxy env LANG=C.UTF-8 /bin/bash
# 查看 ShardingSphere 的实时日志,以实际目录和文件名为准
tail -f /opt/shardingsphere-proxy/logs/shardingsphere.log
-- 路由到 server-order1
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);
-- 路由到 server-order0
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);
-- 验证数据分布
SELECT t_order;
至此,基于 ShardingSphere 的水平分片读写测试完成。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online