你好,我是陈皓,网名左耳朵耗子。
隔离设计对应的单词是Bulkheads,中文翻译为隔板。但其实,这个术语是用在造船上的,也就是船舱里防漏水的隔板。一般的船无论大小都会有这个东西,大一点的船都会把船舱隔成若干个空间。这样,如果船舱漏水,只会进到一个小空间里,不会让整个船舱都进水而导致整艘船都沉了,如下图所示。
我们的软件设计当然也“漏水”,所以为了不让“故障”蔓延开来,需要使用“隔板”技术,来将架构分隔成多个“船舱”来隔离故障。
多扯一句,著名的泰坦尼克号也有Bulkheads设计,然而其设计上有个缺陷。如下图所示,当其撞上冰山漏水时,因为船体倾斜,导致水漫过了隔板,从而下沉了。
在分布式软件架构中,我们同样需要使用类似的技术来让我们的故障得到隔离。这就需要我们对系统进行分离。一般来说,对于系统的分离有两种方式,一种是以服务的种类来做分离,一种是以用户来做分离。下面具体说明一下这两种方式。
按服务的种类来做分离
下面这个图中,说明了按服务种类来做分离的情况。
上图中,我们将系统分成了用户、商品、社区三个板块。这三个块分别使用不同的域名、服务器和数据库,做到从接入层到应用层再到数据层三层完全隔离。这样一来,在物理上来说,一个板块的故障就不会影响到另一板块。
在亚马逊,每个服务都有自己的一个数据库,每个数据库中都保存着和这个业务相关的数据和相应的处理状态。而每个服务从一开始就准备好了对外暴露。同时,这也是微服务所推荐的架构方式。
然而任何架构都有其好和不好的地方,上面这种架构虽然在系统隔离上做得比较好,但是也存在以下一些问题。
- 如果我们需要同时获得多个板块的数据,那么就需要调用多个服务,这会降低性能。注意,这里性能降低指的是响应时间,而不是吞吐量(相反,在这种架构下,吞吐量可以得到提高)。
对于这样的问题,一般来说,我们需要小心地设计用户交互,最好不要让用户在一个页面上获得所有的数据。对于目前的手机端来说,因为手机屏幕尺寸比较小,所以,也不可能在一个屏幕页上展示太多的内容。
- 如果有大数据平台,就需要把这些数据都抽取到一个数据仓库中进行计算,这也增加了数据合并的复杂度。对于这个问题,我们需要一个框架或是一个中间件来对数据进行相应的抽取。
- 另外,如果我们的业务逻辑或是业务流程需要跨板块的话,那么一个板块的故障也会导致整个流程走不下去,同样会导致整体业务故障。
对于这个问题,一方面,我们需要保证这个业务流程中各个子系统的高可用性,并且在业务流程上做成Step-by-Step的方式,这样用户交互的每一步都可以保存,以便故障恢复后可以继续执行,而不是从头执行。 - 还有,如果需要有跨板块的交互也会变得有点复杂。对此我们需要一个类似于Pub/Sub的高可用、且可以持久化的消息订阅通知中间件来打通各个板块的数据和信息交换。 - 最后还会有在多个板块中分布式事务的问题。对此,我们需要“二阶段提交”这样的方案。在亚马逊中,使用的是Plan – Reserve – Commit/Cancel 模式。
也就是说,先做一个plan的API调用,然后各个子系统reserve住相应的资源,如果成功,则Commit;如果有一个失败,则整体Cancel。这其实很像阿里的TCC – try confirm/cancel。
可见,隔离了的系统在具体的业务场景中还是有很多问题的,是需要我们小心和处理的。对此,我们不可掉以轻心。根据我的经验,这样的系统通常会引入大量的异步处理模型。
按用户的请求来做分离
下图是一个按用户请求来做分离的图示。
在这个图中,可以看到,我们将用户分成不同的组,并把后端的同一个服务根据这些不同的组分成不同的实例。让同一个服务对于不同的用户进行冗余和隔离,这样一来,当服务实例挂掉时,只会影响其中一部分用户,而不会导致所有的用户无法访问。
这种分离和上面按功能的分离可以融合。说白了,这就是所谓的“多租户”模式。对于一些比较大的客户,我们可以为他们设置专门独立的服务实例,或是服务集群与其他客户隔离开来,对于一些比较小的用户来说,可以让他们共享一个服务实例,这样可以节省相关的资源。
对于“多租户”的架构来说,会引入一些系统设计的复杂度。一方面,如果完全隔离,资源使用上会比较浪费,如果共享,又会导致程序设计的一些复杂度。
通常来说多租户的做法有三种。
- 完全独立的设计。每个租户有自己完全独立的服务和数据。
- 独立的数据分区,共享的服务。多租户的服务是共享的,但数据是分开隔离的。
- 共享的服务,共享的数据分区。每个租户的数据和服务都是共享的。
这三种方案各有优缺点,如图所示。
通过上图,可以看到:
- 如果使用完全独立的方案,在开发实现上和资源隔离度方面会非常好,然而,成本会比较高,计算资源也会有一定的浪费。
- 如果使用完全共享的方案,在资源利用和成本上会非常好,然而,开发难度非常大,而且数据和资源隔离非常不好。
所以,一般来说,技术方案会使用折中方案,也就是中间方案,服务是共享的,数据通过分区来隔离,而对于一些比较重要的租户(需要好的隔离性),则使用完全独立的方式。
然而,在虚拟化技术非常成熟的今天,我们完全可以使用“完全独立”(完全隔离)的方案,通过底层的虚拟化技术(Hypervisor的技术,如KVM,或是Linux Container的技术,如Docker)来实现物理资源的共享和成本的节约。
隔离设计的重点
要能做好隔离设计,我们需要有如下的一些设计考量。
- 我们需要定义好隔离业务的大小和粒度,过大和过小都不好。这需要认真地做业务上的需求和系统分析。
- 无论是做系统板块还是多租户的隔离,你都需要考虑系统的复杂度、成本、性能、资源使用的问题,找到一个合适的均衡方案,或是分布实施的方案尤其重要,这其中需要你定义好要什么和不要什么。因为,我们不可能做出一个什么都能满足的系统。
- 隔离模式需要配置一些高可用、重试、异步、消息中间件,流控、熔断等设计模式的方式配套使用。
- 不要忘记了分布式系统中的运维的复杂度的提升,要能驾驭得好的话,还需要很多自动化运维的工具,尤其是使用像容器或是虚拟机这样的虚拟化技术可以帮助我们更方便地管理,和对比资源更好地利用。否则做出来了也管理不好。
- 最后,你需要一个非常完整的能够看得到所有服务的监控系统,这点非常重要。
小结
好了,我们来总结一下今天分享的主要内容。首先,我从船体水密舱的设计,引出了分布式系统设计中的隔离设计。然后我介绍了常见的隔离有两种,一种是按服务种类隔离,另一种是按用户隔离(即多租户)。下节课,我们讲述异步通讯设计。希望对你有帮助。
也欢迎你分享一下你是如何为分布式系统做隔离设计的。
文末给出了《分布式系统设计模式》系列文章的目录,希望你能在这个列表里找到自己感兴趣的内容。
-
弹力设计篇
- 隔离设计Bulkheads
- 异步通讯设计Asynchronous
- 幂等性设计Idempotency
- 服务的状态State
- 补偿事务Compensating Transaction
- 重试设计Retry
- 熔断设计Circuit Breaker
- 限流设计Throttle
- 降级设计degradation
- 弹力设计总结
-
管理设计篇
- 配置中心Configuration Management
- 边车模式Sidecar
- 服务网格Service Mesh
- 网关模式Gateway
- 部署升级策略
-
性能设计篇
- 异步处理Asynchronous
- 数据库扩展
- 秒杀Flash Sales
- 边缘计算Edge Computing
- shufang 👍(0) 💬(1)
多租户的实例是指请求层服务层数据层的完全隔离吗?
2018-03-02 - 来 👍(31) 💬(1)
我们目前系统中采用隔离的点包括: 1、服务集群隔离,我们可以配置不同的请求访问不同的服务集群,我们通过服务别名来区分 2、数据存储隔离,包括数据库隔离、缓存集群隔离。数据库隔离一般通过分库分表,读写分离 3、线程池隔离,在同一个应用中,不同的任务处理通过线程池隔离 4、网络带宽隔离 暂时想到这么多,我理解隔离的本质是当系统出尽现故障时,尽可能的将故障影响范围降到最低。
2018-05-20 - 几度嘟嘟 👍(3) 💬(9)
不是很能理解多组户做法中的第三种”共享服务和数据分区“。文章前半部分讲到用户分离的时候,我理解这里指的是物理隔离,但是阅读到”共享的服务,共享的数据分区。每个租户的数据和服务都是共享的“时,我有些疑问这不是又回到隔断设计前的问题吗?一旦服务挂了之后,不是依旧会导致所有用户不可用吗? 如果是我理解上的问题,那么”共享的服务和数据分区“隔离的又是什么呢?
2020-05-29 - 罗杰.菲の樂 👍(2) 💬(0)
现在云服务厂商提供的服务大多数都是multi-tenant的,一般会有resource governance(RG)的专门的模块去防止 noisy neighbor,这里也体现出了隔离的思想。 如果用database as a service,即使创建了3个数据库服务,它们还是有一定的可能会被映射到同一个物理主机上。所以这里RG就显得更为重要了。
2020-07-13 - 常清静 👍(2) 💬(0)
目前,所采用的隔离,只是服务级别的隔离,用户级别的隔离,更多的像是基于区域而进行的异地多活,通过不同的地域,隔离不同的用户,这样,从地区网络,以及资源调控上,更具备优势,但是这个的话,也只有到了一定体量之后,才是合理高效的架构
2020-03-29 - 北极点 👍(2) 💬(0)
隔离设计感觉是一个随着系统逐步进化,业务逐渐成熟的前提情况下诞生出来的模式。特别是多租户的设计!我之前的工作当中要是早了解或者思考下这种设计可能就会在维护现有的系统时考虑设计了,或者也会给技术管理层领导提建议了!读这篇文章很有感触。
2018-03-22 - escray 👍(1) 💬(0)
Bulkhead n. a wall that divides the structure of a ship or aircraft into separate parts. 对于普通租户,服务共享,数据隔离;对于重要租户,完全独立资源。 利用虚拟化技术实现物理资源共享和成本节约。 对于云盘存储来说,一旦发现不同用户存储了相同文件,那么就可以采用数据共享的方式,特别适合存储视频文件。 感觉一般会采用服务种类和用户双重分离的方式,先按照服务种类分,对于核心服务提供更多的资源,在极端情况下也保证运行;然后再按照用户分,可以按用户等级或地域,保障重点用户。 但是这样一来,似乎就更复杂了。 如果底层的 IaaS 或者 PaaS 平台做的好的话,是否可以减少隔离的考虑? 完整的服务监控系统,我觉的应该找机会去做云平台监控相关工作。 突然发现这个专栏的订阅数和留言的比例悬殊比较大,是因为留言的人少,还是作者放出来的少?
2023-03-14 - InfoQ_6fb64a94dbb7 👍(1) 💬(0)
船仓 隔板/泰坦尼克号这些内容简直和《反应式设计模式》书中一毛一样
2021-05-02 - Geek_7b1383 👍(1) 💬(0)
隔离设计的重点 1)定义好隔离业务的大小和粒度,过大和过小都不好。这需要认真地做业务上的需求和系统分析。 2)系统的复杂度、成本、性能、资源使用的问题的合适的均衡方案,或是分布实施的方案 3)隔离模式需要配置一些高可用、重试、异步、消息中间件,流控、熔断等设计模式的方式配套使用。 4)自动化运维的工具,尤其是使用像容器或是虚拟机这样的虚拟化技术可以帮助我们更方便地管理,和对比资源更好地利用 5)非常完整的能够看得到所有服务的监控系统
2020-04-27 - FeiFei 👍(1) 💬(0)
是啊。 监控系统太重要了,怕的不是出故障。故障在分布式系统里面是不可避免的,需要解决的是围绕着故障发生所做的一系列事情。 事前的监控 发生时候的故障处理 解决完问题的故障反思,避免下次再出现同一个错误。
2020-01-16 - MClink 👍(0) 💬(0)
好不容易打了一千多字,为啥说有敏感词,也不说是哪个敏感词,我分享技术心得也不给啊
2023-06-10 - JianXu 👍(0) 💬(0)
我一开始会偏向去解决系统的扩展性问题,并且希望一套控制面和数据面。后来越来越开始接受为每一个环境部署一套控制面和数据面,其实我把时间从解决高扩展性问题变成了解决多控制面的一致性问题。
2022-01-23 - 晓峰Ontheway 👍(0) 💬(0)
用的是服务隔离,每个服务下面都会挂一个数据库,并且数据会通过sns sqs流出,如果处理失败会进dlq中保存起来,人为介入处理。
2021-11-10 - 方勇(gopher) 👍(0) 💬(0)
隔离设计,流量调度,资源隔离,监控系统。按事业部做租户隔离,对服务做数据隔离,引入消息中间件。
2021-10-25 - simonren 👍(0) 💬(0)
技术方案会使用折衷方案,也就是中间方案,服务是共享的,数据通过分区来隔离,而对于一些比较重要的租户(需要好的隔离性),则使用完全独立的方式。
2020-04-24