刘 彬,程 凯,于 杰
1(金诚信矿业管理股份有限公司,北京 100044)
2(北京宸控科技有限公司,北京 102200)
3(北京市新媒体技师学院,北京 102200)
随着云计算的发展及应用软件的成熟,软件即服务 (Software as a Service,SaaS)[1]作为云计算的一种应用形式越来越受到重视.多租户数据架构是搭建SaaS应用平台的关键技术之一,不仅需要在数据库层面实现租户之间数据的隔离[2],还要满足租户的定制需求.
目前几种典型的多租户共享存储模型,包括透视表、稀疏表、块表及块折叠,都能保障租户数据的隔离性和可定制性的需求,但仍存在各自的不足.例如,在透视表存储模型中,租户数据被拆成键值对形式的元组垂直存储,这使得重构租户逻辑关系需要做大量连接操作,重构一个n列的表需要做n–1次连接;在稀疏表存储模型中,不同租户的逻辑表都被映射到一个列数很大的表中,例如Salesforce.com的数据表有500列[3],从而会导致表中包含大量空值,存储空间利用率低;块表存储模型在透视表存储模型的基础上进行了改进,一个块中包含若干不同数据类型的字段,但在租户数据类型相同的字段数量多的情况下,重构租户逻辑表仍然需要大量连接;块折叠存储模型在块表存储模型的基础上做了进一步改进,通过垂直划分将租户逻辑表中共有的属性存储在基本表中,而剩余的属性仍然是采用块表存储,并没有解决块表存储模型中存在的问题.综上所述,目前并没有完全成熟的多租户数据库架构[4],因此如何提高多租户数据库性能仍然是值得研究的问题.
本文提出一种稀疏表与块表结合的存储模型,旨在提升稀疏表存储模型的存储空间利用率,并结合块表存储模型以更好地满足不同租户的个性定制需求.
针对SaaS应用场景下的多租户数据共享存储模型,国内外学术界的研究者们已经做过大量研究.文献[5]中提出了一种基于SaaS化多租户数据进行分区的模型和策略,使得多租户共享存储模型能够实现由单节点向多节点的扩展.文献[6]中提出了一种在关系数据库中集成xml的方案,即将xml数据类型的文档插入到数据库的大对象字段中,但对xml文档进行解析的过程较耗费时间,从而影响数据库整体性能.文献[7]中提出了一种多稀疏表的存储模型,即按照租户逻辑表的列数将其映射到不同列数的稀疏表中,较之传统单稀疏表存储模型减少了空值存储,提升了存储空间利用率,但只是通过预留列的方式满足租户对逻辑表的扩展需求,而当扩展列数超出稀疏表列数时仍需要进行大量的数据迁移,极大影响数据库性能.文献[8]从缓存的角度提升多租户数据库查询性能,提出了一种基于块折叠存储模型的缓存管理机制.文献[9]中针对传统块折叠存储模型提出了一种多级块折叠存储模型,较之传统块折叠存储模型,提升了查询性能和存储空间利用率.文献[10]中针对多租户数据库一般定制下的自适应数据模式和高可定制下的个性化数据模式分别进行了设计,并对基于相变存储器的数据库索引作了设计,从而达到改善SaaS化系统的存储开销、可扩展性和系统性能的目的.综上所述,现有的多租户共享存储模型重构租户逻辑表仍需要较多连接操作,其存储空间利用率和查询访问效率较低,需进一步改善.
本文提出一种稀疏表与块表结合的存储模型,将租户属性划分为在应用服务商提供的逻辑表的基础之上定制的属性和租户扩展的自定义属性,然后分别映射到一组列数不同的稀疏表中及块表中,较之传统稀疏表存储模型,在存储空间利用率及查询效率上都有所改善.
对于多租户共享存储模型来说,尽管在实际的物理存储结构中,各个租户的数据都被存储在同样的数据库及数据表中,但是租户之间不会感觉到其他租户的存在,更不会访问其他租户的数据.租户可以在应用服务商提供的逻辑表的基础之上定制各自需要的属性,也可以往逻辑表中添加新的自定义的属性,甚至还可以自定义新的逻辑表.如图1所示,各个租户可以针对SaaS平台中的各个应用,通过定制生成各自私有的逻辑表,之后就可以针对逻辑表做查询和访问操作,而不用关心底层数据库中表的结构.
图1 租户逻辑定制示意图
物理存储是指数据库中表的组织形式,对于上层租户来说是透明的.数据库中包括三种类型的表,分别是:稀疏表、块表及元数据表.
块表用于存储租户自定义字段,当租户在逻辑表中扩展自定义字段时,若该字段数据类型与块表中包含的某个字段的数据类型一致,则将该字段映射到块表中相应的字段存储.因此对于块表中字段的选取应结合具体SaaS应用的业务特征,进而选择最常用的几种数据类型.
稀疏表用于存储租户在逻辑表上定制的字段、字段的数据类型不包含在块表中的租户自定义字段以及租户自定义的逻辑表中的字段.本文在传统稀疏表的基础上添加了row字段,表示租户逻辑表中数据记录的行号,并作为重构租户逻辑关系时稀疏表和块表的连接条件之一.
元数据表包括对稀疏表进行描述的表及对块表进行描述的表.其中,对稀疏表进行描述的表存储了稀疏表与逻辑表之间的对应关系以及各个稀疏表的列数.而对块表进行描述的表存储了块表与逻辑表之间的对应关系以及块表的表名和表中字段的数据类型.
模式映射是建立逻辑表与物理表之间的映射关系,即将逻辑表中的字段对应到物理表中.首先要合理划分一组不同列数的稀疏表并给一组块表设置合适的字段.针对不同列数的稀疏表的划分,本文提出的策略是,先统计应用服务商为租户提供的各个逻辑表的字段个数,并保存到集合sl{sl_1,sl_2,…,sl_n}中,字段个数相同的只计一次;再依次取集合sl中的值加α作为列数来创建相应列数的稀疏表,α表示预留列数,用于存储租户扩展字段.针对块表中字段的设置,由于稀疏表中预留的列数有限,且租户的定制不是一次性完成的,当租户向已有的逻辑表中添加新的自定义的字段时,应让更多的扩展列映射存储到块表中,少数的扩展列存储到稀疏表中,这样可以降低稀疏表列数溢出的概率,因此可以根据SaaS应用的业务特征来选择扩展字段可能的数据类型.
模式映射的具体过程为:当租户定制逻辑表时,先判断是否为租户自定义的逻辑表,若是自定义的,则先获取每个稀疏表的列数,再根据二分查找法找到列数大于且最接近的该逻辑表字段数的稀疏表,再在相应的元数据表中存储映射关系;若不是租户自定义的逻辑表,则需要进一步判断该逻辑表中是否包含租户自定义的字段,若不包含则映射到相应的稀疏表中,若包含自定义的字段,则通过查询元数据表,判断该字段的数据类型是否与块表中的某个字段数据类型一致,再根据判断的结果将其映射到相应的稀疏表或者块表中.由逻辑表映射到物理表的过程如图2所示.
图2 模式映射过程
要验证稀疏表与块表结合的共享存储模型的合理性,只需要证明该共享存储模型与传统关系模型是等价关系即可.证明的过程大致可分为两个步骤:
第一步要证明传统关系模型可以等价转化为稀疏表与块表结合的存储模型,即对于租户定制的任意一个逻辑表,假设为R,对于R中的任意属性V,其都可以被映射存储到稀疏表与块表结合的存储模型中.首先若V是应用服务商提供的属性,则将V映射存储到相应的稀疏表中;其次若V是租户自定义的属性,则根据该属性的数据类型分为两种情况,若块表中包含与V的数据类型相同的字段,则将V映射存储到块表中,否则将V映射存储到相应的稀疏表中;最后若V是租户自定义的逻辑表中的属性,则将V映射存储到相应的稀疏表中.
第二步要证明稀疏表与块表结合的存储模型可以等价转化为传统关系模型,即通过选择、连接及投影三种标准关系运算重构租户逻辑关系.首先对于租户自定义的逻辑关系,假设为租户8的device表,先根据md_sparse表中的元数据信息找到对应的稀疏表,假设为sparse_i表,然后对sparse_i表做选择和投影操作形成视图X,关系代数表示为:
最后对X进行更名操作,即形成租户逻辑关系R,关系代数表示为:
其中,i=1,2,…,n;其次对于应用服务商提供给租户的逻辑关系,假设为租户8的user表,并假设租户8在user表中的定制属性存储在稀疏表sparse_i中,先对chunktable表做自身连接及投影操作形成视图X,关系代数表示为:
再对X和相应的稀疏表做自然连接及投影操作形成视图Y,关系代数表示为:
最后对Y做更名操作形成租户逻辑关系R,关系代数表示为:
上述公式中,i=1,2,…,n.
通过以上两个步骤,即可证明本文提出的稀疏表与块表结合的存储模型与传统关系模型等价,即租户所有基于传统关系模型的操作都可以转化为基于稀疏表与块表结合的存储模型完成.
对于传统的稀疏表存储模型和块表存储模型来说,影响存储空间利用率的最大因素是表中的空值.空值既包括该属性值为空,还包括租户未定制而产生的空值.由于各个租户逻辑表的结构各异且稀疏表列数大,稀疏表中必然存在租户未定制该列而产生的空值.与传统稀疏表存储模型中只有一张宽度很大的稀疏表相比,稀疏表与块表结合的存储模型中划分了一组不同列数的稀疏表,进而将租户逻辑表映射到列数与之接近的稀疏表中,因此稀疏表中的空值大量减少.而块表中用于映射租户逻辑字段的列数很少,因此块表中的空值相对于传统稀疏表存储模型来说也很少.
假设平台中有n个租户,且一共定制了m个逻辑表 (Tl1,Tl2,…,Tlm),Tli的列数为Cli,行数为Rli,Cli列中有Ei列自定义的字段存储在块表中.设根据逻辑表的字段个数划分了k个列数不同的稀疏表(TS1,TS2,…,TSk),Tsi的列数为Csi,且有Cs1<Cs2< … <Csk,Tsi中存储了Li个租户逻辑表.设块表的列数为Tc,且块表中存储了Ln个逻辑表中的自定义字段.则可得到本文中存储模型的存储利用率ρ为:
设传统稀疏表存储模型中表的列数为Max,则该存储模型的存储利用率ρ,为:
将式(6)与式(7)相减,可得到两种存储模型下的存储空间利用率的差值,将该值简化后的分子表示为:
由式(8)可看出当一组稀疏表的存储容量之和加上块表的容量等于传统稀疏表的容量时,两种存储模型下的存储空间利用率才相等.然而块表中的列数一般会比宽度最小的稀疏表列数还少,且通过换算可以得到:
因此我们可以得出稀疏表与块表结合的存储模型较之传统稀疏表存储模型在存储空间利用率上有所改善.
由于数据库中实际的物理存储结构对租户来说是透明的,且所有租户对于数据的查询和访问操作都是针对其各自私有的逻辑表进行的,因此需要通过程序中的查询重写器将租户针对逻辑表发起的逻辑SQL请求转换为针对物理存储结构的SQL请求,最后将结果返回给上层租户.
查询转换的过程可分为如下四个步骤:
(1)获取租户唯一标识,并从逻辑SQL请求中获取逻辑表的表名、要查询的字段名及查询条件
(2)查询元数据表,并根据逻辑表的表名和租户唯一标识获取该逻辑表存在映射关系的物理表的表名,再获取逻辑表中的字段与相应物理表中字段之间的对应关系
(3)根据上一步骤中得到的逻辑表中字段与物理表中字段之间的对应关系来构建针对物理表进行查询的SQL语句,并分别为该SQL语句中查询的所有物理表中的字段名设置别名,且别名均为逻辑表中与之对应的字段名
(4)重新改写逻辑SQL请求,用上一步骤中得到的SQL语句来代替原始SQL语句中逻辑表的表名,即接在from子句之后表名
经过上述四个步骤,可将逻辑SQL请求转换为物理SQL请求,从而完成查询访问操作.
操作系统:64 位 Windows 8.1;处理器:Core i5-4210M @ 2.60 GHz 双核;内存:8 GB
数据库:MySQL 5.5.28
实验中通过程序生成了模拟的100个租户user表的数据,然后将其分别映射到稀疏表与块表结合的存储模型及传统稀疏表存储模型的物理表中.传统稀疏表用1张列数为500的大宽表存储所有租户的数据,稀疏表与块表结合的存储模型采用了5张列数分别为33、43、53、63、73的稀疏表和1张列数为10的块表存储所有租户数据.各个租户的user表中的字段个数为15–34,且每张user表中都有1000条记录.
对于存储空间利用率的分析,本文中采取的做法是分别将传统稀疏表存储模型和稀疏表与块表结合的存储模型下的数据表导出为SQL文件,分别命名为“稀疏表与块表.sql”和“single_sparse.sql”.比较两个文件的大小,前者文件大小为25.5 MB,而后者文件大小为292 MB,由此可知稀疏表与块表结合的存储模型相比传统的单稀疏表存储模型显著地提升了存储空间利用率.
对于查询效率的分析,本文中采取的做法是模拟多个租户同时发起查询,每个租户发起400个查询请求,然后计算不同并发查询线程个数的情况下,租户的平均查询响应时间.两种存储模型下的查询效率对比如图3所示.
图3 两种存储模型的查询效率对比
由图3可看出,稀疏表与块表结合共享存储模型的平均查询时延小于传统稀疏表共享存储模型,且随着并发查询线程数量的增加,差值逐渐增大,表明新提出的共享存储模型对查询访问效率进行了改善.
针对传统单稀疏表存储模型存储空间利用率低及块表存储模型连接次数多的问题,本文提出一种稀疏表与块表结合的存储模型.该存储模型采用一组列数不同的稀疏表及块表共享存储多租户数据,并构建相应的元数据表用于存储对稀疏表和块表进行描述的信息.将租户基于服务商提供的逻辑表定制的属性及租户自定义的逻辑表中的属性映射到列数接近的稀疏表中,而根据字段的数据类型将租户在逻辑表中自定义的属性映射到块表或者相应的稀疏表中.通过存储分析及实验分析对比,并从存储空间利用率,查询效率及可定制性三个方面综合比较,该存储模型性能优于传统的稀疏表存储模型.