前言

最近两周我都发了随笔写关于利用EF core实现多租户,并且给出了一些关于EF 自动迁移的内容。

这个系列的随笔是想要把这部分的代码优化和做成类库的。

我已经整理和抽象好了,本来想介绍一下整理的思路的。但后来发现这里的代码量太少了,好像没什么可以说的。

所以这篇随笔会讲解利用这个类库可以实现的功能。

 

多租户介绍

按照系列的随笔介绍,现在主要支持3种模式。分别是: 按表、按Schema和按数据库分离数据。

支持的数据库有MySql和SqlServer,并且在我重构的时候,把Postgre也集成进去了。

通过这次的代码重构,代码的结构已经不像前面的文章一样,停留在Demo层面。

代码修改后,我的目标是同时支持最基本的多租户,多租户演变成读写分离。

典型的模式

1. 按数据库分离的模式,可以看到一个DbContext会同时连接3个不同的数据库,每个库里面都有一个Product表.

多租户mysql分表_多租户

 

 2. 按表分离的模式,这里可以看到一个DbContext只会同时连接一个数据库,数据库里面有3个结构相同的Product表,但是它们的名称是根据前缀区分的。

多租户mysql分表_多租户_02

 

 3. 按Schema分离的模式,这里是一个DbContext只会同时连接一个数据库,数据库里面有3个Schema,3个Schema同时具有Product表

多租户mysql分表_数据库_03

 

 

在多租户的场景下的变型

通过通过数据库的结构,我们能知道,数据库、Schema和表是有层级关系的。一个数据库有n个Schema,一个Schema有n个表。

通过这个层级特性,我们是可以把他变型成4种模式:数据库和表混合模式、数据库和Schema混合模式、Schema和表混合模式、数据库和Schema和表混合模式

但一般来说,后面2中模式把更加多的压力都同时在一个数据库,并没有从硬件/数据库实例方面进行分离,数据量继续增长的情况下,最终还是需要通过多个数据库分离数据。

 

1. 数据库和表混合模式,可以看到DbContext里面有3个连接分别连接到3个Store Container的数据库,里面各自存在3个结构相同的数据表。

通过3个Store container,共有9个租户

多租户mysql分表_数据库_04

 

 

2. 数据库和Schema混合模式,一个DbContext里面有3个连接连接到3个Store Container的数据库,里面各自有3个Schema,每个Schema下都有一个结构相同的数据表

通过3个Store Container, 共有9个租户

多租户mysql分表_多租户mysql分表_05

 

 

转变为读写分离

在目前的系统中,读写分离是的应用更加广泛。通过下面的图看出,同一个DbContext下有3个连接分别链接到不同的数据库。数据库里见面有完全相同的表

其中一个是主库,2个是从库。

如果对比我们典型的多租户模式,其实是非常类型的,显而易见他们之间是可以互相演变的。事实上我项目中其实就是通过多租户模式下演变成读写分离的。

多租户mysql分表_数据库_06

 

读写分离&多租户图解

我们这里先看看下图中的结构。其实这里的图就是我整个系列的主要流程。其中有几个关键步骤

A. Http Request通过asp.net core的中间件或者拦截器。通过AOP的模式,通过http header和url等, 调用Tenant Generator。

B. Tenant Generator根据调用的接口参数,获取这是哪一个租户和API的操作类型(读或写),并且讲租户信息和操作类型返回

C. Connection Resolver接收租户和操作信息的组合,通过配置文件或配置中心获取具体的连接字符串,并且把连接字符串作为参数传入到DbContext的构造函数。

D. Db Context利用接收到连接字符串,通过EF core的封装,自动连接到不同的数据库。

注:租户和操作信息的组合,拿store1 & read的组合举个例子,他的配置的连接字符串的键值是 store_read。同理 store2 & write 的键值就是store2_write

多租户mysql分表_EF_07

 

 通过上图的结构,其实读写分离在我们的封装下,也是能轻而易举的实现的。估计读者来到这里会发现有3个关键组件是需要用户自定义才能完成。

分别是中间件或拦截器、Tenant Generator和Connection Resolver。他们3者需要同时维护和使用一个TenantInfo。

 

总结

好了,来到这里已经是本文的结束。是的,本文并没有贴出任何代码,仅仅是一个介绍的随笔。

本文的目的是,让阅读者对多租户和读写分离模式有抽象的概念,利用图和抽象对象尽量描述出这个模式实现下的关键是什么。

从系列的第一篇开始,是对多租户的入门,之后的随笔是对该模式的深入理解和加深实施办法。

经过了前面几篇文章的基础,通过本文的抽象概念和之前的实施代码进行融合,从而希望读者能够系统地了解到分库分表。