一.ShardingSphere
在介绍读写分离前,要先给介绍一下ShardingSphere。
Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。
1.ShardingSphere-JDBC
ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
2.ShardingSphere-Proxy
ShardingSphere-Proxy 定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。
客户端可以像使用MySQL一样使用ShardingSphere-Proxy,包括命令行操作和程序访问。

3.ShardingSphere-Proxy 工作原理
ShardingSphere-proxy主要的作用是转发客户端对数据库的请求,并支持数据分片功能。其工作原理如下:
|--------------------------------------------------------------------|
| 客户端发送 SQL 语句到 ShardingSphere-proxy |
| ShardingSphere-proxy 接收 SQL 语句并解析操作类型,如SELECT,INSERT,UPDATE,DELETE |
| ShardingSphere-proxy 根据操作类型和分片规则将SQL转发到底层真实的数据库节点(可能是多个) |
| 底层真实数据库节点执行 SQL 语句,并将结果返回给 ShardingSphere-proxy |
| ShardingSphere-proxy 合并不同数据节点返回的数据,并将最终结果返回给客户端 |
4.安装ShardingSphere-Proxy
1)创建Docker容器
bash
# 安装ShardingSphere镜像并启动容器
# 指定JVM参数:
# -e JJVM_OPTS="-Xms256m -Xmx256m -Xmn128m" 初始堆内存256m,量⼤堆内存256m,新⽣代内存128m
# 指定端⼝号:
# -e PORT=3308 端⼝号为3308
docker run -d \
-p 3307:3307 \
-v /shardingsphere/proxy/conf:/opt/shardingsphere-proxy/conf \
-v /shardingsphere/proxy/ext-lib:/opt/shardingsphere-proxy/ext-lib \
-v /shardingsphere/proxy/logs:/opt/shardingsphere-proxy/logs \
-e JVM_OPTS="-Xms256m -Xmx256m -Xmn128m" \
--name ss-proxy \
apache/shardingsphere-proxy:5.3.2
2)修改配置文件
将已有的conf目录下的文件复制到宿主机映射目录:
bash
cp /opt/shardingsphere-proxy/conf/server.yaml /shardingsphere/proxy/conf/server.yaml
修改 conf/server.yaml:
bash
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.38 # MySQL版本号
3)上传MySQL驱动
连接 MySQL 数据库时,需要把MySQL 驱动包放入宿主机映射扩展目录 /ext-lib 中。
下载链接:mysql-connector-j-8.0.33.jar 下载地址
4)启动
bash
# 重新启动容器
docker restart ss-proxy
# 查看状态,启动成功
docker ps
# 进入容器
docker exec -it ss-proxy env LANG=C.UTF-8 /bin/bash
5)测试

二.应用场景
读写分离是一种提高数据库性能和可扩展性的常用策略,特别是在面对高并发、大数据量的场景时。它将数据库的操作分为读(查询)和写(更新、插入、删除)两部分,使主数据库(master)处理事务性操作(增、删、改),而从数据库(slave)处理查询操作。这种技术可以分散数据库的负载,提高系统的整体性能和稳定性。
当系统负载越来越大时,I/O作为整个系统的性能瓶颈就越来越明显,大量的数据库访问可能会把某个数据节点打爆(尤其是在单台数据库服务器的情况下),通过部署读写分离可以有效的解决单点故障问题并提升系统性能。
有以下需求时可以使用读写分离架构部署数据库服务:
|---------|--------------------------------------------------------------|
| 读多写少的场景 | 很多的应用程序都是读多写少的场景,读写分离可以将读请求分散到多个从服务器上,从而减轻主服务器的负担,显著提高读操作的性能 |
| 水平扩展 | 通过增加从服务器的数量,可以进一步扩展数据库的读能力,以应对不断增长的负载 |
| 故障转移 | 在主服务器发生故障时,可以快速将读和写操作切换到从服务器,保证服务的可用性 |
| 实时备份 | 从服务器也可以作为主服务器的实时备份节点,当主服务器发生故障时,可以快速恢复数据 |
这里采用一主两从的数据库集群架构
具体怎么设置可以看这篇文章:【MySQL】主从复制-CSDN博客
首先要确定好主从服务器是正常运行的。
三.配置文件
1.配置读写分离
修改 conf/database-readwrite-splitting.yaml 配置文件:
bash
databaseName: proxy_db
dataSources:
write_ds:
url: jdbc:mysql://你的云服务器的IP地址:53306/test_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://你的云服务器的IP地址:53307/test_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://你的云服务器的IP地址:53308/test_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: weight
loadBalancers:
random:
type: RANDOM
round_robin:
type: ROUND_ROBIN
weight:
type: WEIGHT
props:
read_ds_0: 2.0
read_ds_1: 1.0
2.日志配置
新建 conf/logback.xml ,并编写以下内容:
XML
<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-MM-dd}.%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>