劉 彬,程 凱,于 杰
1(金誠(chéng)信礦業(yè)管理股份有限公司,北京 100044)
2(北京宸控科技有限公司,北京 102200)
3(北京市新媒體技師學(xué)院,北京 102200)
隨著云計(jì)算的發(fā)展及應(yīng)用軟件的成熟,軟件即服務(wù) (Software as a Service,SaaS)[1]作為云計(jì)算的一種應(yīng)用形式越來(lái)越受到重視.多租戶數(shù)據(jù)架構(gòu)是搭建SaaS應(yīng)用平臺(tái)的關(guān)鍵技術(shù)之一,不僅需要在數(shù)據(jù)庫(kù)層面實(shí)現(xiàn)租戶之間數(shù)據(jù)的隔離[2],還要滿足租戶的定制需求.
目前幾種典型的多租戶共享存儲(chǔ)模型,包括透視表、稀疏表、塊表及塊折疊,都能保障租戶數(shù)據(jù)的隔離性和可定制性的需求,但仍存在各自的不足.例如,在透視表存儲(chǔ)模型中,租戶數(shù)據(jù)被拆成鍵值對(duì)形式的元組垂直存儲(chǔ),這使得重構(gòu)租戶邏輯關(guān)系需要做大量連接操作,重構(gòu)一個(gè)n列的表需要做n–1次連接;在稀疏表存儲(chǔ)模型中,不同租戶的邏輯表都被映射到一個(gè)列數(shù)很大的表中,例如Salesforce.com的數(shù)據(jù)表有500列[3],從而會(huì)導(dǎo)致表中包含大量空值,存儲(chǔ)空間利用率低;塊表存儲(chǔ)模型在透視表存儲(chǔ)模型的基礎(chǔ)上進(jìn)行了改進(jìn),一個(gè)塊中包含若干不同數(shù)據(jù)類型的字段,但在租戶數(shù)據(jù)類型相同的字段數(shù)量多的情況下,重構(gòu)租戶邏輯表仍然需要大量連接;塊折疊存儲(chǔ)模型在塊表存儲(chǔ)模型的基礎(chǔ)上做了進(jìn)一步改進(jìn),通過(guò)垂直劃分將租戶邏輯表中共有的屬性存儲(chǔ)在基本表中,而剩余的屬性仍然是采用塊表存儲(chǔ),并沒(méi)有解決塊表存儲(chǔ)模型中存在的問(wèn)題.綜上所述,目前并沒(méi)有完全成熟的多租戶數(shù)據(jù)庫(kù)架構(gòu)[4],因此如何提高多租戶數(shù)據(jù)庫(kù)性能仍然是值得研究的問(wèn)題.
本文提出一種稀疏表與塊表結(jié)合的存儲(chǔ)模型,旨在提升稀疏表存儲(chǔ)模型的存儲(chǔ)空間利用率,并結(jié)合塊表存儲(chǔ)模型以更好地滿足不同租戶的個(gè)性定制需求.
針對(duì)SaaS應(yīng)用場(chǎng)景下的多租戶數(shù)據(jù)共享存儲(chǔ)模型,國(guó)內(nèi)外學(xué)術(shù)界的研究者們已經(jīng)做過(guò)大量研究.文獻(xiàn)[5]中提出了一種基于SaaS化多租戶數(shù)據(jù)進(jìn)行分區(qū)的模型和策略,使得多租戶共享存儲(chǔ)模型能夠?qū)崿F(xiàn)由單節(jié)點(diǎn)向多節(jié)點(diǎn)的擴(kuò)展.文獻(xiàn)[6]中提出了一種在關(guān)系數(shù)據(jù)庫(kù)中集成xml的方案,即將xml數(shù)據(jù)類型的文檔插入到數(shù)據(jù)庫(kù)的大對(duì)象字段中,但對(duì)xml文檔進(jìn)行解析的過(guò)程較耗費(fèi)時(shí)間,從而影響數(shù)據(jù)庫(kù)整體性能.文獻(xiàn)[7]中提出了一種多稀疏表的存儲(chǔ)模型,即按照租戶邏輯表的列數(shù)將其映射到不同列數(shù)的稀疏表中,較之傳統(tǒng)單稀疏表存儲(chǔ)模型減少了空值存儲(chǔ),提升了存儲(chǔ)空間利用率,但只是通過(guò)預(yù)留列的方式滿足租戶對(duì)邏輯表的擴(kuò)展需求,而當(dāng)擴(kuò)展列數(shù)超出稀疏表列數(shù)時(shí)仍需要進(jìn)行大量的數(shù)據(jù)遷移,極大影響數(shù)據(jù)庫(kù)性能.文獻(xiàn)[8]從緩存的角度提升多租戶數(shù)據(jù)庫(kù)查詢性能,提出了一種基于塊折疊存儲(chǔ)模型的緩存管理機(jī)制.文獻(xiàn)[9]中針對(duì)傳統(tǒng)塊折疊存儲(chǔ)模型提出了一種多級(jí)塊折疊存儲(chǔ)模型,較之傳統(tǒng)塊折疊存儲(chǔ)模型,提升了查詢性能和存儲(chǔ)空間利用率.文獻(xiàn)[10]中針對(duì)多租戶數(shù)據(jù)庫(kù)一般定制下的自適應(yīng)數(shù)據(jù)模式和高可定制下的個(gè)性化數(shù)據(jù)模式分別進(jìn)行了設(shè)計(jì),并對(duì)基于相變存儲(chǔ)器的數(shù)據(jù)庫(kù)索引作了設(shè)計(jì),從而達(dá)到改善SaaS化系統(tǒng)的存儲(chǔ)開(kāi)銷、可擴(kuò)展性和系統(tǒng)性能的目的.綜上所述,現(xiàn)有的多租戶共享存儲(chǔ)模型重構(gòu)租戶邏輯表仍需要較多連接操作,其存儲(chǔ)空間利用率和查詢?cè)L問(wèn)效率較低,需進(jìn)一步改善.
本文提出一種稀疏表與塊表結(jié)合的存儲(chǔ)模型,將租戶屬性劃分為在應(yīng)用服務(wù)商提供的邏輯表的基礎(chǔ)之上定制的屬性和租戶擴(kuò)展的自定義屬性,然后分別映射到一組列數(shù)不同的稀疏表中及塊表中,較之傳統(tǒng)稀疏表存儲(chǔ)模型,在存儲(chǔ)空間利用率及查詢效率上都有所改善.
對(duì)于多租戶共享存儲(chǔ)模型來(lái)說(shuō),盡管在實(shí)際的物理存儲(chǔ)結(jié)構(gòu)中,各個(gè)租戶的數(shù)據(jù)都被存儲(chǔ)在同樣的數(shù)據(jù)庫(kù)及數(shù)據(jù)表中,但是租戶之間不會(huì)感覺(jué)到其他租戶的存在,更不會(huì)訪問(wèn)其他租戶的數(shù)據(jù).租戶可以在應(yīng)用服務(wù)商提供的邏輯表的基礎(chǔ)之上定制各自需要的屬性,也可以往邏輯表中添加新的自定義的屬性,甚至還可以自定義新的邏輯表.如圖1所示,各個(gè)租戶可以針對(duì)SaaS平臺(tái)中的各個(gè)應(yīng)用,通過(guò)定制生成各自私有的邏輯表,之后就可以針對(duì)邏輯表做查詢和訪問(wèn)操作,而不用關(guān)心底層數(shù)據(jù)庫(kù)中表的結(jié)構(gòu).
圖1 租戶邏輯定制示意圖
物理存儲(chǔ)是指數(shù)據(jù)庫(kù)中表的組織形式,對(duì)于上層租戶來(lái)說(shuō)是透明的.數(shù)據(jù)庫(kù)中包括三種類型的表,分別是:稀疏表、塊表及元數(shù)據(jù)表.
塊表用于存儲(chǔ)租戶自定義字段,當(dāng)租戶在邏輯表中擴(kuò)展自定義字段時(shí),若該字段數(shù)據(jù)類型與塊表中包含的某個(gè)字段的數(shù)據(jù)類型一致,則將該字段映射到塊表中相應(yīng)的字段存儲(chǔ).因此對(duì)于塊表中字段的選取應(yīng)結(jié)合具體SaaS應(yīng)用的業(yè)務(wù)特征,進(jìn)而選擇最常用的幾種數(shù)據(jù)類型.
稀疏表用于存儲(chǔ)租戶在邏輯表上定制的字段、字段的數(shù)據(jù)類型不包含在塊表中的租戶自定義字段以及租戶自定義的邏輯表中的字段.本文在傳統(tǒng)稀疏表的基礎(chǔ)上添加了row字段,表示租戶邏輯表中數(shù)據(jù)記錄的行號(hào),并作為重構(gòu)租戶邏輯關(guān)系時(shí)稀疏表和塊表的連接條件之一.
元數(shù)據(jù)表包括對(duì)稀疏表進(jìn)行描述的表及對(duì)塊表進(jìn)行描述的表.其中,對(duì)稀疏表進(jìn)行描述的表存儲(chǔ)了稀疏表與邏輯表之間的對(duì)應(yīng)關(guān)系以及各個(gè)稀疏表的列數(shù).而對(duì)塊表進(jìn)行描述的表存儲(chǔ)了塊表與邏輯表之間的對(duì)應(yīng)關(guān)系以及塊表的表名和表中字段的數(shù)據(jù)類型.
模式映射是建立邏輯表與物理表之間的映射關(guān)系,即將邏輯表中的字段對(duì)應(yīng)到物理表中.首先要合理劃分一組不同列數(shù)的稀疏表并給一組塊表設(shè)置合適的字段.針對(duì)不同列數(shù)的稀疏表的劃分,本文提出的策略是,先統(tǒng)計(jì)應(yīng)用服務(wù)商為租戶提供的各個(gè)邏輯表的字段個(gè)數(shù),并保存到集合sl{sl_1,sl_2,…,sl_n}中,字段個(gè)數(shù)相同的只計(jì)一次;再依次取集合sl中的值加α作為列數(shù)來(lái)創(chuàng)建相應(yīng)列數(shù)的稀疏表,α表示預(yù)留列數(shù),用于存儲(chǔ)租戶擴(kuò)展字段.針對(duì)塊表中字段的設(shè)置,由于稀疏表中預(yù)留的列數(shù)有限,且租戶的定制不是一次性完成的,當(dāng)租戶向已有的邏輯表中添加新的自定義的字段時(shí),應(yīng)讓更多的擴(kuò)展列映射存儲(chǔ)到塊表中,少數(shù)的擴(kuò)展列存儲(chǔ)到稀疏表中,這樣可以降低稀疏表列數(shù)溢出的概率,因此可以根據(jù)SaaS應(yīng)用的業(yè)務(wù)特征來(lái)選擇擴(kuò)展字段可能的數(shù)據(jù)類型.
模式映射的具體過(guò)程為:當(dāng)租戶定制邏輯表時(shí),先判斷是否為租戶自定義的邏輯表,若是自定義的,則先獲取每個(gè)稀疏表的列數(shù),再根據(jù)二分查找法找到列數(shù)大于且最接近的該邏輯表字段數(shù)的稀疏表,再在相應(yīng)的元數(shù)據(jù)表中存儲(chǔ)映射關(guān)系;若不是租戶自定義的邏輯表,則需要進(jìn)一步判斷該邏輯表中是否包含租戶自定義的字段,若不包含則映射到相應(yīng)的稀疏表中,若包含自定義的字段,則通過(guò)查詢?cè)獢?shù)據(jù)表,判斷該字段的數(shù)據(jù)類型是否與塊表中的某個(gè)字段數(shù)據(jù)類型一致,再根據(jù)判斷的結(jié)果將其映射到相應(yīng)的稀疏表或者塊表中.由邏輯表映射到物理表的過(guò)程如圖2所示.
圖2 模式映射過(guò)程
要驗(yàn)證稀疏表與塊表結(jié)合的共享存儲(chǔ)模型的合理性,只需要證明該共享存儲(chǔ)模型與傳統(tǒng)關(guān)系模型是等價(jià)關(guān)系即可.證明的過(guò)程大致可分為兩個(gè)步驟:
第一步要證明傳統(tǒng)關(guān)系模型可以等價(jià)轉(zhuǎn)化為稀疏表與塊表結(jié)合的存儲(chǔ)模型,即對(duì)于租戶定制的任意一個(gè)邏輯表,假設(shè)為R,對(duì)于R中的任意屬性V,其都可以被映射存儲(chǔ)到稀疏表與塊表結(jié)合的存儲(chǔ)模型中.首先若V是應(yīng)用服務(wù)商提供的屬性,則將V映射存儲(chǔ)到相應(yīng)的稀疏表中;其次若V是租戶自定義的屬性,則根據(jù)該屬性的數(shù)據(jù)類型分為兩種情況,若塊表中包含與V的數(shù)據(jù)類型相同的字段,則將V映射存儲(chǔ)到塊表中,否則將V映射存儲(chǔ)到相應(yīng)的稀疏表中;最后若V是租戶自定義的邏輯表中的屬性,則將V映射存儲(chǔ)到相應(yīng)的稀疏表中.
第二步要證明稀疏表與塊表結(jié)合的存儲(chǔ)模型可以等價(jià)轉(zhuǎn)化為傳統(tǒng)關(guān)系模型,即通過(guò)選擇、連接及投影三種標(biāo)準(zhǔn)關(guān)系運(yùn)算重構(gòu)租戶邏輯關(guān)系.首先對(duì)于租戶自定義的邏輯關(guān)系,假設(shè)為租戶8的device表,先根據(jù)md_sparse表中的元數(shù)據(jù)信息找到對(duì)應(yīng)的稀疏表,假設(shè)為sparse_i表,然后對(duì)sparse_i表做選擇和投影操作形成視圖X,關(guān)系代數(shù)表示為:
最后對(duì)X進(jìn)行更名操作,即形成租戶邏輯關(guān)系R,關(guān)系代數(shù)表示為:
其中,i=1,2,…,n;其次對(duì)于應(yīng)用服務(wù)商提供給租戶的邏輯關(guān)系,假設(shè)為租戶8的user表,并假設(shè)租戶8在user表中的定制屬性存儲(chǔ)在稀疏表sparse_i中,先對(duì)chunktable表做自身連接及投影操作形成視圖X,關(guān)系代數(shù)表示為:
再對(duì)X和相應(yīng)的稀疏表做自然連接及投影操作形成視圖Y,關(guān)系代數(shù)表示為:
最后對(duì)Y做更名操作形成租戶邏輯關(guān)系R,關(guān)系代數(shù)表示為:
上述公式中,i=1,2,…,n.
通過(guò)以上兩個(gè)步驟,即可證明本文提出的稀疏表與塊表結(jié)合的存儲(chǔ)模型與傳統(tǒng)關(guān)系模型等價(jià),即租戶所有基于傳統(tǒng)關(guān)系模型的操作都可以轉(zhuǎn)化為基于稀疏表與塊表結(jié)合的存儲(chǔ)模型完成.
對(duì)于傳統(tǒng)的稀疏表存儲(chǔ)模型和塊表存儲(chǔ)模型來(lái)說(shuō),影響存儲(chǔ)空間利用率的最大因素是表中的空值.空值既包括該屬性值為空,還包括租戶未定制而產(chǎn)生的空值.由于各個(gè)租戶邏輯表的結(jié)構(gòu)各異且稀疏表列數(shù)大,稀疏表中必然存在租戶未定制該列而產(chǎn)生的空值.與傳統(tǒng)稀疏表存儲(chǔ)模型中只有一張寬度很大的稀疏表相比,稀疏表與塊表結(jié)合的存儲(chǔ)模型中劃分了一組不同列數(shù)的稀疏表,進(jìn)而將租戶邏輯表映射到列數(shù)與之接近的稀疏表中,因此稀疏表中的空值大量減少.而塊表中用于映射租戶邏輯字段的列數(shù)很少,因此塊表中的空值相對(duì)于傳統(tǒng)稀疏表存儲(chǔ)模型來(lái)說(shuō)也很少.
假設(shè)平臺(tái)中有n個(gè)租戶,且一共定制了m個(gè)邏輯表 (Tl1,Tl2,…,Tlm),Tli的列數(shù)為Cli,行數(shù)為Rli,Cli列中有Ei列自定義的字段存儲(chǔ)在塊表中.設(shè)根據(jù)邏輯表的字段個(gè)數(shù)劃分了k個(gè)列數(shù)不同的稀疏表(TS1,TS2,…,TSk),Tsi的列數(shù)為Csi,且有Cs1<Cs2< … <Csk,Tsi中存儲(chǔ)了Li個(gè)租戶邏輯表.設(shè)塊表的列數(shù)為Tc,且塊表中存儲(chǔ)了Ln個(gè)邏輯表中的自定義字段.則可得到本文中存儲(chǔ)模型的存儲(chǔ)利用率ρ為:
設(shè)傳統(tǒng)稀疏表存儲(chǔ)模型中表的列數(shù)為Max,則該存儲(chǔ)模型的存儲(chǔ)利用率ρ,為:
將式(6)與式(7)相減,可得到兩種存儲(chǔ)模型下的存儲(chǔ)空間利用率的差值,將該值簡(jiǎn)化后的分子表示為:
由式(8)可看出當(dāng)一組稀疏表的存儲(chǔ)容量之和加上塊表的容量等于傳統(tǒng)稀疏表的容量時(shí),兩種存儲(chǔ)模型下的存儲(chǔ)空間利用率才相等.然而塊表中的列數(shù)一般會(huì)比寬度最小的稀疏表列數(shù)還少,且通過(guò)換算可以得到:
因此我們可以得出稀疏表與塊表結(jié)合的存儲(chǔ)模型較之傳統(tǒng)稀疏表存儲(chǔ)模型在存儲(chǔ)空間利用率上有所改善.
由于數(shù)據(jù)庫(kù)中實(shí)際的物理存儲(chǔ)結(jié)構(gòu)對(duì)租戶來(lái)說(shuō)是透明的,且所有租戶對(duì)于數(shù)據(jù)的查詢和訪問(wèn)操作都是針對(duì)其各自私有的邏輯表進(jìn)行的,因此需要通過(guò)程序中的查詢重寫器將租戶針對(duì)邏輯表發(fā)起的邏輯SQL請(qǐng)求轉(zhuǎn)換為針對(duì)物理存儲(chǔ)結(jié)構(gòu)的SQL請(qǐng)求,最后將結(jié)果返回給上層租戶.
查詢轉(zhuǎn)換的過(guò)程可分為如下四個(gè)步驟:
(1)獲取租戶唯一標(biāo)識(shí),并從邏輯SQL請(qǐng)求中獲取邏輯表的表名、要查詢的字段名及查詢條件
(2)查詢?cè)獢?shù)據(jù)表,并根據(jù)邏輯表的表名和租戶唯一標(biāo)識(shí)獲取該邏輯表存在映射關(guān)系的物理表的表名,再獲取邏輯表中的字段與相應(yīng)物理表中字段之間的對(duì)應(yīng)關(guān)系
(3)根據(jù)上一步驟中得到的邏輯表中字段與物理表中字段之間的對(duì)應(yīng)關(guān)系來(lái)構(gòu)建針對(duì)物理表進(jìn)行查詢的SQL語(yǔ)句,并分別為該SQL語(yǔ)句中查詢的所有物理表中的字段名設(shè)置別名,且別名均為邏輯表中與之對(duì)應(yīng)的字段名
(4)重新改寫邏輯SQL請(qǐng)求,用上一步驟中得到的SQL語(yǔ)句來(lái)代替原始SQL語(yǔ)句中邏輯表的表名,即接在from子句之后表名
經(jīng)過(guò)上述四個(gè)步驟,可將邏輯SQL請(qǐng)求轉(zhuǎn)換為物理SQL請(qǐng)求,從而完成查詢?cè)L問(wèn)操作.
操作系統(tǒng):64 位 Windows 8.1;處理器:Core i5-4210M @ 2.60 GHz 雙核;內(nèi)存:8 GB
數(shù)據(jù)庫(kù):MySQL 5.5.28
實(shí)驗(yàn)中通過(guò)程序生成了模擬的100個(gè)租戶user表的數(shù)據(jù),然后將其分別映射到稀疏表與塊表結(jié)合的存儲(chǔ)模型及傳統(tǒng)稀疏表存儲(chǔ)模型的物理表中.傳統(tǒng)稀疏表用1張列數(shù)為500的大寬表存儲(chǔ)所有租戶的數(shù)據(jù),稀疏表與塊表結(jié)合的存儲(chǔ)模型采用了5張列數(shù)分別為33、43、53、63、73的稀疏表和1張列數(shù)為10的塊表存儲(chǔ)所有租戶數(shù)據(jù).各個(gè)租戶的user表中的字段個(gè)數(shù)為15–34,且每張user表中都有1000條記錄.
對(duì)于存儲(chǔ)空間利用率的分析,本文中采取的做法是分別將傳統(tǒng)稀疏表存儲(chǔ)模型和稀疏表與塊表結(jié)合的存儲(chǔ)模型下的數(shù)據(jù)表導(dǎo)出為SQL文件,分別命名為“稀疏表與塊表.sql”和“single_sparse.sql”.比較兩個(gè)文件的大小,前者文件大小為25.5 MB,而后者文件大小為292 MB,由此可知稀疏表與塊表結(jié)合的存儲(chǔ)模型相比傳統(tǒng)的單稀疏表存儲(chǔ)模型顯著地提升了存儲(chǔ)空間利用率.
對(duì)于查詢效率的分析,本文中采取的做法是模擬多個(gè)租戶同時(shí)發(fā)起查詢,每個(gè)租戶發(fā)起400個(gè)查詢請(qǐng)求,然后計(jì)算不同并發(fā)查詢線程個(gè)數(shù)的情況下,租戶的平均查詢響應(yīng)時(shí)間.兩種存儲(chǔ)模型下的查詢效率對(duì)比如圖3所示.
圖3 兩種存儲(chǔ)模型的查詢效率對(duì)比
由圖3可看出,稀疏表與塊表結(jié)合共享存儲(chǔ)模型的平均查詢時(shí)延小于傳統(tǒng)稀疏表共享存儲(chǔ)模型,且隨著并發(fā)查詢線程數(shù)量的增加,差值逐漸增大,表明新提出的共享存儲(chǔ)模型對(duì)查詢?cè)L問(wèn)效率進(jìn)行了改善.
針對(duì)傳統(tǒng)單稀疏表存儲(chǔ)模型存儲(chǔ)空間利用率低及塊表存儲(chǔ)模型連接次數(shù)多的問(wèn)題,本文提出一種稀疏表與塊表結(jié)合的存儲(chǔ)模型.該存儲(chǔ)模型采用一組列數(shù)不同的稀疏表及塊表共享存儲(chǔ)多租戶數(shù)據(jù),并構(gòu)建相應(yīng)的元數(shù)據(jù)表用于存儲(chǔ)對(duì)稀疏表和塊表進(jìn)行描述的信息.將租戶基于服務(wù)商提供的邏輯表定制的屬性及租戶自定義的邏輯表中的屬性映射到列數(shù)接近的稀疏表中,而根據(jù)字段的數(shù)據(jù)類型將租戶在邏輯表中自定義的屬性映射到塊表或者相應(yīng)的稀疏表中.通過(guò)存儲(chǔ)分析及實(shí)驗(yàn)分析對(duì)比,并從存儲(chǔ)空間利用率,查詢效率及可定制性三個(gè)方面綜合比較,該存儲(chǔ)模型性能優(yōu)于傳統(tǒng)的稀疏表存儲(chǔ)模型.