Go 簡單實現(xiàn)多租戶數據庫隔離
多租戶
在 SaaS 系統(tǒng)中多租戶是一個很重要的架構,在服務上僅需運行一個軟件實例就能夠支持每個租戶的功能,它們之間的數據互相隔離。就比如 Gitee ,每個用戶或組織都擁有自己的空間。它們自己的數據僅在自己的空間內流通,彼此之間互不影響。多租戶其實就是一種軟件設計結構。
所以。租戶模型其實就是分離數據的方式:
- 單租戶:一個應用一個數據庫。其實就是應用分離,數據分離。
- 多租戶:一個應用多個數據庫。就是同一個應用不同數據庫。
為什么需要多租戶?
剛畢業(yè)第一家公司,接觸的第一個項目的內容主要幫助客戶提高生產力。每次有一個很大的問題就是,合作一個客戶,項目復制一份出來,然后改成該客戶定制的功能需求。這樣就導致相同功能要更新多份代碼,還要注意可能會出現(xiàn)因不同客戶的不同需求問題。整個過程就導致了一個很大的維護成本的支出。
多租戶應用程序的維護更容易,只需根據每個租戶專屬標志,然后提供不同的功能,且公共的功能可以集中更新升級。
數據隔離方式
在 SaaS 系統(tǒng)中一般分離租戶的數據有兩種模型:
- 數據的邏輯分離:所有租戶只使用一個數據庫。它們的數據通過為每個租戶使用一個唯一標識符來分隔。
- 數據的物理分離:一個租戶分配一個數據庫。就是一個應用對應多個數據庫。每個數據庫就是一個租戶。這種方式在客戶的增長時擴展了應用的功能,也方便擴展數據庫
物理分離詳細實現(xiàn)
目標:每個請求過來,應用程序能夠識別租戶,并從該租戶數據庫中進行提供數據。
- 公共數據庫:存儲所有租戶相關全局配置和所有租戶數據庫信息。
- 租戶數據庫:每個租戶獨立的的數據庫,根據租戶需要保存數據。
啟動服務
創(chuàng)建 main 文件,并使用 Gin 框架。初始化一個簡單的應用程序并創(chuàng)建基本的路由。
func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) r.Run() }
數據庫配置
在公共數據庫創(chuàng)建一個保存租戶數據庫信息表并添加上租戶的數據庫。
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) , )
在配置文件中加入一個公共數據庫的連接配置,這樣就可以在服務啟動時第一次連接的是公共數據庫。接著需要實現(xiàn)根據請求連接到正確的租戶數據庫。主要使用 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 }
通過使用中間件來解析每個請求連接,從而確定整個請求是由哪個租戶數據庫來提供數據讀寫。中間件中主要的處理方式是得到租戶對應的數據庫連接名,然后從連接池中拿到該連接并設置在全局變量中。在業(yè)務邏輯處理中從全局拿到數據庫連接,就可以進行數據庫讀寫。
sr.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 ,這樣就可以正常進行數據讀寫。
其實可以從域名上解析對應的數據庫連接。這里最重要就是對數據庫的解析。這里的例子只是實驗使用,其中還有很多可優(yōu)化的點。比如可以考慮使用連接池,這樣就不用在項目啟動時都全部創(chuàng)建數據庫連接,造成浪費。
到此這篇關于Go 簡單實現(xiàn)多租戶數據庫隔離的文章就介紹到這了,更多相關Go 多租戶隔離內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
golang多次讀取http request body的問題分析
這篇文章主要給大家分析了golang多次讀取http request body的問題,文中通過代碼示例和圖文介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-01-01