(升级)Sharding-JDBC 第三章 读写分离

8.读写分离

8.1 理解读写分离

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类 型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能 够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
这是单库优化遇到瓶颈之后,应该是最先使用读写分离方案,当然可以分库分表和读写分离结合
在这里插入图片描述
通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至 磁盘物理损坏的情况下仍然不影响系统的正常运行。
在这里插入图片描述
读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读
写分离联合使用,能够更加有效的提升系统的性能。
在这里插入图片描述

Sharding-JDBC读写分离则是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。它提供透明化读写分离,让使用方尽量像使用一个数据库一样使用主从数据库集群。
在这里插入图片描述
Sharding-JDBC提供一主多从的读写分离配置,可独立使用,也可配合分库分表使用,同一线程且同一数据库连接 内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。Sharding-JDBC不提供主从数据库的数据 同步功能,需要采用其他机制支持。
在这里插入图片描述
接下来,咱们对上面例子中user_db进行读写分离实现。为了实现Sharding-JDBC的读写分离,首先,要进行 mysql的主从同步配置。

8.1.mysql主从同步(windows)

一,新增mysql实例

复制原有mysql如:D:\mysql-5.7.25(作为主库) -> D:\mysql-5.7.25-s1(作为从库),并修改以下从库的my.ini:

 [mysqld]
#设置3307端口
port = 3307
# 设置mysql的安装目录 
basedir=D:\mysql‐5.7.25‐s1
# 设置mysql数据库的数据的存放目录 
datadir=D:\mysql‐5.7.25‐s1\data

然后将从库安装为windows服务,注意配置文件位置:
D:\mysql‐5.7.25‐s1\bin>mysqld install mysqls1 ‐‐defaults‐file=“D:\mysql‐5.7.25‐s1\my.ini”
由于从库是从主库复制过来的,因此里面的数据完全一致,可使用原来的账号、密码登录。

二,修改主、从库的配置文件(my.ini),新增内容如下:

主库:

[mysqld]
#开启日志
log‐bin = mysql‐bin #设置服务id,主从不能一致
server‐id = 1
#设置需要同步的数据库 
binlog‐do‐db=user_db
#屏蔽系统库同步 
binlog‐ignore‐db=mysql 
binlog‐ignore‐db=information_schema 
binlog‐ignore‐db=performance_schema

从库:

[mysqld]
#开启日志
log‐bin = mysql‐bin
#设置服务id,主从不能一致
server‐id = 2
#设置需要同步的数据库 
replicate_wild_do_table=user_db.%
#屏蔽系统库同步 
replicate_wild_ignore_table=mysql.% 
replicate_wild_ignore_table=information_schema.% 
replicate_wild_ignore_table=performance_schema.%

重启主库和从库:

net start [主库服务名]
net start [从库服务名mysqls1]

请注意,主从MySQL下的数据(data)目录下有个文件auto.cnf,文件中定义了uuid,要保证主从数据库实例的 uuid不一样,建议直接删除掉,重启服务后将会重新生成。

三,授权主从复制专用账号

#切换至主库bin目录,登录主库
mysql ‐h localhost ‐uroot ‐p
#授权主备复制专用账号
GRANT REPLICATION SLAVE ON *.* TO 'db_sync'@'%' IDENTIFIED BY 'db_sync'; #刷新权限
   FLUSH PRIVILEGES;
#确认位点 记录下文件名以及位点
show master status;

四,设置从库向主库同步数据、并检查链路

#切换至从库bin目录,登录从库
mysql ‐h localhost ‐P3307 ‐uroot ‐p #先停止同步
STOP SLAVE;
#修改从库指向到主库,使用上一步记录的文件名以及位点 CHANGE MASTER TO
    master_host = 'localhost',
    master_user = 'db_sync',
    master_password = 'db_sync',
    master_log_file = 'mysql‐bin.000002',
    master_log_pos = 154;
#启动同步
START SLAVE; 
#查看从库状态Slave_IO_Runing和Slave_SQL_Runing都为Yes说明同步成功,如果不为Yes,请检查error_log,然后 排查相关异常。
show slave status\G
#注意 如果之前此备库已有主库指向 需要先执行以下命令清空 
STOP SLAVE IO_THREAD FOR CHANNEL '';
reset slave all;

最后测试在主库修改数据库,看从库是否能够同步成功。

8.2.实现sharding-jdbc读写分离

(1)在Sharding-JDBC规则中修改

# 增加数据源s0,使用上面主从同步配置的从库。
spring.shardingsphere.datasource.names = m0,m1,m2,s0
...
spring.shardingsphere.datasource.s0.type = com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.s0.driver‐class‐name = com.mysql.jdbc.Driver spring.shardingsphere.datasource.s0.url = jdbc:mysql://localhost:3307/user_db?useUnicode=true spring.shardingsphere.datasource.s0.username = root spring.shardingsphere.datasource.s0.password = root
# 主库从库逻辑数据源定义 ds0为user_db 
spring.shardingsphere.sharding.master‐slave‐rules.ds0.master‐data‐source‐name=m0 spring.shardingsphere.sharding.master‐slave‐rules.ds0.slave‐data‐source‐names=s0
# t_user分表策略,固定分配至ds0的t_user真实表 
spring.shardingsphere.sharding.tables.t_user.actual‐data‐nodes = ds0.t_user

(2)测试

执行testInsertUser单元测试:
在这里插入图片描述
通过日志可以看出,所有写操作落入m0数据源。
执行testSelectUserbyIds单元测试:
在这里插入图片描述
为了防止主从延迟,可以使用以下语句强制路由到主库。HintManager 使用了 ThreadLocal 来保存 HintManager 实例。显然,基于这种处理方式,所有分片信息的作用范围就是当前线程。
HintManager.getInstance().setMasterRouteOnly();

(3)原理

而 ShardingSphere 专门提供了 HintShardingStrategyConfiguration 用于完成 Hint 的分片策略配置,如下面这段代码所示:

public final class HintShardingStrategyConfiguration implements ShardingStrategyConfiguration {
    private final HintShardingAlgorithm shardingAlgorithm;
    public HintShardingStrategyConfiguration(final HintShardingAlgorithm shardingAlgorithm) {
        Preconditions.checkNotNull(shardingAlgorithm, "ShardingAlgorithm is required.");
        this.shardingAlgorithm = shardingAlgorithm;
    }
}

可以看到,HintShardingStrategyConfiguration 中需要设置一个 HintShardingAlgorithm。HintShardingAlgorithm 是一个接口,我们需要提供它的实现类来根据 Hint 信息执行分片。

public interface HintShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {
    //根据Hint信息执行分片
    Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<T> shardingValue);
}

我们可以根据需要提供自己的 HintShardingAlgorithm 实现类并集成到 HintShardingStrategyConfiguration 中。例如,我们可以对比所有可用的分库分表键值,然后与传入的强制分片键进行精准匹配,从而确定目标的库表信息:

public final class MatchHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final HintShardingValue<Long> shardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String each : availableTargetNames) {
            for (Long value : shardingValue.getValues()) {
                if (each.endsWith(String.valueOf(value))) {
                    result.add(each);
                }
            }
        }
        return result;
    }
}

一旦提供了自定的 HintShardingAlgorithm 实现类,就需要将它添加到配置体系中。在这里,我们基于 Yaml 配置风格来完成这一操作:

defaultDatabaseStrategy:
    hint:
        algorithmClassName: com.tianyilan.shardingsphere.demo.hint.MatchHintShardingAlgorithm

ShardingSphere 在进行路由时,如果发现 TableRuleConfiguration 中设置了 Hint 的分片算法,就会从 HintManager 中获取分片值并进行路由操作。

基于强制路由访问目标库表

为了更好地组织代码结构,我们先来构建两个 Helper 类,一个是用于获取 DataSource 的 DataSourceHelper。在这个 Helper 类中,我们通过加载 .yaml 配置文件来完成 DataSource 的构建:

public class DataSourceHelper {
 
    static DataSource getDataSourceForShardingDatabases() throws IOException, SQLException {
       return YamlShardingDataSourceFactory.createDataSource(getFile("/META-INF/hint-databases.yaml")); 
    }
    private static File getFile(final String configFile) {
        return new File(Thread.currentThread().getClass().getResource(configFile).getFile());
    }
}

8.3 通过druid的主从库实现读写分离

大多数情况下,不建议采用sharding-jdbc进行读写分离,而是采用druid的数据库连接实现读写分离,尤其是在写延迟时,需要强制从主库读取。实践代码后续贴上来。

参考

druid和spring动态数据源实现读写分离:https://blog.csdn.net/lp19861126/article/details/84880508

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值