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