Go 簡(jiǎn)單實(shí)現(xiàn)多租戶(hù)數(shù)據(jù)庫(kù)隔離
多租戶(hù)
在 SaaS 系統(tǒng)中多租戶(hù)是一個(gè)很重要的架構(gòu),在服務(wù)上僅需運(yùn)行一個(gè)軟件實(shí)例就能夠支持每個(gè)租戶(hù)的功能,它們之間的數(shù)據(jù)互相隔離。就比如 Gitee ,每個(gè)用戶(hù)或組織都擁有自己的空間。它們自己的數(shù)據(jù)僅在自己的空間內(nèi)流通,彼此之間互不影響。多租戶(hù)其實(shí)就是一種軟件設(shè)計(jì)結(jié)構(gòu)。
所以。租戶(hù)模型其實(shí)就是分離數(shù)據(jù)的方式:
- 單租戶(hù):一個(gè)應(yīng)用一個(gè)數(shù)據(jù)庫(kù)。其實(shí)就是應(yīng)用分離,數(shù)據(jù)分離。
- 多租戶(hù):一個(gè)應(yīng)用多個(gè)數(shù)據(jù)庫(kù)。就是同一個(gè)應(yīng)用不同數(shù)據(jù)庫(kù)。
為什么需要多租戶(hù)?
剛畢業(yè)第一家公司,接觸的第一個(gè)項(xiàng)目的內(nèi)容主要幫助客戶(hù)提高生產(chǎn)力。每次有一個(gè)很大的問(wèn)題就是,合作一個(gè)客戶(hù),項(xiàng)目復(fù)制一份出來(lái),然后改成該客戶(hù)定制的功能需求。這樣就導(dǎo)致相同功能要更新多份代碼,還要注意可能會(huì)出現(xiàn)因不同客戶(hù)的不同需求問(wèn)題。整個(gè)過(guò)程就導(dǎo)致了一個(gè)很大的維護(hù)成本的支出。
多租戶(hù)應(yīng)用程序的維護(hù)更容易,只需根據(jù)每個(gè)租戶(hù)專(zhuān)屬標(biāo)志,然后提供不同的功能,且公共的功能可以集中更新升級(jí)。
數(shù)據(jù)隔離方式
在 SaaS 系統(tǒng)中一般分離租戶(hù)的數(shù)據(jù)有兩種模型:
- 數(shù)據(jù)的邏輯分離:所有租戶(hù)只使用一個(gè)數(shù)據(jù)庫(kù)。它們的數(shù)據(jù)通過(guò)為每個(gè)租戶(hù)使用一個(gè)唯一標(biāo)識(shí)符來(lái)分隔。
- 數(shù)據(jù)的物理分離:一個(gè)租戶(hù)分配一個(gè)數(shù)據(jù)庫(kù)。就是一個(gè)應(yīng)用對(duì)應(yīng)多個(gè)數(shù)據(jù)庫(kù)。每個(gè)數(shù)據(jù)庫(kù)就是一個(gè)租戶(hù)。這種方式在客戶(hù)的增長(zhǎng)時(shí)擴(kuò)展了應(yīng)用的功能,也方便擴(kuò)展數(shù)據(jù)庫(kù)
物理分離詳細(xì)實(shí)現(xiàn)
目標(biāo):每個(gè)請(qǐng)求過(guò)來(lái),應(yīng)用程序能夠識(shí)別租戶(hù),并從該租戶(hù)數(shù)據(jù)庫(kù)中進(jìn)行提供數(shù)據(jù)。
- 公共數(shù)據(jù)庫(kù):存儲(chǔ)所有租戶(hù)相關(guān)全局配置和所有租戶(hù)數(shù)據(jù)庫(kù)信息。
- 租戶(hù)數(shù)據(jù)庫(kù):每個(gè)租戶(hù)獨(dú)立的的數(shù)據(jù)庫(kù),根據(jù)租戶(hù)需要保存數(shù)據(jù)。
啟動(dòng)服務(wù)
創(chuàng)建 main 文件,并使用 Gin 框架。初始化一個(gè)簡(jiǎn)單的應(yīng)用程序并創(chuàng)建基本的路由。
func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) r.Run() }
數(shù)據(jù)庫(kù)配置
在公共數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)保存租戶(hù)數(shù)據(jù)庫(kù)信息表并添加上租戶(hù)的數(shù)據(jù)庫(kù)。
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) , )
在配置文件中加入一個(gè)公共數(shù)據(jù)庫(kù)的連接配置,這樣就可以在服務(wù)啟動(dòng)時(shí)第一次連接的是公共數(shù)據(jù)庫(kù)。接著需要實(shí)現(xiàn)根據(jù)請(qǐng)求連接到正確的租戶(hù)數(shù)據(jù)庫(kù)。主要使用 gorm 的 DBResolver ,多個(gè)數(shù)據(jù)庫(kù)的連接支持
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 負(fù)載均衡策略 ? Policy: dbresolver.RandomPolicy{}, }) ? ?return allDbs }
通過(guò)使用中間件來(lái)解析每個(gè)請(qǐng)求連接,從而確定整個(gè)請(qǐng)求是由哪個(gè)租戶(hù)數(shù)據(jù)庫(kù)來(lái)提供數(shù)據(jù)讀寫(xiě)。中間件中主要的處理方式是得到租戶(hù)對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接名,然后從連接池中拿到該連接并設(shè)置在全局變量中。在業(yè)務(wù)邏輯處理中從全局拿到數(shù)據(jù)庫(kù)連接,就可以進(jìn)行數(shù)據(jù)庫(kù)讀寫(xiě)。
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) }
這樣就可以啟動(dòng)項(xiàng)目,然后訪問(wèn) localhost:8003?dbName=db1 ,這樣就可以正常進(jìn)行數(shù)據(jù)讀寫(xiě)。
其實(shí)可以從域名上解析對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接。這里最重要就是對(duì)數(shù)據(jù)庫(kù)的解析。這里的例子只是實(shí)驗(yàn)使用,其中還有很多可優(yōu)化的點(diǎn)。比如可以考慮使用連接池,這樣就不用在項(xiàng)目啟動(dòng)時(shí)都全部創(chuàng)建數(shù)據(jù)庫(kù)連接,造成浪費(fèi)。
到此這篇關(guān)于Go 簡(jiǎn)單實(shí)現(xiàn)多租戶(hù)數(shù)據(jù)庫(kù)隔離的文章就介紹到這了,更多相關(guān)Go 多租戶(hù)隔離內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解基于Mybatis-plus多租戶(hù)實(shí)現(xiàn)方案
- MyBatis利用MyCat實(shí)現(xiàn)多租戶(hù)的簡(jiǎn)單思路分享
- SpringBoot集成Mybatis-Plus多租戶(hù)架構(gòu)實(shí)現(xiàn)
- 基于Mybatis-plus實(shí)現(xiàn)多租戶(hù)架構(gòu)的全過(guò)程
- Springboot?多租戶(hù)SaaS搭建方案
- SpringCloud 搭建企業(yè)級(jí)開(kāi)發(fā)框架之實(shí)現(xiàn)多租戶(hù)多平臺(tái)短信通知服務(wù)(微服務(wù)實(shí)戰(zhàn))
- Mybatis-plus多租戶(hù)項(xiàng)目實(shí)戰(zhàn)進(jìn)階指南
- Oracle?CDB管理實(shí)現(xiàn)多租戶(hù)管理功能
- vue項(xiàng)目多租戶(hù)環(huán)境變量的設(shè)置
相關(guān)文章
golang多次讀取http request body的問(wèn)題分析
這篇文章主要給大家分析了golang多次讀取http request body的問(wèn)題,文中通過(guò)代碼示例和圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01Go語(yǔ)言實(shí)現(xiàn)操作MySQL的基礎(chǔ)知識(shí)總結(jié)
這篇文章主要總結(jié)一下怎么使用Go語(yǔ)言操作MySql數(shù)據(jù)庫(kù),文中的示例代碼講解詳細(xì),需要的朋友可以參考以下內(nèi)容,希望對(duì)大家有所幫助2022-09-09手把手帶你走進(jìn)Go語(yǔ)言之類(lèi)型轉(zhuǎn)換
每個(gè)函數(shù)都可以強(qiáng)制將一個(gè)表達(dá)式轉(zhuǎn)換成某種特定數(shù)據(jù)類(lèi)型,本文給大家介紹了在Go語(yǔ)言中類(lèi)型轉(zhuǎn)換的具體用法,講述的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值2021-09-09詳解Golang如何優(yōu)雅接入多個(gè)遠(yuǎn)程配置中心
這篇文章主要為大家為大家介紹了Golang如何優(yōu)雅接入多個(gè)遠(yuǎn)程配置中心詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Go語(yǔ)言操作MySQL的知識(shí)總結(jié)
Go語(yǔ)言中的database/sql包提供了保證SQL或類(lèi)SQL數(shù)據(jù)庫(kù)的泛用接口,并不提供具體的數(shù)據(jù)庫(kù)驅(qū)動(dòng)。本文介紹了Go語(yǔ)言操作MySQL的相關(guān)知識(shí),感興趣的可以了解一下2022-11-11Go語(yǔ)言中常用語(yǔ)法編寫(xiě)與優(yōu)化技巧小結(jié)
為了充分利用?Go?的潛力,我們需要了解如何優(yōu)化?Go?程序,本文將介紹一些常見(jiàn)的?Go?語(yǔ)言?xún)?yōu)化技巧,并通過(guò)實(shí)際例子進(jìn)行說(shuō)明,希望對(duì)大家有所幫助2024-02-02Go語(yǔ)言實(shí)現(xiàn)RSA加解密算法詳解
隨著互聯(lián)網(wǎng)的高速發(fā)展,人們對(duì)安全的要求也越來(lái)越高,加解密也變得越來(lái)越重要,本文主要為大家介紹了Go語(yǔ)言中實(shí)現(xiàn)RSA加解密與簽名驗(yàn)證算法,希望對(duì)大家有所幫助2023-06-06