如何做数据隔离,其实是基于SaaS架构的一个核心问题。我个人看到的基于saaS架构,讲数据隔离的最早的一本资料是 微软的基于SAAS模式的多用户数据体系结构(下载地址: http://www.spluss.cn/forum/viewthread.php?tid=6&extra=page%3D1)。说实话,我看到这本资料的时候,我自己做的这个进销存系统已经基本成形了,并不是吹嘘自己,我是在没有看到任何数据隔离资料的情形下做出的一种数据隔离策略,我其实最早看到的是 阿里赵进 在程序员杂志上发表的那篇SaaS成熟度模型,我做的系统那时已经成形了,就想对比一下自己做的究竟符合成熟度模型的第几级,然后又开始从网上搜索多租户的数据隔离策略,就搜索到了微软的那份资料。
令我很奇怪的是,为什么是微软而不是IBM在前几年就做了这种理论上的探索。
数据隔离的方资料已经有很多了,包括我前期的Blog,阿里软件的技术总监 叶伟出的那本书,也讲得很详细了,无外乎那三种。第一种单独的数据库,咱们就不多说了。现在的问题是,在multiple schema和每个表都加一个tenantid 之间的取舍。这两种数据隔离(其实还有一种,就是利用数据库本身的特性,数据隔离策略相对简单些)各有各自的优缺点,所以我就想,能不能做成一种架构,自适应两种数据隔离策略呢?
1)对于采用multiple schema的方案,对应用程序来讲,是没有任何变化的,SQL语句无论多么复杂,也不需要采取考虑任何数据隔离的策略,压力都在那个数据库连接池的编写上,如何做到Dynamic和performance都没有问题,这个是对系统架构师的一个考验.我的第一版就是这么实现的,自己写了一个数据库连接池代理策略.
2) 每个表都加一个tenantid,这个在数据库设计的时候,很容易实现,关键是查询语句的编写,比如:最简单的查询采购订单的SQL语句:
select purchaseorder.*,custsupp.csname as custsuppname from purchaseorder,custsupp
where purchaseorder.custsuppno=custsupp.csno order by purchaseorder.pono
这个SQL语句是采购订单和供应商作关联,如果都要求程序员自己上加上tenantid,那么SQL语句就变成
select purchaseorder.*,custsupp.csname as custsuppname from purchaseorder,custsupp
where purchaseorder.custsuppno=custsupp.csno and purchaseorder.tenantid=? and custsupp.tenantid=?
order by purchaseorder.pono,如果关联表格很少还好,表格多了的话,就很容易出错了.
那么我是怎么做的呢? 我是在用户注册的时候,是采用独立的数据库(其实是Schema)隔离呢?还是共享数据库,或者这个也可以
根据用户选择的服务标准不同而设定. 在登陆的时候,如果判断用户购买的是独立的Schema方案,则数据隔离策略采用方案一,如果用户采用的是共享数据库,则我自己写了一个数据库SQL语句解析器,使其能够在所有的SQL语句当中,自动加上tenantid=XXX
这样的条件,减少程序员出错的可能。当然这个解析器还没有最后完成。简单的SQL语句是很好分析的,而对于left join,SQL嵌套查询这类的复杂语句,就不是那么好分析的了。
对于采用数据库私有数据隔离方案的话,重点解决方案是跟独立Schema解决方案是一样的,应用程序没有任何变化,主要也是数据库连接池如何做到Dynamic和performance都没有问题,而且数据库本身采用了这种方案后,performance没有问题,对DBA也是一种考验。