找回密码
 立即注册
首页 业界区 安全 SpringCloud进阶--MySQL主从复制、分库分表、读写分离的 ...

SpringCloud进阶--MySQL主从复制、分库分表、读写分离的实现

表弊捞 6 小时前
MySQL与分布式

主从复制

其思路和redis的主从复制思路相似,也是采用增量复制的方式。
MySQL在运行过程中,会记录二进制日志,所有的DML和DDL操作都会被记录到日志中,主库将操作记录复制给从库,从库也运行一次,就实现了主从复制。注意:它不会再一开始进行全量复制,所以最好在开始主从之前将数据库的内容保持一致。
主从复制模式下,主库挂掉,从库也能正常提供服务,并且还可以实现读写分离操作。
这里使用两台主机搭建一主一:

  • 先在主库创建账号:
create user test identified with mysql_native_password by '123456'

  • 开启外网访问:
sudo vim /etc/mysql/mysql.conf.d/mysqld.cof

  • 修改配置文件:
注释掉 bind-address = 127.0.0.1
注释掉  mysqlx-bind-address = 127.0.0.1
然后重启MySQL服务。

  • 配置主库,给刚才创建的用户分配一个主从复制的权限即可:
  1. grant replication slave on *.* to test;flush privileges;
复制代码
这时主库就搭建完成了,然后开始进行从库配置

  • 配置从库配置文件:
  1. # 这里需要将server-id配置为其他的值(默认1),所有MySQL主从实例的id必须唯一!,不然会开启失败server-id  = 2
复制代码

  • 进入数据库,输入:
  1. change replication source to SOURCE_HOST='192.168.0.8',SOURCE_USER='test',SOURCE_PASSWORD='123456',SOURCE_LOG_FILE='BINLOG.000004',SOURCE_LOG_POS=591;
复制代码
SOURCE_HOST -- 主库地址
SOURCE_LOG_FILE-- 二进制日志,就是主库的日志文件(在主库输入 show master status 可以查到)
SOURCE_LOG_POS -- 日志的偏移地址(在主库输入 show master status 可以查到)

  • 执行完后输入start replica;
这时从库就启动了!
输入show replica status\G;

最关键的就是Replica_IO_Running和Replica_SQL_Running必须同时为yes才可以!
实际上从库会创建2个线程,一个线程复制与主库进行通信,获取二进制日志,暂时存放到一个中间表(Relay_Log)中,另一个线程将中间表保存的二进制日志信息进程执行,然后插入到从库中。
此时就配置完成了。在主库创建一个数据库,从库就会跟着创建一个数据库.
那要是主库挂了会怎么样?
这时IO线程处于重连状态,等待主库恢复运行.
主库恢复之后,它的日志表名变了,此时需要重新配置从库,不然从库使用的还是之前的错误日志表.
分库分表

大型互联网系统中,单台MySQL的存储容量无法满足需求,这时就需要扩容.
我们通过多台实例进行扩容,可以将数据分散,让多台主机共同保存数据.
那么如何进行拆分?

  • 垂直拆分:将数据库中的所有表,按照业务功能拆分到各个数据库中,而对于一张表,也可以通过外键之类的机制,将其拆分成多个表.


  • 水平拆分:水平拆分针对的是数据,不是表.让多个具有相同表的数据库协同存放一部分数据,相当于把数据分散到各个节点上.

实现这样的拆分操作,目前已经有一些解决方案了,比如mycat(数据库中间件,相当于挂了一层代理,再通过mycat进行分库分表操作数据库,只需要连接就能使用)或者Sharding JDBC(应用程序中字节对sql语句进行解析,然后转换成分库分表操作,需要自己编写一些逻辑代码),这里以Sharding JDBC为例!
Sharding JDBC

Sharding-JDBC 它定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
分库实现

具体实现水平拆分步骤如下:

  • 新建一个spring boot项目.先导入依赖:
  1.     org.apache.shardingsphere    shardingsphere-jdbc-core-spring-boot-starter    5.1.0    org.mybatis.spring.boot    mybatis-spring-boot-starter    4.0.1    org.projectlombok    lombok    true
复制代码

  • 编写配置文件
  1. spring:  shardingsphere:    datasource:      # 有几个数据源,就写几个,名称+数字的形式      names: ds0,ds1      # 每个数据源的具体配置      ds0:        type: com.zaxxer.hikari.HikariDataSource        driver-class-name: com.mysql.cj.jdbc.Driver        jdbc-url: jdbc:mysql://localhost:3306/yyds?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC        username: root        password: 123456      ds1:        type: com.zaxxer.hikari.HikariDataSource        driver-class-name: com.mysql.cj.jdbc.Driver        jdbc-url: jdbc:mysql://localhost:3306/yyds?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC        username: root        password: 123456
复制代码

  • 编写实体类和Mapper接口
  1. @AllArgsConstructor@Datapublic class User {    int id;    String name;    String password;}
复制代码
  1. @Mapperpublic interface UserMapper {    @Select("select * from user where id = #{id}")    User getUserById(int id);    @Insert("insert into user (id, name, password) values (#{id}, #{name}, #{password})")    int addUser(User user);}
复制代码
这些都是常规操作,编写代码的关注点依然放在业务上.
现在需要编写配置文件,告诉Sharding JDBC要如何进行分片.(现在是两个数据库都有user表,我们的目标是将用户信息分别存放在这两个数据库中)
  1. spring:  shardingsphere:    rules:      sharding:        tables:          # 这里填写表名,程序中对这张表的所有操作 都会采用下面的路由方案          user:            # 实际的路由数据节点,我们要分两个库,每个库一个表,所以是两个数据节点,格式是 数据源名称.表名            # 也可以使用表达式的方式来写,比如:ds$->{0..1}.user            actual-data-nodes: ds0.user,ds1.user            # 分库策略配置            database-strategy:              # 这里选择标准的分库策略,也可以配置复杂的分库策略,具体可以参考官方文档              standard:                # 参与分片运算的字段,通常是主键,下面的算法会根据这个字段的值来决定路由到哪个库                sharding-column: id                # 选择分片算法,下面我们会自定义一个分片算法,命名为my-alg                sharding-algorithm-name: my-alg      sharding-algorithms:        # 自定义的分片算法,命名为my-alg        my-alg:          # 算法类型(更多类型可以查询官方文档),这里选择MOD算法,MOD算法会根据分片字段的值对分片数量根据2取模来决定路由到哪个库          type: MOD          props:            shard-count: 2    props:      # 开启SQL日志输出,方便我们观察SQL路由的情况      sql-show: true
复制代码
这时就完成分库了,然后接可以进行业务开发了.
分表实现和查询

假如数据库中有test_01 和test_02两张表,表结构一样.我们希望能根据id取模运算的结果分别放到这两个不同的表中.首先需要明白两个概念:什么是逻辑表,什么是真实表

  • 逻辑表:相同结构的水平拆分数据库(表)的逻辑名称,是sql中表的逻辑标识,例如:订单数据根据主键拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名就是t_order
  • 真实表:真实存在的表,就是上面的t_order_0到t_order_9
实现的时候,不用修改任何业务逻辑代码,只需要做相应的配置即可:
  1. spring:  shardingsphere:    rules:      sharding:        tables:          test:            actual-data-nodes: ds0.test$->{0..1}            # 配置分表策略            table-strategy:              standard:                sharding-column: id                sharding-algorithm-name: my-alg        sharding-algorithms:            my-alg:              # INLINE方式,自定义表达式来决定路由到哪个库,表达式中可以使用分片字段的值来进行计算                type: INLINE                props:                  algorithm-expression: test$->{id % 2}                  # 查询也可以根据分片策略来进行,如果使用的是范围查询,依然会进行全量查询,这里先关闭                  allow-range-query-with-inline-sharding: false
复制代码
查询的时候,如果是根据id获取一行数据,实际上是去两张表里面查.
如果是范围查询,也就是返回结果是一个list集合的查询,需要配置allow-range-query-with-inline-sharding: true实际执行的sql是把两张表的查询结果union all起来,比如:
  1. select * from test where id >10 -- 就是执行下面的sqlselect * from test_0 where id >10 union all select * from test_1 where id >10
复制代码
分布式序列算法

在复杂分布式系统中,特别是微服务架构中,需要对大量数据和消息进行唯一标识.随着数据增多,分库分表成为常见方案,对数据分库分表后需要有一个唯一id来标识一条数据或消息(如订单号,事件编号等),此时需要一个能够生成全局唯一id的算法。这个id有以下要求:

  • 必须全局唯一
  • 尽可能保持有效,这样会提升索引的查询效率
满足以上需求的方案有:

  • uuid:是一组32位数的16禁止数字随机构成,全局唯一        但无需。
  • 雪花算法(Snowflake):生成一个64bit大小的整型id,需要使用Long类型。int类型装不下

雪花算法虽然具备了唯一性和有序性,但是依然有缺点,第一就是时间问题,如果机器时间出现倒退,那么就会导致生成重复的id,并且节点容量只有1024个,如果是超大规模集群,也存在隐患。
这里让Sharding JDBC用雪花算法为我们生成主键:

  • 先把表中的主键字段类型改为bigint
  • 修改配置文件,添加对应配置:
  1. spring:  shardingsphere:    rules:      sharding:        tables:          user:            actual-data-nodes: ds0.user,ds1.user            # 分库策略配置            database-strategy:              # 这里选择标准的分库策略,也可以配置复杂的分库策略,具体可以参考官方文档              standard:                # 参与分片运算的字段,通常是主键,下面的算法会根据这个字段的值来决定路由到哪个库                sharding-column: id                # 选择分片算法,下面我们会自定义一个分片算法,命名为my-alg                sharding-algorithm-name: my-alg            key-generate-strategy:              column: id              key-generator-name: my-gen        key-generators:          # 自定义的主键生成算法,命名为my-gen          my-gen:            # 算法类型,这里选择SNOWFLAKE算法,SNOWFLAKE算法会生成全局唯一的ID,适合分布式环境            type: SNOWFLAKE            props:            # SNOWFLAKE算法需要配置一个worker-id,通常是一个唯一的数字,可以根据实际情况来设置,确保在分布式环境中不同的实例有不同的worker-id              worker-id: 666        sharding-algorithms:        # 自定义的分片算法,命名为my-alg          my-alg:          # 算法类型,这里选择MOD算法,MOD算法会根据分片字段的值对分片数量取模来决定路由到哪个库            type: MOD            props:              shard-count: 2    props:      # 开启SQL日志输出,方便我们观察SQL路由的情况      sql-show: true
复制代码
此时就完成了主键生成策略设置
读写分离

之前实现的MySQL主从复制模式,我们可以将主库作为写操作,从库作为只读操作

在实现了主从复制模式的基础上进行配置:

  • 在从库的配置文件中,设置 read-only =1,这样从库就只能读数据了。
然后重启从库

  • 配置Sharding JDBC
  1. spring:  shardingsphere:    rules:      # 配置读写分离      readwrite-splitting:        data-sources:          #名称随便写          user-db:            type: static            props:              # 配置写库,只能写一个              write-data-source-name: ds0              # 配置读库,可以配置多个,逗号分隔              read-data-source-names: ds1              load-balancer-name: my-load        load-balancers:            # 自定义的负载均衡算法,命名为my-load          my-load:            type: round_robin
复制代码
此时读写分离配置完成!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册