技术开发系统架构系统架构

Saas多租户系统的架构设计

2020-07-18  本文已影响0人  Zal哥哥

Saas系统分级

SaaS系统架构成熟度模型的5个级别——从“混乱”到“乌托邦”。

第0级(混乱):每次新增一个客户,都会新增软件的一个实例。
第1级(受控的混乱):所有客户都运行在软件的同一个版本上,而且任何的定制化都通过修改配置来实现。
第2级(多租户[multi-tenant]、高层建筑[Highrise]):所有的客户都已经可以在软件的同一个版本上运行了,而且他们都在同一个“实例”上运行。
第3级(多租户, 扩建[Build-Out]):此时你已经拥有了多租户、单一版本的软件模型。不过你还是可以通过硬件扩展(scale-out)的方式来进行扩充。
第4级(乌托邦):如同第3级,除非你可以找出有效的方式,以在不同的“实例”上运行不同版本的软件。

应用程序必须支持多租户:

多租户可以分为几个不同的类别(如列表下方的图所示):   
1.1,云中的简单虚拟化,其中只对硬件进行共享。   
1.2,共享应用程序,对每个租户使用不同的数据库。   
1.3,共享应用程序和数据库(效率最高,真正的多租户)。

1. 分层设计

Saas 系统分层大概是:

image.png

Saas系统分层:租户识别 > 应用层 > 数据访问层 > 缓存层 > 数据库

业务代码都是写在应用层。
租户识别可以用spring拦截器实现,然后使用ThreadLocal传递给后端
数据库和缓存层对应用层应该是透明的。程序员在写代码的时候,只关心业务逻辑,不应该担心多租户的问题。

2. 数据隔离要透明

saas系统说起来很简单,任何系统似乎加个tenant_id(租户id)就变成saas系统了。比如原来的用户登录是:

image.png

改成

image.png

对于复杂业务的saas系统,这样做法非常危险,而且开发效率很低。你想想如果那个程序员写sql时候忘了加 “ and tenant_id =1” ,结果不堪设想。

比较好做法是在数据库访问层对SQL进行改写。

image.png

在连接池根据TenatnContext改写Sql。

这样做好处是,一来程序猿最多把系统搞down了,也不至于信息串了互相泄露。二来将来做分表分库也很方便,上层应用不用修改。

3. 租户识别方案

比较好做法是通过url识别租户。系统是给租户生成一个随机的三级域名,比如 abc.crm.baidu.com. 如果客户想使用自己的域名,可以在cname到我们生成的三级域名,并在管理系统里面做绑定。

这样一个租户可以有两个域名,访问saas,一个随机生成的三级域名,另外一个租户自己的域名.代码里面可以根据过来的域名,判断是那个租户然后初始化TenantContext.

如果不想通过域名来做,也可以通过登录名来判断。这种方式要涉及到租户切换问题。

4. 智能DNS

Nginx中rewrite实现二级域名、三级域名、泛域名、路径的重写

5. 租户管理系统(计费,订购,定制,充值,催缴)

Saas系统是必须考虑计费系统和租户控制系统。这个系统需要都是独立设计。比如那个租户购买了那些模块,一个月多少钱。租户可以创建最多的用户数。计费到期邮件提醒等功能。

计费方式一般有两种,周期性计费,类似月租方案,和使用量计费,用多少付多少。周期性计费比较简单。也可以两者结合起来。

6. 定制化开发

SAAS的优势在于一套系统多人使用,似乎和定制化开发有冲突。比如A客户想要A功能,B客户不想要。但定制化开发是无法避免的,比如CRM系统这样复杂的系统,不可能一套系统满足所有公司的要求。定制化开发尽可能分系统,分模块去做。然后通过控制台中配置不同租户订购不同模块,那些模块可以在前端页面上显示。不同的子系统需要分开部署。前端可通过nginx根据url分发,比如 abc.crm.baidu.com/bi/xxx/xx这个地址,就分发到BI子系统。不要尝试OSGI去搞模块化,这个是个大坑。

还有开发和产品,现有需求一定要分析清楚,不要一上线发现后患无穷。新功能尽量做的独立可以配置。

7. 灰度升级

SAAS付费企业客户对系统问题都特别敏感。为了减少升级可能出现问题的影响范围,一般都采用灰度升级策略。如果使用了url来区分不同租户,灰度升级配置就会很方便。可以配置nginx 来根据域名做分发,比如租户A(aaa.com)到实例1(版本1.0),租户B(bbb.com)到实例2(版本). 当需要域名配置非常多的时候,nginx配置文档会乱。这块时候可以考虑使用nignx_lua来写一些扩展模块。

8. 容量估计

对高并发的估计,读写操作的频率估计。

9. Saas平台架构分层分析

Saas平台架构需要完成从用户申请链接saas到用户对自己购买的功能模块的应用整个过程,用户用起saas看似简单快捷,但这个过程却需要saas平台架构默默完成的非常复杂的处理过程。通过对saas平台架构的了解,可以清晰的分化数据的处理过程,让用户也可以明白saas平台架构处理数据的优势。下面介绍:saas平台架构分为哪几部分。

saas平台架构之呈现层:

saas平台架构的呈现层可以使用的客户端可能都浏览器或本地客户端。如果是浏览器则需要Web界面技术、交互技术等技术(如:HTMl5技术、CSS3技术、Ajax技术等)的支持,如果是软件客户端则需要远程桌面技术、软件交互技术等技术支持。

saas平台架构之调度层:

saas平台架构的调度层体现分布式系统的特性之一。调度层首先负责识别并通过AAA认证每个用户请求,然后根据业务处理器的负载、业务特征进行合理的调度。通过应用这样的架构SaaS平台可以横向扩展。此外在存储、缓存等方面为了满足平台的横向扩展需求,调度层也必须具有良好的可扩展性。

saas平台架构之业务层:

saas平台架构的业务层负责接收调度层转发过来的请求,而且还要通过对接受到的请求执行真正的业务逻辑。一般来说业务逻辑的执行使用一台服务器就够了。因此业务层实际是由一排对等的服务器组成的,每台服务器都执行相同的业务逻辑。

saas平台架构之数据层:

saas平台架构的数据库集群用于处理存储关系性很强并且对事务性要求很高的业务数据,这类数据目前还要用传统的数据库集群技术来解决,saas平台架构的数据库集群主要是根据业务特征制定数据拆分方案。同时分布式数据库用于存放海量但关系性不强的数据(如:用户的操作日志等)。

以上是对“Saas系统架构的思考,多租户Saas架构设计分析”的介绍,从saas平台架构处理数据可以看出saas平台的应用有很强的优势,如用户使用saas非常方便简单只要浏览器或本地客户端接口,saas平台处理数据要经过层层认证saas产品安全可靠,saas平台优化处理数据提高saas性能。

多租户Saas系统架构还应该满足以下需求:

image.png

Saas 正在蓬勃发展,最近的销售易被腾讯重金加持,看好 SaaS 系统的未来!

多租户系统架构

运行时架构图:

img_1

做为SaaS的基本特征,多租户对系统的很多方面都产生了很多深远的影响.就数据层面的架构来说,基本上分成了多租户共享单一数据库、单一租户独享单一数据库以及介于两者之间的单一数库下的单一租户独享单一schema三种方案。
这篇文章 http://msdn.microsoft.com/en-us/library/aa479086.aspx 对三种架构方案做了全面和细致的分析,里面提到的pattern都是非常实用的(特别是Name-Value Pairs模式)。
让我印象最深刻的是,本文在分析每种方案的利弊和适用场景时,视野宽广,目光长远,考虑到了很多过去我自己没有想到过的因素。比如在谈到数据安全时,作者举例说对于某些类型的租户对数据安全是非常关切的(比如银行),这一类用户是很难容忍将自己的数据与其他租户放在一起的。再比如是否会考虑为租户提供数据备份与恢复的增值服务供需要的租户购买。还有就是综合预期产品未来的租户数量(10个和1000就会有质的不同),平均每个租户的数据量,以及单一租户的并发访问量等等.这些都会影响到方案的选择.总之这是一篇关于多租户Multi-Tenant数据架构方面非常全面的文章!

nginx:主要做多域名映射,根据域名映射到不同的web Server,比如接受到域名A请求,则路由到web Server1,接受到域名B请求,则路由到web server2

web server:主要是放网页或者web相关的,比如用户登录业务等,客户多变的需求都放到这层实现,比如有些客户在要求自己的网站注册的商家,必须上传运业执照,有些不需要等可变的需求

basic server:后台服务,这层的服务都是共有的,对于每个用户都不变的基础服务都放这层,并且这层做数据库路由,每个域名一个数据库(每个客户一个数据库,做数据隔离,当时个人还不同意,从事后来看,这种架构确实好处比较多,特别是客户以前就有一个网站,然后在往新库里导数据,然后又删新库里的数据时,不担心会把其它客户的数据删掉)。

DB :每个客户一个数据库,做到数据上的逻辑隔离和物理隔离(当时设想每个外部客户1个域名,然后在数据库的每个表里加平台id以区分是那个外部客户的数据,后来架构师力排众议,每个客户1个数据库,做到数据隔离,Basic Server做数据库路由)

如何做数据库路由?

web server根据请求的url,拿到域名,然后查出平台id。
basic server中的每个接口,都需要带平台id字段。
web server 调用basic server接口时,传入平台id。然后在basic server的service层,做aop,根据参数里的平台id,找到配置好的平台id和数据库连接信息,把连接信息放入ThreadLocal,包装自己的DataSource,在DataSource里获得数据库连接时,用ThreadLocal里的数据库连接信息,获得数据库连接,方法执行完,清除数据库连接(这里曾出现过小问题,service嵌套套用的时候,里面service方法退出清除数据库连接,导致外面service在操作数据库时,拿不到连接信息而报错,后来增加了一个调用层次计数)

日志监控层

任何可以反映 SpringBoot 微服务运行状态的数据,对于监控来说都是十分重要的“财产”,都应该尽量采集上来进行分析,从而在分析的基础上谋求对 SpringBoot 微服务的改进。

对于应用日志来说,在单机单结点的年代,我们只要登录应用部署的服务器,然后使用 tail-f 之类的命令就可以实时地查看应用日志信息,并决定如何做出应对。

但对于 SpringBoot 微服务来说,数量上的特征已经决定了单机单结点的方法已经行不通了,如果还是一台台地去查看应用日志,我们不但会“疲于奔命”,而且还无法及时有效地发现微服务作为一个逻辑服务集群整体上的状态特征现在是什么样的,我们这时候需要的是一种集中式的日志采集、存储和分析平台。

对于 Java 开发者来说,ELK 技术栈正是为此而生的(E=ElasticSearch,L=Logstash,K=Kibana),整个功能链路如图 2 所示。

基本ELK技术栈功能链路示意图

图 2 基本ELK技术栈功能链路示意图

不过,鉴于 ElasticSearch 对高频度的写入并没有很高的承受力,在正式的生产环境中,我们一般会采用如图 3 所示的部署结构。

生产环境典型ELK技术栈功能链路部署示意图

图 3 生产环境典型 ELK 技术栈功能链路部署示意图

即我们使用 Kafka 作为数据采集的缓冲区,以便减轻从大量应用结点采集日志并写入 ElasticSearch 的负担。

上一篇下一篇

猜你喜欢

热点阅读