乐趣区

关于java:Spring-Boot-优雅实现多租户架构so-easy~

一、概述

1. 什么是多租户架构?

多租户架构是指在一个利用中反对多个租户(Tenant)同时拜访,每个租户领有独立的资源和数据,并且彼此之间齐全隔离。艰深来说,多租户就是把一个利用依照客户的需要“宰割”成多个独立的实例,每个实例互不烦扰。

2. 多租户架构的劣势

  • 更好地满足不同租户的个性化需要。
  • 能够升高运维老本,缩小硬件、网络等基础设施的投入。
  • 节约开发成本,通过复用代码,疾速上线新的租户实例。
  • 加强了零碎的可扩展性和可伸缩性,反对程度扩大,每个租户的数据和资源均可治理和管制。

3. 实现多租户架构的技术抉择

对于实现多租户架构技术不是最重要的最重要的是正确的架构思路。然而抉择正确的技术能够更快地实现多租户架构。

二、设计思路

1. 架构选型

基于 Java 开发多租户利用举荐应用 Spring Boot 和 Spring Cloud。Spring Boot 能疾速搭建利用并提供许多成熟的插件。Spring Cloud 则提供了许多实现微服务架构的工具和组件。

1.1 Spring Boot

应用 Spring Boot 能够简化我的项目的搭建过程主动配置许多常见的第三方库和组件,缩小了开发人员的工作量。

@RestController
public class TenantController {@GetMapping("/hello")
    public String hello(@RequestHeader("tenant-id") String tenantId) {return "Hello," + tenantId;}
}

1.2 Spring Cloud

在架构多租户的零碎时 Spring Cloud 会更加有用。Spring Cloud 提供了一些成熟的解决方案,如 Eureka、Zookeeper、Consul 等,以实现服务发现、负载平衡等微服务性能。

2. 数据库设计

在多租户环境中数据库必须为每个租户别离存储数据并确保数据隔离。咱们通常应用以下两种形式实现:

  • 多个租户共享雷同的数据库,每个表中都蕴含 tenant_id 这一列,用于辨别不同租户的数据。
  • 为每个租户创立独自的数据库,每个数据库内的表构造雷同,但数据互相隔离。

3. 利用多租户部署

为了实现多租户在利用部署时咱们须要思考以下两个问题。

3.1 利用隔离

在多租户环境中不同租户须要拜访不同的资源,因而须要进行利用隔离。能够通过构建独立的容器或虚拟机、应用命名空间等形式实现。Docker 就是一种十分风行的隔离容器技术。

3.2 利用配置

因为每个租户都有本人的配置需要因而须要为每个租户别离设置利用配置信息,例如端口号、SSL 证书等等。这些配置能够存储在数据库中,也能够存储在云配置核心中。

4. 租户治理

在多租户零碎中须要可能治理不同租户的数据和资源,同时须要为每个租户调配相应的权限。解决方案通常包含以下两局部。

4.1 租户信息保护

租户信息的保护包含增加、批改、删除、查问等操作,要求可能依据租户名称或租户 ID 疾速查找对应的租户信息。

CREATE TABLE tenant (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL UNIQUE,
    description VARCHAR(255),
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

4.2 租户权限管制

在多租户利用中必须为每个租户别离设置对系统资源的拜访权限。例如,A 租户和 B 租户不能拜访彼此的数据。

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()
                .antMatchers("/api/tenant/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin();}

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService())
                .passwordEncoder(new BCryptPasswordEncoder())
                .and()
                .inMemoryAuthentication()
                .withUser("admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("ADMIN");
    }
}

三、技术实现

1. Spring Boot 中的多租户实现

在 Spring Boot 中能够通过多数据源和动静路由来实现多租户机制。

Spring Boot 根底就不介绍了,举荐看这个实战我的项目:

https://github.com/javastacks/spring-boot-best-practice

1.1 多数据源实现

多数据源是指为不同的租户配置不同的数据源,使得每个租户都能够拜访本人的独立数据。具体实现办法如下:

@Configuration
public class DataSourceConfig {@Bean(name = "dataSourceA")
    @ConfigurationProperties(prefix = "spring.datasource.a")
    public DataSource dataSourceA() {return DataSourceBuilder.create().build();}

    @Bean(name = "dataSourceB")
    @ConfigurationProperties(prefix = "spring.datasource.b")
    public DataSource dataSourceB() {return DataSourceBuilder.create().build();}

    @Bean(name = "dataSourceC")
    @ConfigurationProperties(prefix = "spring.datasource.c")
    public DataSource dataSourceC() {return DataSourceBuilder.create().build();}
}

以上代码是配置了三个数据源别离对应三个租户。而后在应用时,能够应用注解标记须要连贯的数据源。

@Service
public class ProductService {
    @Autowired
    @Qualifier("dataSourceA")
    private DataSource dataSource;

    // ...
}

1.2 动静路由实现

动静路由是指依据申请的 URL 或参数动静地切换到对应租户的数据源。具体实现如下:

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {return TenantContextHolder.getTenantId();
    }
}

@Configuration
public class DataSourceConfig {@Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {return DataSourceBuilder.create().type(DynamicDataSource.class).build();}
}

以上是动静路由的外围代码 DynamicDataSource 继承自 AbstractRoutingDataSource,通过determineCurrentLookupKey() 办法动静取得租户 ID,而后切换到对应的数据源。

2. Spring Cloud 中的多租户实现

在 Spring Cloud 中能够通过服务注册与发现、配置核心、负载平衡等形式实现多租户机制。

2.1 服务注册与发现

应用 Spring Cloud 中的 Eureka 实现服务注册与发现。每个租户的服务都在注册核心以不同的利用名称进行注册,客户端能够通过服务名称来拜访对应租户的服务。

2.2 配置核心

应用 Spring Cloud Config 作为配置核心。配置文件以租户 ID 进行辨别,客户端通过读取对应租户的配置文件来获取配置信息。

2.3 负载平衡

应用 Spring Cloud Ribbon 作为负载均衡器。依据申请的 URL 或参数抉择对应租户的服务实例进行申请转发。

2.4 API

在 API 网关层面实现多租户机制依据申请的 URL 或参数判断所属租户,并转发到对应租户的服务实例。

四、利用场景

1. 公有云环境

公有云环境指的是由企业自行搭建的云环境,不对外提供服务,次要利用于企业外部的数据存储、治理、共享和安全控制。相较于私有云,公有云的长处在于能够更好地爱护企业外围数据,同时也可能满足企业对于数据安全性和可控性的要求。

2. 私有云环境

私有云环境指的是由云服务商搭建并对外提供服务的云环境,用户能够依据须要购买相应的云服务,如云存储、云计算、云数据库等。相较于公有云,私有云的长处在于具备老本低廉、弹性伸缩、全球化部署等特点,可能更好地满足企业疾速倒退的需要。

3. 企业级利用

企业级利用是指面向企业客户的应用程序,次要包含 ERP、CRM、OA 等一系列利用零碎。这类利用的特点在于功能强大、流程简单、数据量大,须要满足企业的高效率、高可靠性、高安全性和易维护性等要求。在云计算环境下,企业能够将这些利用部署在公有云或私有云上,缩小了硬件设施的投入和保护老本,进步了管理效率。

五、实现步骤

1. 搭建 Spring Boot 和 Spring Cloud 环境

首先须要在 Maven 我的项目中引入以下依赖:

<!-- Spring Boot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Cloud -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>2020.0.3</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

而后须要在 application.yml 中配置相应的参数,如下所示:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/appdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

mybatis:
  type-aliases-package: com.example.demo.model
  mapper-locations: classpath:mapper/*.xml

server:
  port: 8080

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"

其中 datasource.url 为数据库连贯的 URL,username 和 password 为数据库连贯的账号和明码;server.port为 Spring Boot 利用启动的端口;eureka.client.serviceUrl.defaultZone为 Eureka 服务注册核心的 URL。

Java 指南:java-family.cn

2. 批改数据库设计

接下来须要对数据库进行相应的批改,以反对多租户部署。具体来说,咱们须要在数据库中增加一个与租户相干的字段,以便在利用中辨别不同的租户。

3. 实现利用多租户部署

接着须要在代码中实现利用的多租户部署性能。具体来说,咱们须要为每个租户实例化对应的 Spring Bean,并依据租户 ID 将申请路由到相应的 Bean 中去解决。

以下是一个简略的实现示例:

@Configuration
public class MultiTenantConfig {
 
    // 提供对应租户的数据源
    @Bean
    public DataSource dataSource(TenantRegistry tenantRegistry) {return new TenantAwareDataSource(tenantRegistry);
    }
 
    // 多租户 Session 工厂
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
            throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();}
 
    // 动静切换租户
    @Bean
    public MultiTenantInterceptor multiTenantInterceptor(TenantResolver tenantResolver) {MultiTenantInterceptor interceptor = new MultiTenantInterceptor();
        interceptor.setTenantResolver(tenantResolver);
        return interceptor;
    }
 
    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(multiTenantInterceptor());
    }
 
    // 注册租户信息
    @Bean
    public TenantRegistry tenantRegistry() {return new TenantRegistryImpl();
    }
     
    // 解析租户 ID
    @Bean
    public TenantResolver tenantResolver() {return new HeaderTenantResolver();
    }
 
}

其中 MultiTenantConfig 是多租户部署的外围配置类,它提供了对应租户数据源、多租户 Session 工厂、动静切换租户等性能。

4. 实现租户治理

最初须要实现一个租户治理的性能,以便在零碎中治理不同的租户。具体来说,咱们能够应用 Spring Cloud 的服务注册与发现组件 Eureka 来注册每个租户的实例,并在治理界面中进行相应的操作。另外,咱们还须要为每个租户提供一个独立的数据库,以保证数据隔离性。

六、小结回顾

本文具体介绍了如何应用 Spring Boot 和 Spring Cloud 实现一个反对多租户部署的利用。次要包含搭建 Spring Boot 和 Spring Cloud 环境、批改数据库设计、实现利用多租户部署、实现租户治理等方面。

利用场景次要包含 SaaS 利用、多租户云服务等。优劣势次要体现在晋升了利用的可扩展性和可维护性,但也减少了部署和治理的复杂度。将来的改良方向能够思考进一步晋升多租户治理的自动化水平,缩小人工干预和错误率。

版权申明:本文为 CSDN 博主「格林希尔」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。原文链接:https://blog.csdn.net/u010349629/article/details/130737253

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版