張雅文,劉春霞,白尚旺,黨偉超
(太原科技大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,太原030024)
軟件即服務(wù)(Software as a service, SaaS)是隨著云計(jì)算發(fā)展起來(lái)的一種新型軟件服務(wù)模式。SaaS環(huán)境下,多租戶(hù)數(shù)據(jù)存儲(chǔ)一直是研究領(lǐng)域的熱點(diǎn)?;趯挶淼臄?shù)據(jù)存儲(chǔ)模式可以有效解決多租戶(hù)數(shù)據(jù)存儲(chǔ)問(wèn)題,表的數(shù)量不會(huì)隨著租戶(hù)數(shù)量的增加而增加,且由于是整行存儲(chǔ)數(shù)據(jù)也不用進(jìn)行表的多次連接,但寬表可能會(huì)造成大量的空值產(chǎn)生。因此針對(duì)SaaS應(yīng)用單實(shí)例多租賃的特點(diǎn),在保證租戶(hù)定制需求的基礎(chǔ)上,有必要研究新的數(shù)據(jù)存儲(chǔ)模式,以提高存儲(chǔ)空間利用率和查詢(xún)效率。
SaaS模式是通過(guò)Internet提供軟件的模式,用戶(hù)不需要安裝軟件,只需要連接到網(wǎng)絡(luò)就可以使用SaaS模式提供的軟件[1-2]。用戶(hù)可以根據(jù)自身需求以租賃的方式對(duì)軟件進(jìn)行使用,使得成本遠(yuǎn)遠(yuǎn)要比在本地部署專(zhuān)有軟件的成本低。
數(shù)據(jù)的多租戶(hù)化是SaaS應(yīng)用多租戶(hù)化的重要組成部分,SaaS應(yīng)用采用一個(gè)應(yīng)用實(shí)例為多個(gè)租戶(hù)提供服務(wù)[2-3],各個(gè)租戶(hù)在視圖層又有不同的數(shù)據(jù)模式,所以需要有一個(gè)不同于傳統(tǒng)應(yīng)用的數(shù)據(jù)存儲(chǔ)方案,以實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)、隔離,及用戶(hù)訪問(wèn)數(shù)據(jù)的便捷性。
目前SaaS多租戶(hù)數(shù)據(jù)存儲(chǔ)已有了一些解決方案。例如擴(kuò)展表方法將租戶(hù)共享模式部分公共存儲(chǔ),租戶(hù)單獨(dú)模式部分分開(kāi)存儲(chǔ),在一定程度上共享了租戶(hù)數(shù)據(jù),減少了存儲(chǔ)開(kāi)銷(xiāo),但是沒(méi)有解決表數(shù)目跟隨租戶(hù)數(shù)目的增長(zhǎng)而增長(zhǎng);透視表采取垂直存儲(chǔ)的策略,將租戶(hù)數(shù)據(jù)拆解成(key,value)的方式進(jìn)行存儲(chǔ),這樣減少了空值的數(shù)量,但是元組重組困難,如果想要重組含有n列的某租戶(hù)的邏輯表,則需要進(jìn)行n-1次的連接操作[5]。
Salesforce作為全球最大的SaaS服務(wù)提供商,提出了基于寬表的存儲(chǔ)模式進(jìn)行數(shù)據(jù)存儲(chǔ),屬于共享數(shù)據(jù)庫(kù)共享模式的數(shù)據(jù)存儲(chǔ)架構(gòu),能夠共用存儲(chǔ)結(jié)構(gòu)和資源,保證資源使用效率[6-7]。寬表存儲(chǔ)數(shù)據(jù)具有很大的稀疏性,可能產(chǎn)生大量的空值,原因有兩種:一是租戶(hù)未定制該列,為模式空;二是租戶(hù)定制了該列而列值為空,為值空[8]。在寬表的存儲(chǔ)模式下,空值主要為模式空。為減少模式空值的產(chǎn)生,降低空值對(duì)數(shù)據(jù)查詢(xún)的影響,本文將單寬表的存儲(chǔ)模式擴(kuò)展為多寬表的存儲(chǔ)模式,并提出將用戶(hù)發(fā)起的SQL查詢(xún)語(yǔ)句轉(zhuǎn)換為可以直接作用于數(shù)據(jù)庫(kù)的SQL查詢(xún)語(yǔ)句,以方便租戶(hù)查詢(xún)數(shù)據(jù)時(shí)進(jìn)行模式映射和查詢(xún)重寫(xiě)。
寬表的存儲(chǔ)模式是一種共享數(shù)據(jù)庫(kù)共享模式的數(shù)據(jù)存儲(chǔ)架構(gòu)。由于租戶(hù)的數(shù)據(jù)存儲(chǔ)在一張寬表中,所以數(shù)據(jù)表的數(shù)目不會(huì)隨租戶(hù)數(shù)量的變化而變化,也不會(huì)發(fā)生膨脹,節(jié)省了數(shù)據(jù)庫(kù)的存儲(chǔ)空間。所以基于寬表的存儲(chǔ)模式是一種有效解決多租戶(hù)數(shù)據(jù)存儲(chǔ)問(wèn)題的模式。
SaaS區(qū)別于傳統(tǒng)軟件的重要差別就是多租戶(hù)的模式,多租戶(hù)架構(gòu)是SaaS應(yīng)用的基本特性,多個(gè)租戶(hù)共享一個(gè)實(shí)例,租戶(hù)的數(shù)據(jù)既是隔離的也是共享的[9]。物理層面上,租戶(hù)的數(shù)據(jù)共同存儲(chǔ)在同一個(gè)數(shù)據(jù)模式下,邏輯層面上,通過(guò)租戶(hù)特有的標(biāo)識(shí)對(duì)其進(jìn)行區(qū)別,實(shí)現(xiàn)數(shù)據(jù)的隔離。
圖 1 多租戶(hù)架構(gòu)
Fig.1 Multi-tenancy Infrastructure
圖1描述了寬表模式下的多租戶(hù)架構(gòu),包含4個(gè)層次。最底層是所有租戶(hù)使用的業(yè)務(wù)數(shù)據(jù)以及元數(shù)據(jù),這些數(shù)據(jù)以寬表的方式存儲(chǔ)在數(shù)據(jù)庫(kù)中。緊鄰底層的是模式映射和查詢(xún)重寫(xiě)技術(shù)層,相當(dāng)于一個(gè)中間件,以實(shí)現(xiàn)邏輯視圖與物理存儲(chǔ)結(jié)構(gòu)的透明轉(zhuǎn)換[10]。頂部?jī)蓪邮荢aaS應(yīng)用和租戶(hù)應(yīng)用,多個(gè)租戶(hù)應(yīng)用可以宿主于一個(gè)SaaS應(yīng)用。
Salesforce使用的存儲(chǔ)模式是寬表。寬表的主要數(shù)據(jù)結(jié)構(gòu)是由租戶(hù)標(biāo)識(shí)Tenantid和屬于租戶(hù)的某表的標(biāo)識(shí)TableName,以及N列的數(shù)據(jù)列組成,數(shù)據(jù)列的類(lèi)型使用可以靈活轉(zhuǎn)換為其他類(lèi)型的變長(zhǎng)字符串類(lèi)型。
寬表是整行存儲(chǔ)數(shù)據(jù),不需要做大量的連接操作,也符合大部分人的存儲(chǔ)習(xí)慣,這是它最大的優(yōu)勢(shì)。但是可能會(huì)造成大量的空值,占用存儲(chǔ)空間??梢酝ㄟ^(guò)對(duì)寬表進(jìn)行改進(jìn),形成多寬表的存儲(chǔ)方式,減少空值的出現(xiàn)。
多寬表的數(shù)據(jù)存儲(chǔ)模式是將單個(gè)的寬表用不同列的多表代替來(lái)存儲(chǔ)業(yè)務(wù)數(shù)據(jù),通過(guò)元數(shù)據(jù)對(duì)業(yè)務(wù)數(shù)據(jù)進(jìn)行描述,元數(shù)據(jù)表保存了租戶(hù)數(shù)據(jù)模式與實(shí)際物理存儲(chǔ)位置之間的映射關(guān)系。
圖2描述了多寬表存儲(chǔ)模式下的數(shù)據(jù)結(jié)構(gòu)定義。其中包含兩種類(lèi)型的表:一種為元數(shù)據(jù)表MetaDataFields和MetaTable,另一種為數(shù)據(jù)表DefSQLTable和一系列的寬表DatA.
圖2 多寬表數(shù)據(jù)結(jié)構(gòu)定義
Fig.2 Multiple universal table data structure definition
(1)DefSQLTable表用來(lái)存儲(chǔ)租戶(hù)邏輯私有表的SQL定義,邏輯私有表也就是租戶(hù)視圖層的數(shù)據(jù)模式,該定義中包含了租戶(hù)視圖層與數(shù)據(jù)庫(kù)層的映射關(guān)系。查詢(xún)重寫(xiě)時(shí)根據(jù)租戶(hù)查詢(xún)請(qǐng)求判斷所請(qǐng)求的SQL定義是否存在,若存在則從該表中獲取對(duì)應(yīng)的SQL定義,若不存在則通過(guò)訪問(wèn)元數(shù)據(jù)得到相應(yīng)的SQL定義并存儲(chǔ)在該表中。
(2)MetaTable表用來(lái)存儲(chǔ)一系列Data寬表的基本信息,包括寬表的表名和列數(shù)等信息,當(dāng)租戶(hù)需要選擇寬表進(jìn)行存儲(chǔ)時(shí),該信息作為租戶(hù)選擇寬表進(jìn)行存儲(chǔ)的依據(jù)。
(3)MetaDataFields表用來(lái)存儲(chǔ)Data寬表的信息以及其中屬性的各種信息。租戶(hù)標(biāo)識(shí)TenantId、租戶(hù)邏輯私有表標(biāo)識(shí)TableName以及寬表所屬列名fieldName聯(lián)合作為主鍵,通過(guò)RealTableName可以映射出租戶(hù)業(yè)務(wù)數(shù)據(jù)fieldName實(shí)際物理存儲(chǔ)位置,而RealFieldName可以映射Data寬表中fieldName的真正含義。fieldType、fieldLength、NullField分別表示fieldName的屬性:類(lèi)型、長(zhǎng)度、是否為空。
(4)Data1, Data2, Data x表示列數(shù)不同的寬表,寬表的列數(shù)呈遞增趨勢(shì)分布。租戶(hù)標(biāo)識(shí)TenantId和租戶(hù)邏輯私有表標(biāo)識(shí)TableName聯(lián)合作為主鍵,對(duì)租戶(hù)的業(yè)務(wù)數(shù)據(jù)進(jìn)行存儲(chǔ),它們的最大列數(shù)分別為valueMax,columnMax,rowMax.
多寬表的數(shù)據(jù)存儲(chǔ)模式是租戶(hù)的業(yè)務(wù)數(shù)據(jù)以多個(gè)寬表的形式存儲(chǔ)在數(shù)據(jù)庫(kù)中。在該模式下的查詢(xún)重寫(xiě),是指用戶(hù)發(fā)起的邏輯SQL查詢(xún)到實(shí)際作用于數(shù)據(jù)庫(kù)的物理SQL查詢(xún)的轉(zhuǎn)換,其中涉及到元數(shù)據(jù)的訪問(wèn)和SQL重寫(xiě)。在租戶(hù)對(duì)數(shù)據(jù)進(jìn)行查詢(xún)時(shí),租戶(hù)的數(shù)據(jù)模式與實(shí)際存儲(chǔ)模式不同,因此需要轉(zhuǎn)換,對(duì)SQL語(yǔ)句重寫(xiě),使邏輯SQL語(yǔ)句可以透明轉(zhuǎn)換為物理SQL語(yǔ)句。
在圖2數(shù)據(jù)定義的前提下,對(duì)數(shù)據(jù)的SQL查詢(xún)進(jìn)行重寫(xiě)。方法有兩種,一種是動(dòng)態(tài)SQL重寫(xiě),另一種是視圖定義SQL重寫(xiě)。
動(dòng)態(tài)SQL重寫(xiě),要先進(jìn)行復(fù)雜的SQL分析,因?yàn)樾枰獙?duì)SQL語(yǔ)句的每一項(xiàng)進(jìn)行解析,重寫(xiě)過(guò)程很復(fù)雜。例如執(zhí)行SQL語(yǔ)句select sold from Student where sno=’1’,首先需要找到Student所在的寬表,其次找到sold對(duì)應(yīng)的寬表的列,最后才能根據(jù)sno=’1’進(jìn)行查詢(xún)。如果查詢(xún)的列為多項(xiàng),則在重寫(xiě)過(guò)程中需要?jiǎng)討B(tài)地獲得查詢(xún)的每一項(xiàng),并且找到其映射關(guān)系。但是對(duì)于簡(jiǎn)單的查詢(xún)語(yǔ)句,例如select * from Student,只需找到Student所在的寬表,根據(jù)租戶(hù)標(biāo)識(shí)以及私有表名Student查詢(xún)即可得到結(jié)果。
視圖定義SQL重寫(xiě),重寫(xiě)過(guò)程不必對(duì)查詢(xún)項(xiàng)和涉及的表一一進(jìn)行解析、映射,簡(jiǎn)化了重寫(xiě)過(guò)程。當(dāng)在對(duì)租戶(hù)信息進(jìn)行查詢(xún)時(shí),先對(duì)元數(shù)據(jù)進(jìn)行訪問(wèn),獲得租戶(hù)私有表的SQL定義,將其存儲(chǔ)在DefSQLTable中;接著對(duì)用戶(hù)發(fā)起的SQL查詢(xún)語(yǔ)句進(jìn)行重寫(xiě);最后通過(guò)物理SQL查詢(xún)數(shù)據(jù)進(jìn)而取得查詢(xún)結(jié)果。
私有表SQL定義的生成流程圖如圖3所示。首先輸入要進(jìn)行SQL定義的租戶(hù)標(biāo)識(shí)和租戶(hù)私有表名稱(chēng);其次從元數(shù)據(jù)表獲得該租戶(hù)該私有表的元數(shù)據(jù)映射關(guān)系;然后通過(guò)字符串拼接得到SQL定義;最后將其保存在表中。在該存儲(chǔ)模式下,元數(shù)據(jù)只能通過(guò)私有表SQL定義過(guò)程進(jìn)行訪問(wèn),有效保護(hù)了租戶(hù)業(yè)務(wù)數(shù)據(jù)的元數(shù)據(jù)。
圖3 私有表SQL定義生成流程圖
Fig.3 Flow chart of private table SQL definition generation
圖4 查詢(xún)重寫(xiě)流程圖
Fig.4 Query rewrite flow chart
查詢(xún)重寫(xiě)的流程圖如圖4所示。首先輸入發(fā)起查詢(xún)操作的租戶(hù)標(biāo)識(shí)和SQL語(yǔ)句;其次對(duì)SQL語(yǔ)句分解、解析,獲得解析所得的表;然后從DefSQLTable表中取出該表的定義,替換SQL語(yǔ)句中涉及的表;最后得到直接作用于數(shù)據(jù)庫(kù)的SQL查詢(xún)語(yǔ)句。
視圖定義SQL重寫(xiě),避免了復(fù)雜的SQL分析,降低了模式映射難度,通過(guò)減少SQL重寫(xiě)時(shí)間消耗,整體上提高了查詢(xún)效率。
多寬表數(shù)據(jù)存儲(chǔ)模式實(shí)驗(yàn)主要針對(duì)存儲(chǔ)空間的利用率進(jìn)行分析,將其與寬表模式進(jìn)行比較,并對(duì)查詢(xún)重寫(xiě)過(guò)程的可行性進(jìn)行驗(yàn)證。
模式空是寬表數(shù)據(jù)存儲(chǔ)模式空值大量存在的主要原因,而在多寬表數(shù)據(jù)存儲(chǔ)模式下,不同租戶(hù)可以根據(jù)自己數(shù)據(jù)模式的列數(shù),選擇最為接近的寬表進(jìn)行存儲(chǔ),可以大大減少模式空值的產(chǎn)生,提高存儲(chǔ)空間的利用率。
假設(shè)要存儲(chǔ)N個(gè)租戶(hù)數(shù)據(jù)存儲(chǔ)模式,其中模式i具有p行q列。
結(jié)果表明,多寬表的存儲(chǔ)模式有效減少了空值的存在,提高了存儲(chǔ)空間的利用率。
查詢(xún)重寫(xiě)實(shí)驗(yàn),數(shù)據(jù)庫(kù)選擇使用MySQL Server 5.5,運(yùn)行環(huán)境為Eclipse 3.7.2.
實(shí)驗(yàn)數(shù)據(jù)實(shí)例如圖5所示。Coursetenanlid=1表示Course表中租戶(hù)1的數(shù)據(jù),表的結(jié)構(gòu)為(CNo,Cname,CGrade),主鍵為CNo;NativePlaceTenantild=2表示NativePlace表中租戶(hù)2的數(shù)據(jù),表的結(jié)構(gòu)為(Nno, NName, NPlace),主鍵為Nno.在多寬表的存儲(chǔ)模式中,這兩張表結(jié)構(gòu)是某租戶(hù)的數(shù)據(jù)模式,而真正的數(shù)據(jù)是共同存儲(chǔ)在Data表中。
若租戶(hù)進(jìn)行如下SQL查詢(xún):select CGrade from Course where cno='1' .首先對(duì)該SQL語(yǔ)句進(jìn)行分解解析,看是否為簡(jiǎn)單SQL語(yǔ)句,判斷為否,得到表Course.然后對(duì)SQL定義表進(jìn)行查詢(xún),看是否存在Course表的SQL定義。如果存在,則進(jìn)行替換形成作用于數(shù)據(jù)庫(kù)的SQL查詢(xún)語(yǔ)句;如果不存在,則使用SQL定義的方法對(duì)Course表進(jìn)行定義并存儲(chǔ)后,再取出SQL定義,形成新的SQL查詢(xún)語(yǔ)句。通過(guò)以上步驟,獲得可以作用于實(shí)際數(shù)據(jù)庫(kù)的SQL查詢(xún)語(yǔ)句:select CGrade from (select value1 as CNo,value2 as CName,value3 as CGrade from data1 where TenantId=‘1’ and TableName=‘Course’) as a where cno=‘1’.通過(guò)程序訪問(wèn)數(shù)據(jù)庫(kù)可得到結(jié)果為2.
圖5 實(shí)驗(yàn)數(shù)據(jù)實(shí)例
Fig.5 Experimental data example
若租戶(hù)進(jìn)行如下SQL查詢(xún):select * from CoursE.首先對(duì)該SQL語(yǔ)句進(jìn)行分解解析,看是否為簡(jiǎn)單SQL語(yǔ)句,判斷為是。通過(guò)查詢(xún)?cè)獢?shù)據(jù)表得到Course所在寬表,然后重寫(xiě)SQL語(yǔ)句為select * from data1 where TenantId=‘1’ and TableName=‘Course’,最后執(zhí)行該語(yǔ)句所得結(jié)果為:1 yuwen 2. 對(duì)于這樣的簡(jiǎn)單SQL語(yǔ)句,使用動(dòng)態(tài)SQL重寫(xiě)方法要更為簡(jiǎn)單,不必再訪問(wèn)SQL定義表,簡(jiǎn)化了重寫(xiě)過(guò)程,節(jié)約了查詢(xún)時(shí)間。
討論了基于寬表的多租戶(hù)數(shù)據(jù)存儲(chǔ)模式,及該模式下的數(shù)據(jù)查詢(xún)重寫(xiě)過(guò)程。在分析多租戶(hù)寬表存儲(chǔ)模式的特點(diǎn)和存在的缺陷后,將其改進(jìn)為基于多寬表的數(shù)據(jù)存儲(chǔ)模式,通過(guò)實(shí)驗(yàn)驗(yàn)證減少了數(shù)據(jù)模式空值,提高了存儲(chǔ)空間利用率。并提出在多寬表的數(shù)據(jù)存儲(chǔ)模式下,采用動(dòng)態(tài)SQL重寫(xiě)和視圖定義SQL重寫(xiě)兩種方法對(duì)租戶(hù)發(fā)起的SQL查詢(xún)進(jìn)行重寫(xiě),使之成為可以直接作用于實(shí)際數(shù)據(jù)庫(kù)的SQL語(yǔ)句。但對(duì)數(shù)據(jù)的增加,刪除,修改等其他操作,還需要進(jìn)一步研究多寬表數(shù)據(jù)存儲(chǔ)模式,提出新的SQL重寫(xiě)過(guò)程。