多租户
在 SaaS 体系中多租户是一个很重要的架构,在服务上仅需运转一个软件实例就可以支持每个租户的功用,它们之间的数据互相隔离。就比方 Gitee ,每个用户或组织都拥有自己的空间。它们自己的数据仅在自己的空间内流转,彼此之间互不影响。多租户其实便是一种软件设计结构。
所以。租户模型其实便是别离数据的方法:
- 单租户:一个运用一个数据库。其实便是运用别离,数据别离。
- 多租户:一个运用多个数据库。便是同一个运用不同数据库。
为什么需求多租户?
刚毕业第一家公司,接触的第一个项目的内容主要协助客户提高生产力。每次有一个很大的问题便是,协作一个客户,项目复制一份出来,然后改成该客户定制的功用需求。这样就导致相同功用要更新多份代码,还要留意可能会出现因不同客户的不同需求问题。整个进程就导致了一个很大的维护成本的支出。
多租户运用程序的维护更容易,只需依据每个租户专属标志,然后提供不同的功用,且公共的功用可以会集更新晋级。
数据隔离方法
在 SaaS 体系中一般别离租户的数据有两种模型:
- 数据的逻辑别离:一切租户只运用一个数据库。它们的数据通过为每个租户运用一个仅有标识符来分隔。
- 数据的物理别离:一个租户分配一个数据库。便是一个运用对应多个数据库。每个数据库便是一个租户。这种方法在客户的增加时扩展了运用的功用,也便利扩展数据库
物理别离具体实现
方针:每个恳求过来,运用程序可以识别租户,并从该租户数据库中进行提供数据。
- 公共数据库:存储一切租户相关全局装备和一切租户数据库信息。
- 租户数据库:每个租户独立的的数据库,依据租户需求保存数据。

发动服务
创立 main 文件,并运用 Gin 框架。初始化一个简单的运用程序并创立根本的路由。
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
r.Run()
}
数据库装备
在公共数据库创立一个保存租户数据库信息表并添加上租户的数据库。
Create Table db_tenant (
id int primary key,
db_name varchar(100) unique not null,
db_domain varchar(100) unique not null,
conn_str varchar(200) not null,
remark varchar(1000) ,
)
在装备文件中参与一个公共数据库的衔接装备,这样就可以在服务发动时第一次衔接的是公共数据库。接着需求实现依据恳求衔接到正确的租户数据库。主要运用 gorm 的 DBResolver ,多个数据库的衔接支持
func allDbConnect(db *db.gorm) (allDbs map[string]) {
db.Model(&db_tenant).Find(&allDbs)
var gconn []gorm.Dialector
for _,connStr := range allDbs {
db :=mysql.Open(connStr)
gconn = append(gconn,db)
}
db.Use(dbresolver.Register(dbresolver.Config{
Sources: gconn,
// sources/replicas 负载均衡战略
Policy: dbresolver.RandomPolicy{},
})
return allDbs
}
通过运用中间件来解析每个恳求衔接,从而确定整个恳求是由哪个租户数据库来提供数据读写。中间件中主要的处理方法是得到租户对应的数据库衔接名,然后从衔接池中拿到该衔接并设置在全局变量中。在业务逻辑处理中从全局拿到数据库衔接,就可以进行数据库读写。
r.Use(middlerware.dbResolve)
func dbResolve(ctx *gin.Context) {
dbName := ctx.Query("dbName")
setGlobalDb(dbName)
}
func dbOperater(){
db := getDb()
var users []User
db.Clauses(dbresolver.Use(dbName)).First(&users)
}
这样就可以发动项目,然后访问 localhost:8003?dbName=db1 ,这样就可以正常进行数据读写。
其实可以从域名上解析对应的数据库衔接。这儿最重要便是对数据库的解析。这儿的例子只是试验运用,其中还有很多可优化的点。比方可以考虑运用衔接池,这样就不用在项目发动时都悉数创立数据库衔接,形成浪费。
本文正在参与「金石计划 . 瓜分6万现金大奖」