Sharding-Sphere实现多租户架构

简介: Sharding-Sphere实现多租户架构

在上一篇文章中,介绍了基于Mybatis-plus实现多租户架构,但是在实际工作中可能会存在一些不足:

  1. 如果是基于现有的系统改造,那么在所有的表上都需要加租户字段,会非常复杂
  2. 如果第三方系统调用我们的接口,可能无法要求他们在请求中携带租户信息,因此要重写大量的需要单独过滤的sql语句

针对上面的问题,接下来继续介绍一下基于Sharding-Sphere的分表来实现多租户,与之前在一张表中存放数据不同,我们会将不同租户的数据存放在同一数据库的不同表中,相对于前一种模式,这样会具有更高的数据隔离性。

首先来假设一个应用场景,某航空票务公司网站中,海航系、南航系和国航系被分为3个租户,租户间数据分表存放,它们下属的各个航空公司分别隶属于以上租户,那么随之各自的订单数据也存放在各自的租户数据表中。

首先先进行准备工作,为3个租户分别建表:

CREATE TABLE `t_order_0` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `order_number` varchar(32) DEFAULT NULL,
  `money` decimal(18,4) DEFAULT NULL,
  `postage` decimal(18,4) DEFAULT NULL,
  `address` varchar(128) DEFAULT NULL,
  `company` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

注意相同表结构的表需要建立三张,分别是t_order_0t_order_1t_order_2

导入Sharding-Sphere依赖和数据库连接池druid的依赖:

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.22</version>
</dependency>

注意这里引入的是druid而不是druid-spring-boot-starter,因为在高版本的sharding-sphere中,如果使用starter版本可能报错找不到url

application.yml中进行配置数据源及分表规则:

spring:
  shardingsphere:
    datasource:
      names: ds0
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/tenant?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: hydra
        password: 123456
    sharding:
      defaultDataSourceName: ds0
      tables:
        t_order:
          actualDataNodes: ds0.t_order_$->{0..2}
          tableStrategy:
            standard:
              shardingColumn: company
              preciseAlgorithmClassName: com.cn.hydra.shardingtest.algorithm.OrderShardingAlgorithm
    props:
      sql:
        show: true

对上面的参数进行说明:

datasource:这里因为还用不到分库,所以只进行了一个数据源的配置,如果存在多个则与ds0结构相同

defaultDataSourceName:选择默认数据源

tables:开始数据分片规则配置,注意下面的t_order是逻辑表名称

actualDataNodes :由数据源名加表名组成,以小数点分隔,多个表以逗号分隔,支持行表达式

tableStrategy:分表策略

standard:用于单分片键的标准分片场景

shardingColumn:分片列名称

preciseAlgorithmClassName:分片算法实现类,这个类由对我们自己实现,定义分片逻辑

props.sql.show:打印sql语句

创建一个枚举类,存放航空公司名称到租户id的对应关系,并写一个根据航空公司查找租户编码的方法,在后面分片规则中使用:

public enum Rules {
    NANHANG(0,Arrays.asList("NANFANG","XIAMEN","CHONGQING")),
    HAIHANG(1, Arrays.asList("SHOUDU","CHANGAN","JINPENG")),
    GUOHANG(2,Arrays.asList("GUOHANG","SHENZHEN","SHANHANG"));
    public static int searchCode(String company){
        for (Rules value : Rules.values()) {
            if (value.getCompany().contains(company)){
                return value.getCode();
            }
        }
        return -1;
    }
    private int code;
    private List<String> company;
    Rules(int code,List<String> company){
        this.code=code;
        this.company=company;
    }
    public int getCode() {
        return code;
    }
    public List<String> getCompany() {
        return company;
    }
}

接下来是分表的核心,分片逻辑类需要实现PreciseShardingAlgorithm接口,并重写doSharding方法。之后对订单表的操作都会执行这里的doSharding方法选择实际执行sql的数据库表:

public class OrderShardingAlgorithm implements PreciseShardingAlgorithm<String> {
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        int tenant = Rules.searchCode(preciseShardingValue.getValue());
        String targetTable="t_order_"+tenant;
        if (collection.contains(targetTable)){
            return targetTable;
        }
        throw  new UnsupportedOperationException("找不到租户:"+preciseShardingValue);
    }
}

之前在yml中定义了分片列是company,因此这里通过preciseShardingValue能够拿到company的值。再根据上面枚举类的对应关系,可以获得租户id,最后返回真正执行sql的表名。

创建一个简单的订单Service进行测试,用来执行创建订单和查询订单的操作,参数都是航空公司的名称:

@Service
public class OrderService {
    @Autowired
    OrderMapper orderMapper;
    public void createOrder(String company){
        Order order=new Order();
        order.setOrderNumber(UUID.randomUUID().toString().replaceAll("-",""));
        order.setMoney(new BigDecimal(100));
        order.setCompany(company);
        orderMapper.insert(order);
    }
    public void getOrder(String company){
        List<Order> orders = orderMapper.selectList(new LambdaQueryWrapper<Order>().eq(Order::getCompany, company));
        orders.stream().forEach(System.out::println);
    }
}

首先调用创建订单方法进行测试,发送一个请求:

http://127.0.0.1:8083/create?company=SHOUDU

查看执行结果的日志打印情况,被分为逻辑sql和实际执行的sql两部分。在逻辑sql语句中,可以看到使用的是逻辑表t_order,在实际sql中实际执行在t_order_1中,因为航空公司名称参数SHOUDU对应的租户编码是1,在分片算法中进行了实际表名的计算。

image.png

将参数换成SHENZHEN再执行一次:

http://127.0.0.1:8083/create?company=SHENZHEN

查看执行结果,实际执行的sql语句的表被换成了t_order_2

image.png

接下来看一下可能发生的特殊情况,首先,如果传递的分片列的参数不在我们定义的映射规则内,那么会抛出UnsupportedOperationException异常:

image.png

如果在sql中没有涉及到分片列,那么数据会被插入到所有的表中,可以看到在下面的情况中,同一个订单被同时插入到了3张表中:

image.png

执行查询订单的方法进行测试:

http://127.0.0.1:8083/list?company=SHENZHEN

同样根据分片规则在表t_order_2中进行了实际的查询操作:

image.png

通过上面的实验,可以看出Sharding-Sphere的配置比较简单,在使用起来也是很方便的,通过客户端分片技术,能够很简单的实现基于分表的多租户需求。

相关文章
|
6月前
|
存储 监控 安全
【Elasticsearch专栏 11】深入探索:Elasticsearch如何支持多租户架构
Elasticsearch支持多租户架构主要通过索引隔离、集群隔离和基于路由的隔离。通过为每个租户创建独立索引或配置路由规则,实现数据隔离。同时,利用基于角色的访问控制机制进行权限管理,确保租户数据安全。这些策略提供了灵活且安全的多租户支持。
222 5
|
2月前
|
存储 Java 数据库
Spring Boot 优雅实现多租户架构
本文详细介绍如何使用Spring Boot和Spring Cloud实现多租户架构。多租户架构允许多个租户共用一个应用,各自拥有独立资源和数据。其优势包括满足个性化需求、降低成本、复用代码以及增强可扩展性。文中探讨了架构选型、数据库设计、应用部署及租户管理等内容,并提供了具体实现步骤和技术细节。适用于SaaS应用和多租户云服务等场景。
|
4月前
|
监控 Java 数据库
Spring Boot中的多租户架构实现
Spring Boot中的多租户架构实现
|
4月前
|
存储 Java 数据库
在Spring Boot中实现多租户架构的数据隔离
在Spring Boot中实现多租户架构的数据隔离
|
安全 Java 数据库
在 Spring Boot 中如何优雅地实现多租户架构?
在 Spring Boot 中如何优雅地实现多租户架构?
1453 0
在 Spring Boot 中如何优雅地实现多租户架构?
|
5月前
|
Oracle 关系型数据库 MySQL
深入OceanBase内部机制:多租户架构下的资源隔离实现精讲
深入OceanBase内部机制:多租户架构下的资源隔离实现精讲
|
6月前
|
安全 Java 数据安全/隐私保护
Spring Boot优雅实现多租户架构:概念与实战
【4月更文挑战第29天】在多租户系统中,一个应用实例服务于多个租户,每个租户享有独立的数据视图,而应用的基础设施被共享。这样的架构不仅优化了资源使用,还能降低维护和运营成本。本文将详细介绍如何在Spring Boot中实现多租户架构,并提供具体的实战案例。
258 2
|
6月前
|
Oracle 安全 数据管理
Oracle 12c多租户架构:数据管理的“摩天大楼”
【4月更文挑战第19天】Oracle 12c的多租户架构允许多个独立数据库环境在同一实例中共享资源,提高效率,降低成本。该架构保证了数据隔离和安全性,同时提供灵活性和可扩展性,简化管理任务。通过理解其原理和管理方法,我们可以充分利用这一架构,为企业数据管理和业务发展提供强大支持。
|
存储 负载均衡 Java
Spring Boot 优雅实现多租户架构,so easy!
Spring Boot 优雅实现多租户架构,so easy!
1180 0
EMQ
|
安全 物联网 Serverless
MQTT 服务新趋势:了解 MQTT 多租户架构
MQTT 的多租户架构为物联网服务提供商提供灵活可扩展的新选择,本文将介绍其优势和挑战。
EMQ
296 0