深入解析MySQL(10)——基于Apache ShardingSphere的高性能架构详解

深入解析MySQL(10)——基于Apache ShardingSphere的高性能架构详解
在这里插入图片描述

🔥我的主页:九转苍翎⭐️个人专栏:《Java SE 》《Java集合框架系统精讲》《MySQL高手之路:从基础到高阶 》《计算机网络 》《Java工程师核心能力体系构建》天行健,君子以自强不息。


MySQL版本:8.0.44
Linux操作系统版本:Ubuntu 24.04 LTS
Apache ShardingSphere版本:5.3.2
(已免费上传至我的资源)
JDBC驱动程序版本:8.0.30(已免费上传至我的资源)

1.理论 - 高性能架构模式

1.1 读写分离

读操作写操作分配到不同的数据库节点上,分散数据库读写操作的压力

在这里插入图片描述

单机架构读写分离架构的区别演示

在这里插入图片描述

1.2 数据分片

在关系型数据库中,索引普遍采用 B+ 树结构。随着业务数据不断积累,单表数据量膨胀会导致 B+ 树高度增加,每次查询需要更多的磁盘 I/O,严重拖慢查询效率。此外,集中式数据库在高并发场景下容易成为系统瓶颈。为解决性能与扩展性问题,必须实施数据分片(Sharding),将数据分散存储到多个数据库节点

1.2.1 垂直分片

垂直分片的核心是按业务功能或数据属性进行纵向拆分。它将一个包含多个字段的“宽表”或一个包含多张表的数据库,按照功能模块、访问频率、数据类型等维度,拆分成不同的数据库或表组

垂直分表

在这里插入图片描述


在这里插入图片描述

垂直分库

在这里插入图片描述

1.2.2 水平分片

水平分片的核心是按数据记录进行横向拆分。它将单张数据量过大的表,按照某种规则(如ID范围、哈希值、时间等)将数据行分散存储到多个结构相同的数据库或表中

水平分库:如果单表切分之后,单台服务器依然无法满足数据库性能要求,那么就需要将多个表分散在不同的数据库服务器上

在这里插入图片描述

水平分表:将原来一张表中的数据根据某种规则拆分到多个表中,将拆分出的多张表尽量放在同一个数据库,主要是避免跨库事务。水平分表后会有效降低 B+ 树高度,从而减少磁盘 I/O

在这里插入图片描述


在这里插入图片描述

1.3 读写分离和数据分片

在这里插入图片描述

2.实践方式 - 高性能架构模式

2.1 代码封装

在这里插入图片描述
  • 代码侵入性强:分片逻辑与业务代码深度耦合
  • 维护困难:分片逻辑散落在代码各处,难以统一管理。变更分片策略需要修改代码并重新发布

2.2 中间件封装

在这里插入图片描述

3.Apache ShardingSphere

Apache ShardingSphere 是一款开源的分布式数据库解决方案,旨在不替换底层数据库的前提下,通过插件化架构增强其数据处理与治理能力。截止2026年1月,它一共推出ShardingSphere-JDBCShardingSphere-Proxy两款产品,分别面向不同的部署与使用场景

3.1 ShardingSphere-JDBC(了解)

定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务
在这里插入图片描述

3.2 ShardingSphere-Proxy

定位为独立的透明化数据库代理服务。它通过原生实现数据库二进制网络协议,屏蔽了后端数据库集群的复杂性,为所有客户端提供一个统一的、标准的数据库访问入口(支持多种语言)简单来说,可以将 ShardingSphere-Proxy 理解为一个“数据库网关”。 应用程序和DBA像操作一个普通的、单点的MySQL服务器一样去操作它,而背后所有的数据分片、路由等分布式逻辑,则由Proxy完全在内部处理并隐藏
在这里插入图片描述


工作原理

  1. 客户端发送 SQL 语句到 ShardingSphere-proxy。
  2. ShardingSphere-proxy 接收 SQL 语句并解析操作类型,如select,insert,update,delete
  3. 基于操作类型、分片规则等条件,路由引擎会进行精准计算,确定该条 SQL 需要访问的具体物理分片(转发到底层真实的数据库节点)
  4. 底层真实数据库节点执行 SQL 语句,并将结果返回给 ShardingSphere-proxy。

ShardingSphere-proxy 合并不同数据节点返回的数据,并将最终结果返回给客户端

在这里插入图片描述

3.3 Dokcer安装ShardingSphere-Proxy

3.3.1 创建Docker容器

# -e JJVM_OPTS="-Xms256m -Xmx256m -Xmn128m" # 初始堆内存256m,量大堆内存256m,新生代内存128mdocker run -d\-p3307: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 \-eJVM_OPTS="-Xms256m -Xmx256m -Xmn128m"\--name ss-proxy \ apache/shardingsphere-proxy:5.3.2 

创建容器后还需要在confext-lib目录下添加配置文件(yaml)和驱动程序(jar)。可以从Apache ShardingSphere官网下载二进制包,然后提取出配置文件,避免手动创建配置文件

在这里插入图片描述

下载链接ShardingSphere-Proxy 二进制包

在这里插入图片描述

3.3.2 配置server.yaml

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版本号

3.3.3 上传MySQL驱动

ShardingSphere-Proxy 数据库代理服务连接 MySQL 数据库时,需要把 MySQL 驱动包放入宿主机映射扩展目录/ext-lib

3.3.4 日志配置

conf目录下配置logback.xml

<?xml version="1.0"?><configuration><!-- 日志输入到文件 --><appendername="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><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>shardingsphere.%d{yyyy-MMdd}.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy></appender><rootlevel="INFO"><appender-refref="SHARDING_FILE"/></root></configuration>

3.3.5 测试连接

# 重新启动容器docker restart ss-proxy # 查看状态,启动成功dockerps# 指定主机和端口号进行连接 mysql -h127.0.0.1-P3307-uroot-p123456

4.实践 - 读写分离

4.1 架构图

在这里插入图片描述

4.2 服务器规划

在这里插入图片描述
数据库服务器容器名端口号
主服务器org-mysql-master53306
从服务器1org-mysql-slave153307
从服务器2org-mysql-slave253308

4.3 创建数据库服务器

参考深入解析MySQL(9)——主从复制架构详解创建一个主服务器和两个从服务器,并开启主从复制

4.4 配置读写分离

/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=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1read_ds_0:# 从节点,读服务器url: jdbc:mysql://YOUR_IP_ADDRESS:53306/org_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1read_ds_1:# 从节点,读服务器url: jdbc:mysql://YOUR_IP_ADDRESS:53306/org_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1rules:-!READWRITE_SPLITTING# 读写分离dataSources:readwrite_ds:staticStrategy:writeDataSourceName: write_ds readDataSourceNames:- read_ds_0 - read_ds_1 loadBalancerName: random # 负载均衡策略名,必须与下面配置的名字一致loadBalancers:# 分别为不的同负载均衡策略指定内置的类型random:# 随机,与上面的负载均衡策略名对应type: RANDOM # 内置类型, 固定为RANDOMround_robin:# 轮询type: ROUND_ROBIN # 固定为ROUND_ROBINweight:# 权重type: WEIGHT # 固定为WEIGHTprops:read_ds_0:2.0read_ds_1:1.0

4.5 启动ShardinSphere

# 启动容器docker start ss-proxy # 查看容器是否启动成功dockerps# 连接ShardinSphere mysql -h127.0.0.1-P3307-uroot-p

4.6 测试

# 进入容器dockerexec-it ss-proxy envLANG=C.UTF-8 /bin/bash # 查看ShardingSphere的实时日志,以实际目录和文件名为准tail-f /opt/shardingsphere-proxy/logs/shardingsphere.log 

查看日志

在这里插入图片描述
如果在事务中查询数据,所有的SQL操作都会被路由到主服务器,避免跨库事务

操作数据库

mysql>use org_proxy_db;Database changed mysql>insertinto t_user values(1,'张三'),(2,'李四'),(3,'王五'); Query OK,3rows affected (0.01 sec) mysql>select*from t_user;+----+--------+| id | name |+----+--------+|1| 张三 ||2| 李四 ||3| 王五 |+----+--------+3rowsinset(0.01 sec) mysql>select*from t_user;+----+--------+| id | name |+----+--------+|1| 张三 ||2| 李四 ||3| 王五 |+----+--------+3rowsinset(0.01 sec)

5.实践 - 垂直分片

5.1 架构图

在这里插入图片描述

5.2 服务器规划

在这里插入图片描述
数据库服务器容器名端口号
用户服务器server-user53310
订单服务器server-order53311

5.3 创建server-user容器

创建数据库

createdatabaseifnotexists user_db characterset utf8mb4 collate utf8mb4_0900_ai_ci;-- 选择数据库use user_db;-- 创建用户表createtableifnotexists t_user ( id bigintprimarykeyauto_increment, name varchar(20));

进入Docker容器

# 进入Docker容器 root@VM-0-7-ubuntu:~# docker exec -it server-user env LANG=C.UTF-8 /bin/bash# 运行Mysql客户端 bash-5.1# mysql -uroot -p
# 修改密码 mysql>set password ='123456';

创建server-user容器

docker run -d\-p53310:3306 \-v /org/mysql/user/conf:/etc/mysql/conf.d \-v /org/mysql/user/mysql:/var/lib/mysql \-eMYSQL_ROOT_PASSWORD=123456\--name server-user \ mysql:8.0.44 

5.4 创建server-order容器

创建数据库

createdatabaseifnotexists order_db characterset utf8mb4 collate utf8mb4_0900_ai_ci;-- 选择数据库use order_db;-- 创建订单表createtableifnotexists t_order ( id bigintprimarykeyauto_increment, order_no varchar(30)comment'订单号', amount decimal(12,2)comment'订单金额', user_id bigintcomment'用户编号');

进入Docker容器

# 进入Docker容器 root@VM-0-7-ubuntu:~# docker exec -it server-order env LANG=C.UTF-8 /bin/bash# 运行Mysql客户端 bash-5.1# mysql -uroot -p
# 修改密码 mysql>set password ='123456';

创建server-order容器

docker run -d\-p53311:3306 \-v /org/mysql/order/conf:/etc/mysql/conf.d \-v /org/mysql/order/mysql:/var/lib/mysql \-eMYSQL_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=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1server_order:url: jdbc:mysql://YOUR_IP_ADDRESS:53311/order_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1rules:-!SHARDINGtables:t_user:actualDataNodes: server_user.t_user t_order:actualDataNodes: server_order.t_order 

5.6 启动ShardinSphere

# 启动容器docker start ss-proxy # 查看容器是否启动成功dockerps# 连接ShardinSphere mysql -h127.0.0.1-P3307-uroot-p

6.实践 - 水平分片

6.1 架构图

水平分库 + 水平分表

在这里插入图片描述

6.2 服务器规划

在这里插入图片描述
数据库服务器容器名端口号
订单服务器server-order063310
订单服务器server-order163311

6.3 创建server-order容器

# 创建server-order0docker run -d\-p63310:3306 \-v /org/mysql/order0/conf:/etc/mysql/conf.d \-v /org/mysql/order0/mysql:/var/lib/mysql \-eMYSQL_ROOT_PASSWORD=123456\--name server-order0 \--restart always \ mysql:8.0.44 # 创建server-order1docker run -d\-p63311:3306 \-v /org/mysql/order1/conf:/etc/mysql/conf.d \-v /org/mysql/order1/mysql:/var/lib/mysql \-eMYSQL_ROOT_PASSWORD=123456\--name server-order1 \--restart always \ mysql:8.0.44 

6.4 进入Docker容器

# 进入Docker容器dockerexec-it server-order0 envLANG=C.UTF-8 /bin/bash # docker exec -it server-order1 env LANG=C.UTF-8 /bin/bash# 运行Mysql客户端 mysql -uroot-p
# 修改root用户密码 mysql>set password ='123456';

6.5 创建数据库

-- 在两个Docker容器都执行相同的SQL语句createdatabaseifnotexists order_db characterset utf8mb4 collate utf8mb4_0900_ai_ci;-- 选择数据库use order_db;-- 创建订单表t_order0createtableifnotexists t_order0 ( id bigintprimarykey, order_no varchar(30)comment'订单号', amount decimal(12,2)comment'订单金额', user_id bigintcomment'用户编号');-- 创建订单表t_order1createtableifnotexists t_order1 ( id bigintprimarykey, order_no varchar(30)comment'订单号', amount decimal(12,2)comment'订单金额', user_id bigintcomment'用户编号');

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=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1server_order1:url: jdbc:mysql://81.69.218.112:63311/order_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=falseusername: root password:123456connectionTimeoutMilliseconds:30000idleTimeoutMilliseconds:60000maxLifetimeMilliseconds:1800000maxPoolSize:50minPoolSize:1rules:-!SHARDINGtables: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}# 分片算法,根据user_id对2取模 alg_hash_mod:type: HASH_MOD props:sharding-count:2

6.7 启动ShardinSphere

# 启动容器docker start ss-proxy # 查看容器是否启动成功dockerps# 连接ShardinSphere mysql -h127.0.0.1-P3307-uroot-p

6.8 测试

# 进入容器dockerexec-it ss-proxy envLANG=C.UTF-8 /bin/bash # 查看ShardingSphere的实时日志,以实际目录和文件名为准tail-f /opt/shardingsphere-proxy/logs/shardingsphere.log 
-- 路由到 server-order1insertinto t_order (id, order_no, user_id, amount)values(1,'BIT001',1,20.00);insertinto t_order (id, order_no, user_id, amount)values(2,'BIT002',1,20.00);insertinto t_order (id, order_no, user_id, amount)values(3,'BIT003',1,20.00);insertinto t_order (id, order_no, user_id, amount)values(4,'BIT004',1,20.00);-- 路由到 server-order0insertinto t_order (id, order_no, user_id, amount)values(1,'BIT001',2,20.00);insertinto t_order (id, order_no, user_id, amount)values(2,'BIT002',2,20.00);insertinto t_order (id, order_no, user_id, amount)values(3,'BIT003',2,20.00);insertinto t_order (id, order_no, user_id, amount)values(4,'BIT004',2,20.00);

Read more

实战指南:利用jsEncrypter插件突破前端加密测试瓶颈

1. 为什么前端加密会成为测试的“拦路虎”? 如果你做过Web安全测试,尤其是登录、注册、支付这类涉及敏感数据交互的功能点,那你一定遇到过这种情况:用BurpSuite抓到的请求包,里面的密码、验证码、身份证号等关键字段,是一长串完全看不懂的乱码。你精心准备的测试用例,比如尝试输入admin' or '1'='1,结果到了服务器端,收到的却是类似aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789+/==这样的密文。这还怎么测?SQL注入、XSS、越权这些攻击手法,在密文面前全都失效了。 这就是前端加密给我们测试人员带来的核心挑战。它的初衷是好的,为了保护数据在传输过程中的安全,防止被中间人窃听。但对于安全测试而言,它就像给测试目标穿上了一层“加密盔甲”,我们的“测试矛”直接戳上去,毫无反应。传统的手工测试和自动化脚本,在加密字段面前都束手无策。你总不能每次都去猜加密算法和密钥吧?那效率太低了。 我刚开始遇到这个问题时也很头疼,尝试过各种笨办法。比如,手动在浏览器控制台里执行加密函数,把测试载荷加密后再粘贴到BurpSuite里重放。

By Ne0inhk
【年终总结】从非科班无实习到准字节前端:我始终相信,开发之外的事,才是破局关键

【年终总结】从非科班无实习到准字节前端:我始终相信,开发之外的事,才是破局关键

目录 【年终总结】从非科班无实习到准字节前端:我始终相信,开发之外的事,才是破局关键 一、求其外,善其内 1、坚持出发点正确的博文写作 2、博文更新对我心态的淬炼 3、社区交流对我视野的启发 4、向外拓展,反哺内修 二、陷入前端则前端死,跳出前端则前端活 1、从不务正业到泛前端 2、从泛前端到大前端,从有形到无形 三、秋招多少事 四、结语         作者:watermelo37         ZEEKLOG优质创作者、华为云云享专家、阿里云专家博主、腾讯云“创作之星”特邀作者、火山KOL、支付宝合作作者,全平台博客昵称watermelo37。         一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。 --------------------------------------------------------------------- 温柔地对待温柔的人,包容的三观就是最大的温柔。

By Ne0inhk
前端真的能防录屏?EME(加密媒体扩展) DRM 反录屏原理 + 实战代码

前端真的能防录屏?EME(加密媒体扩展) DRM 反录屏原理 + 实战代码

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战 🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解 🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用 🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例 ✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧 💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程 🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整 👍《Spring Security》专栏中我们将逐步深入Spring Security的各个

By Ne0inhk

Flutter 三方库 xpath_selector 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、透明、精准的 HTML/XML 数据抓取与 Web 结构解析引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 xpath_selector 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、透明、精准的 HTML/XML 数据抓取与 Web 结构解析引擎 在鸿蒙(OpenHarmony)系统的网络爬虫、自动化测试审计、或者是从复杂的第三方 Web 公告(HTML)中提取关键数据(如新闻标题、资产负债表)时,如何摆脱凌乱的正向正则(Regex),转而使用业界标准的 XPath 语法进行语义化选取?xpath_selector 为开发者提供了一套工业级的、基于 Dart 的 HTML/XML 结构化查询方案。本文将深入实战其在鸿蒙端数据治理中的应用。 前言 什么是 XPath Selector?

By Ne0inhk