Spring Boot と Spring Cloud を使用してマルチテナント アーキテクチャを実装する: アプリケーションのマルチテナントのデプロイと管理をサポートする
I. 概要
1 マルチテナント アーキテクチャとは何ですか?
マルチテナント アーキテクチャとは、アプリケーション内の複数のテナント (テナント) による同時アクセスをサポートすることを指します。各テナントは独立したリソースとデータを持ち、互いに完全に分離されています。平たく言えば、マルチテナンシーとは、顧客のニーズに応じてアプリケーションを複数の独立したインスタンスに「分割」することであり、各インスタンスは互いに干渉しません。
2 マルチテナントアーキテクチャの利点
- さまざまなテナントの個別のニーズをより適切に満たします。
- 運用と保守のコストを削減し、ハードウェアやネットワークなどのインフラストラクチャへの投資を削減できます。
- コードを再利用することで開発コストを節約し、新しいテナント インスタンスを迅速に起動します。
- システムの拡張性や拡張性が強化され、水平拡張に対応し、テナントごとのデータやリソースを管理・制御できます。
3 マルチテナントアーキテクチャを実装するためのテクノロジーの選択
マルチテナント アーキテクチャ テクノロジを実現するために最も重要なことは、正しいアーキテクチャのアイデアではありません。ただし、適切なテクノロジーを選択すると、マルチテナント アーキテクチャの高速化につながる可能性があります。
2. デザインアイデア
1 アーキテクチャの選択
Java ベースのマルチテナント アプリケーションを開発するには、Spring Boot と Spring Cloud を使用することをお勧めします。Spring Boot はアプリケーションを迅速に構築し、成熟したプラグインを多数提供できます。Spring Cloud は、マイクロサービス アーキテクチャを実装するための多くのツールとコンポーネントを提供します。
1.1 スプリングブート
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 は、サービス検出やロード バランシングなどのマイクロサービス機能を実現するために、Eureka、Zookeeper、Consul などのいくつかの成熟したソリューションを提供します。
2 データベース設計
マルチテナント環境では、データベースはテナントごとにデータを個別に保存し、データの分離を確保する必要があります。通常、次の 2 つの方法を使用して実現します。
- 複数のテナントが同じデータベースを共有し、各テーブルには、異なるテナントからのデータを区別するための tenant_id 列が含まれています。
- テナントごとに個別のデータベースを作成します。各データベースは同じテーブル構造を持ちますが、データは相互に分離されます。
3 アプリケーションのマルチテナント展開
アプリケーションの展開でマルチテナントを実現するには、次の 2 つの問題を考慮する必要があります。
3.1 アプリケーションの分離
マルチテナント環境では、異なるテナントが異なるリソースにアクセスする必要があるため、アプリケーションの分離が必要です。これは、名前空間などを使用して、別個のコンテナーまたは仮想マシンを構築することで実現できます。Docker は、コンテナーを分離するための非常に人気のあるテクノロジーです。
3.2 アプリケーションの構成
テナントごとに独自の構成要件があるため、ポート番号やSSL証明書などのアプリケーション構成情報をテナントごとに設定する必要があります。これらの構成は、データベースまたはクラウド構成センターに保存できます。
4 テナント管理
マルチテナント システムでは、異なるテナントのデータとリソースを管理できる必要があると同時に、各テナントに対応する権限を割り当てる必要があります。通常、ソリューションには次の 2 つの部分が含まれます。
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");
}
}
3. 技術的な実現
1 Spring Boot でのマルチテナンシーの実装
Spring Boot では、複数のデータ ソースと動的ルーティングを通じてマルチテナント メカニズムを実現できます。
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();
}
}
上記のコードは、3 つのテナントに対応する 3 つのデータ ソースで構成されています。その後、使用するときに、アノテーションを使用して、接続する必要があるデータ ソースをマークできます。
@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 リボンをロードバランサーとして使用します。リクエストされた URL またはパラメータに従ってテナントに対応するサービス インスタンスを選択し、リクエストを転送します。
2.4 API
マルチテナント メカニズムは API ゲートウェイ レベルで実装され、リクエストの URL またはパラメータに従ってテナントを決定し、対応するテナントのサービス インスタンスに転送します。
4. 応用シナリオ
1 プライベートクラウド環境
プライベートクラウド環境とは、外部サービスを提供せず、主に企業内でのデータの保管、管理、共有、セキュリティ管理に利用される、企業自身が構築するクラウド環境を指します。パブリック クラウドと比較して、プライベート クラウドの利点は、企業のコア データをより適切に保護できること、またデータのセキュリティと制御性に対する企業の要件を満たすことができることです。
2 パブリッククラウド環境
パブリッククラウド環境とは、クラウドサービスプロバイダーが構築して外部サービスを提供するクラウド環境を指し、ユーザーはクラウドストレージ、クラウドコンピューティング、クラウドデータベースなど、ニーズに応じて対応するクラウドサービスを購入できます。プライベート クラウドと比較して、パブリック クラウドには、低コスト、柔軟な拡張性、グローバル展開という利点があり、企業の急速な発展のニーズに十分に対応できます。
3 エンタープライズアプリケーション
エンタープライズレベルアプリケーションとは、企業顧客向けのアプリケーションを指し、主にERP、CRM、OAなどの一連のアプリケーションシステムを含みます。このタイプのアプリケーションは、強力な機能、複雑なプロセス、大量のデータを特徴としており、企業の高効率、高信頼性、高セキュリティ、容易なメンテナンスの要件を満たす必要があります。クラウド コンピューティング環境では、企業はこれらのアプリケーションをプライベート クラウドまたはパブリック クラウドに展開できるため、ハードウェア機器への投資とメンテナンスのコストが削減され、管理効率が向上します。
5. 導入手順
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 が含まれます。
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
マルチテナント展開用のコア構成クラスがあり、対応するテナント データ ソース、マルチテナント セッション ファクトリ、テナントの動的切り替えなどの機能を提供します。
4 テナント管理の実現
最後に、システム内のさまざまなテナントを管理するために、テナント管理機能を実装する必要があります。具体的には、Spring Cloud のサービス登録および検出コンポーネント Eureka を使用して、各テナントのインスタンスを登録し、管理インターフェイスで対応する操作を実行できます。さらに、データの分離を確実にするために、テナントごとに独立したデータベースを提供する必要もあります。
6. まとめと振り返り
この記事では、Spring Boot と Spring Cloud を使用してマルチテナント デプロイメントをサポートするアプリケーションを実装する方法について詳しく説明します。これには主に、Spring Boot および Spring Cloud 環境の構築、データベース設計の変更、アプリケーションのマルチテナント展開の実装、テナント管理の実装が含まれます。アプリケーション シナリオには、主に SaaS アプリケーション、マルチテナント クラウド サービスなどが含まれます。利点と欠点は主に、アプリケーションのスケーラビリティと保守性の向上に反映されますが、展開と管理の複雑さも増します。将来の改善の方向性としては、マルチテナント管理の自動化をさらに改善して、手動介入とエラー率を減らすことが考えられます。