笔者所在公司从18年开始决定将内部软件做成SaaS软件,开始涉足SaaS领域,至今已经5年,从开始对SaaS软件的懵懵懂懂,到对SaaS、IaaS、PaaS、aPaaS的深入了解,以及对多租户、私有化、定制需求的业务满足、架构优化、到最后的软件国际化,一路走来经历了许多曲折,走了许多弯路,有必要记录下来,以便同行交流,避免新人重蹈覆辙。
由于涉及内容较多,本文只涉及初版的设计,关乎多租户、数据隔离、业务隔离、定制化需求,以及涉及到的技术细节等后续文章逐步详细描述。
最初业务系统设计
由于笔者公司业务涉及领域是AI行业,主要在智能客服、呼叫中心等相关业务领域,因此在企业内部已有一套成熟解决方案的情况下,要把内部软件做成SaaS软件,需要考虑的问题由以下几个方面。
单租户改成多租户
系统最初只在公司内部使用,也就是只有一个租户,一切都好说。改为SaaS软件后,就带来了以下几个问题。
多租户数据如何隔离
数据隔离方案由很多,比如逻辑隔离、物理隔离等,每种隔离方案从数据安全性、运维成本、运营成本各不相同。
逻辑隔离有几种方案:
第一种,在设计表的时候,在每张表后面加上一个租户id字段(tenant_id),这种方案所有租户都共用一张表,在数据增删查改的时候,只要带上租户id(tenant_id)即可。在使用MyBatis等组件的时候,只需要编写interceptor对SQL进行拦截,增强字段处理可以解决大部分场景,工作量也不大。
下面是一张分类表,t_category,截取了部分字段,其中tenant_id代表租户id。对数据操作的时候带上租户id即可。目前我们系统采取这种方案,后面在详细说在该基础上怎么去做物理隔离、业务隔离。
字段名 | 类型 | 非空 | 默认值 | 备注 |
id | bigint | ✅ | ||
tenant_id | varchar(32) | ✅ | 租户ID | |
category_name | varchar(32) | ✅ | 分类名称 | |
create_time | timestamp | ✅ | ||
is_deleted | bit | ✅ | 软删除标识 |
第二种,基于schema的租户隔离。从字面上可以看到,该方案针对每个租户单独建立schema,虽然表面上是隔离了数据库,其本质还是用的一个物理数据库,一旦数据库出现问题,影响的还是所有租户。
第三种,基于数据库的租户隔离。这种方案从底层物理数据库就是每个租户独立的,但是成本也最高,一般不会选择这种方案,当然客户如果不差钱,可以独立给他一个数据库,毕竟收益大于成本。
多租户权限如何管理
这里多的多租户权限主要指当你的SaaS系统包含多个软件,比如我们系统里面有智能客服、在线客服、呼叫中心等多套软件,如果用户只购买了呼叫中心,那么其他系统对用户应该是不可见、不可用的。因此对租户使用系统的权限需要做限制,另外在系统页面上也不应该展示用户不可用的软件。
这里对用户访问登录的时候即可知道用户购买了哪些系统,赋予对应的权限。
除了登录外,对用户的每一次请求后端做权限校验很容易,也不可忽略,因为你不知道在你的客户会用什么样的方式去访问你的系统。
除此以外,前端页面也应该对不可见系统做屏蔽。比如采用portal的形式,一个大前端嵌套所有子系统,然后根据后端返回的鉴权结果决定哪些系统对客户可见,哪些不可见。
通过前后端配合,展示用户可用的系统。
![](https://img-blog.csdnimg.cn/img_convert/fc18e7e74f798395efadea0c869ad1d0.png)
多租户角色权限如何管理
角色权限管理和租户权限不同之处在于,角色权限是指租户下面的用户权限。比如xx公司购买了呼叫中心系统,那么该公司下的用户的租户权限应该是可以看到呼叫中心系统,而坐席、坐席主管等拥有的系统权限和数据权限是不一样的。坐席主管应该可以看到每个坐席的接线时长、小休时长,甚至可以进行强插、强拆等,以及在数据报表查看,导出权限上不同。
一般角色权限是按照每个租户组织架构划分角色,再赋予角色对应的权限。企业员工依次归属于不同技能组,这样去实现角色权限。
再设计角色权限的时候也要考虑某些员工的特殊性,比如某个员工即时候在线坐席又是呼叫坐席,也就是角色权限的并集等情况。
用户访问地址设计(域名)
用户访问地址设计主要是针对每一个租户以及租户下面的用户访问系统的时候,如何从系统的角度分辨出当前访问的用户属于哪个租户,以及用户应该从哪个地址访问。
所有租户相同访问地址:
如果给予所有租户一个相同多的域名进行访问,比如:www.company.com,那么只能在用户登陆后才能知道用户的租户信息。
所以,在设计多租户存储方案无论是逻辑隔离、物理隔离,再这之前需要有一个前置数据库,里面包含租户信息,这样用户登录后才能获取到租户信息,才能进行后面的逻辑或物理隔离操作。
![](https://img-blog.csdnimg.cn/img_convert/2350636cfab817ce1e3e2bf628299491.png)
每个用户不同的访问地址
给予用户独有的地址访问系统,比如:a.company.com,b.company.com,这样用户在访问系统无需登录就可以知道用户是哪个租户,也就不需要前置库进行处理了。这个在后续说明业务隔离的时候详细描述,大体图示如下。
![](https://img-blog.csdnimg.cn/img_convert/876eaa2f630598671968e51e09d732b1.png)
系统端数量(toB、toC)等
一个SaaS系统要运营起来和对内系统不一样的地方在于需要做seo,需要官网等。所以对外的时候要考虑要做多少个系统端。
官网:用于系统宣传,吸引客户的一个渠道
B端:toB的系统,用户通过官网等渠道使用系统,无论是试用还是购买后正式使用,B端给客户管理自己的组织架构、角色、配置系统参数等。所以需要一个toB的系统端。
C端:既然我们系统包含了在线客服、智能客服等,那么这些渠道的链接、js、二维码等等,用户都可以放到他自己的网站、app上,这样才能享受到这些系统的服务。而这些网站、app往往是toC的,因此,这个聊天会话窗口端也就是C端。
A端:这个A端指的是Admin,也就是管理端。更准确的说法是运营管理端。当用户从搜索引擎或其它渠道访问官网的时候,一般网站会留下沟通渠道:在线客服、电话、留言等,这样运营人员会和用户联系,给客户开通试用账号。而试用账号的开通、计时等就是在这个运营管理端完成的,当然运营管理端还包括正式用户的计费、公告等。这里没用boss系统去描述,是因为一开始没有考虑做boss系统这个大的一个系统,到后来整个运营支撑还是发展到了boss系统。
技术选型
技术选型其实没什么好说的,SpringCloud提供了一整套解决方案,SpringCloud Alibaba在此基础上也做了一层增强。除此之外,dubbo、sofa也是rpc阵营的优秀框架。选型最终还是要考虑两个方面:
整个公司的架构体系:一个软件公司,如果每个部门使用的软件架构体系、中间件、数据库等五花八门,各自为营,那么对于研发和运维来说,成本是极高的,并且大量时间花在熟悉不同架构、不同中间件等上面去了,而关键的业务必然被忽视。所以尽可能采用一整套架构体系,让各部门研发、运维体系尽可能一致,这样更多时间和精力放到业务扩张和业务架构上,使系统软件更加健壮。
对内和对外的差异:上面一条是整个公司的架构体系,但是公司主要业务和新产品线业务不同,那么这个时候就要做一些改变了。比如内部系统,在用微服务的时候,可以考虑用rpc通信,这样在选择通信协议、编码、传输高效性(不需要传输http header等信息)等方面上更有优势。而对外的系统就讲究规范、标准,rest规范无异是最好的选择。
这里不对技术选型做任何对比和倾向性选择,只要符合各自公司和系统的实际情况即是最好。我们由于公司整体技术标准是SpringCloud体系,因此没有选择RPC。
基于以上的情况,我们的SaaS最初基于SpringCloud体系,设计了官网、A端(运营管理端)、B端(用户管理端)、C端(让企业用户把链接、二维码放到自己的toC端提供聊天服务)。数据库目前是采用租户id(tenant_id)做逻辑隔离。