分库分表解决方案

背景

我们要分库分表?
随着我们系统业务量增加,数据量变大,导致查询效率变低
一般单表超过1000万左右,就该考虑分库分表(这个不是绝对的)
在考虑分库分表前,我需要考虑以下方面:
当查询效率下降,我们是否可以用缓存来解决
我们是否可以用读写分离解决
这些都不能来解决了,再考虑是否分库分表可以解决

分库分表解决方案

  • shareding-jdbc
  • mycat

Sharding-JDBC:Sharding-JDBC部署相对较简单,只需要在应用程序中引入相关依赖并配置分片规则即可。它与现有的JDBC驱动程序兼容,不需要额外的服务器组件。
Mycat:Mycat的部署相对复杂,需要单独配置和管理Mycat服务器,并与MySQL数据库进行集成。此外,Mycat还支持数据分片的自动扩展和缩放。

  • 主要概念
  1. 逻辑表

在对表进行分片后,一张表分成了n个表,比如订单表t_order分成如下三张表:t_order_1,t_order_2,t_order_3。

此时订单表的逻辑表就是t_order,Sharding-JDBC在进行分片规则配置时针对的就是这张逻辑表

  1. 真实表

上述t_ordr_1,t_order_2,t_order_3 称之为 真实表

  1. 数据节点

数据分片的最小单元,由数据源名称和表名称组成,比如:ds1.t_order_1

  1. 分片键

用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订

单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Sharding- Jdbc也支持根据多个字段进行分片。

  1. 分片算法

通过分片算法将数据分片,支持通过 =BETWEENIN 分片。

分片算法需要应用方开发者自行实现,可实现的灵 活度非常高。包括:精确分片算法范围分片算法复合分片算法 等。例如:where order_id = ? 将采用精确分片算法,where order_id in (?,?,?)将采用精确分片算法,where order_id BETWEEN ? and ? 将采用范围分片算 法,复合分片算法用于分片键有多个复杂情况。

Sharding-JDBC 中的分片算法需要开发者根据业务自定义

  1. 分片策略

包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也 就是分片策略。

内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。由用户方配置的分片策略则更加灵活,常用的使用行表达式配置分片策略,它采用Groovy表达式表示,如: t_user_$->{u_id % 8} 表示t_user 表根据u_id模8,而分成8张表,表名称为 t_user_0 到 t_user_7 。

1、标准分片策略

标准分片策略适用于单分片键,此策略支持 PreciseShardingAlgorithmRangeShardingAlgorithm 两个分片算法。

其中 PreciseShardingAlgorithm 是必选的,用于处理 =IN 的分片。RangeShardingAlgorithm 是可选的,用于处理BETWEEN AND><>=<= 条件分片,如果不配置RangeShardingAlgorithm,SQL中的条件等将按照全库路由处理。

2、复合分片策略

复合分片策略,同样支持对 SQL语句中的 =><>=<=INBETWEEN AND 的分片操作。不同的是它支持多分片键,具体分配片细节完全由应用开发者实现。

3、行表达式分片策略

行表达式分片策略,支持对 SQL语句中的 =IN 的分片操作,但只支持单分片键。这种策略通常用于简单的分片,不需要自定义分片算法,可以直接在配置文件中接着写规则。

t_order_$->{t_order_id % 4} 代表 t_order 对其字段 t_order_id取模,拆分成4张表,而表名分别是t_order_0t_order_3

4、Hint分片策略

Hint分片策略,对应上边的Hint分片算法,通过指定分片健而非从 SQL中提取分片健的方式进行分片的策略。

  1. 分布式主键生成策略

通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。

Sharding-JDBC 内部支持UUID和Snowflake生成分布式主键

shareding-jdbc 实战

  • 简介

分布式SQL事务和查询引擎,用于任何数据库上的数据分片,扩展,加密等。

  • 应用示例
    第一步:引入依赖
    <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.13</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

第二步:配置文件

server.port=8888
spring.main.allow-bean-definition-overriding=true

spring.shardingsphere.datasource.names=test

spring.shardingsphere.datasource.test.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.test.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.test.url=jdbc:mysql://192.168.10.10:3306/test
spring.shardingsphere.datasource.test.username=root
spring.shardingsphere.datasource.test.password=123456



spring.shardingsphere.sharding.tables.order.actual-data-nodes=test.order_$->{1..2}
spring.shardingsphere.sharding.tables.order.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order.table-strategy.inline.algorithm-expression=order_$->{id % 2}

spring.shardingsphere.sharding.tables.order.key-generator.column=id
spring.shardingsphere.sharding.tables.order.key-generator.type=SNOWFLAKE

spring.shardingsphere.props.sql.show=true


第三步:controller、entity、mapper

@RestController
@RequiredArgsConstructor
public class ControllerJdbc {
    private final OrderMapper orderMapper;
    @GetMapping(value = "test-jdbc")
    public String testJdbc()  {
        for(int i=1;i<11;i++){
            Order order=new Order();
            order.setNum(i);
            orderMapper.insertUser(order);
        }
        return "ok";
    }

}
public class Order {

    private Integer id;

    private Integer  num;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

}
@Mapper
public interface OrderMapper {
    int insertUser(Order order);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gz.sharding.jdbc.mapper.OrderMapper">
    <resultMap id="BaseResultMap"
               type="com.gz.sharding.jdbc.entity.Order">
        <id column="id" jdbcType="INTEGER" property="id"/>
        <id column="num" jdbcType="INTEGER" property="num"/>

    </resultMap>

    <insert id="insertUser" parameterType="com.gz.sharding.jdbc.entity.Order">
            insert into `order` (num) VALUES (#{num})
    </insert>


</mapper>

DROP TABLE IF EXISTS `order_1`;
CREATE TABLE `order_1`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `num` bigint(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

分库分表问题

  • 需要对原有代码进行改造
  • 需要引入分布式事务
  • 对于复杂sql查询如何解决

如果查询条件不是分片键如何解决? 建议与es结合进行查询,把不是分表键数据同步到es,先从es查询,再根据分片键去查询。

代码地址

https://gitee.com/GZ-jelly/microservice-sample

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫果冻

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值