---
title: "多租户系统设计"
description: "多租户系统设计SaaS 的系统分级SaaS 系统架构成熟度模型的 5 个级别——从“混乱”到“乌托邦“第 0"
date: 2021-10-25T10:24:49Z
canonical: https://xiaobox.github.io/p/2021-10-25-duo-zu-hu-xi-tong-she-ji/
author: 小盒子
categories: ["数据库"]
tags: ["算法", "数据结构", "架构"]
source: https://mp.weixin.qq.com/s/Sgtcvgf1E6GRnKr8X970Uw
license: CC BY-NC-SA 4.0
license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/
---

# 多租户系统设计

## 多租户系统设计

### SaaS 的系统分级

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

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

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-10-25-duo-zu-hu-xi-tong-she-ji/001-f0d035a7.jpg)

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

多租户可以分为几个不同的类别：

-   云中的简单虚拟化，其中只对硬件进行共享。
-   共享应用程序，对每个租户使用不同的数据库。
-   共享应用程序和数据库（效率最高，真正的多租户）。

我们要实现的也即效率最高的，真正的多租户业务模型。但选择是有个筛选的过程的，下面分别介绍下各种多租户的数据隔离方案。

### 独立应用独立库

有多个不同的应用，每个应用都有自己的数据库。这种方式虽然保证了租户数据的隔离，但无论是在扩展性和成本上都是最差的，故首先淘汰这种方式。

### 同一个应用程序，每个租户一个库

优点是

-   租户数据在数据库维护物理上隔离了，
-   由于是每个租户一个库可以在库表设计上做单独扩展，但这也引起了应用程序的兼容问题

缺点是数据库维护成本高，（举例：在相同数据结构的情况下，增加表中的列或索引，需要操作多个库）开发成本也高。

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-10-25-duo-zu-hu-xi-tong-she-ji/002-7db8fb73.jpg)

### 同一个应用程序，同一个数据库

缺点：多租户数据库必然会牺牲租户隔离。多个租户的数据一起存储在一个数据库中。在开发过程中，确保查询不会暴露来自多个租户的数据。

优点：是所有方案中成本最低的。

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-10-25-duo-zu-hu-xi-tong-she-ji/003-58034a8a.jpg)

### 分片多租户

分片多租户即：多租户的单应用+支持多租户的单数据库（分片）

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-10-25-duo-zu-hu-xi-tong-she-ji/004-f2a577f3.jpg)

看起来是不是跟第一个图中：同一个应用程序，每个租户一个库模式差不多，只不过每个库多了几个租户数据？

其实是大不相同的。

首先，第一种模式中不同租户的库是可以分别扩展的，也就是结构可以不一样，但分片多租户的是同一种数据结构。

其次，分片模式的扩展性很强，它可以是一个分片一个租户，也可以是一个分片多个租户，具体要看具体的分片策略。

来看下分片模式下具体的指标情况：

| 指标 | 分片多租户 |
| --- | --- |
| 可扩展性 | 无限 1-1000000s |
| 租户隔离性 | 中等 |
| 每一个租户的数据库成本 | 最低 |
| 性能监控和管理 | 综合和单个（偏综合） |
| 开发复杂度 | 中等 |
| 运维复杂度 | 从低到高，单租户的管理比较复杂 |

### 我们的模型选择

基于以上的分析，我们选择采用分片多租户的模型，因为这样可以获得无限的扩展能力，且对租户数据的隔离性也比较好。

这样的话数据库结构就是统一的，不同分片是同一库表结构。而具体分库规则是可以配置的，建议前期按照 一租户一库 的策略配置。

### 开发实践

-   每一个表的设计都应该考虑是否要加入 “租户 ID”字段，用来区别不同“租户”，或者不同客户，另外，也方便后面用“租房 ID”作为 分片键

-   我们将引入 ShardingSphere 帮我们做数据库的分库分表，对于应用来说是相对透明的，减少应用开发在数据库层面由于引入分库分表的复杂度。

-   我们利用分片规则对数据进行分片，例如根据租户 ID，配置分库分表规则

```
# 配置分片规则
- !SHARDING
  tables:
    # 配置 t_order 表规则
    t_order: 
      actualDataNodes: ds${0..1}.t_order${0..1}
      # 配置分库策略
      databaseStrategy:
        standard:
          shardingColumn: user_id
          shardingAlgorithmName: database_inline
      # 配置分表策略
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: table_inline
    t_order_item: 
    # 省略配置 t_order_item 表规则。..
    # ...
    
  # 配置分片算法
  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds${user_id % 2}
    table_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}

```

-   当数据库表结构有变更的时候（DDL），通过 ShardingProxy 进行代理修改，ShardingProxy 会按照分库分表规则进行多库表的自动修改。

### 元数据/配置驱动

一个好的 SaaS 解决方案应该是高效的多租户。可以使用每个租户的元数据来实现多租户。可以为每个特定组件定义元数据。它定义了运行时的应用程序数据、应用程序的基础功能，以及特定租户的数据和自定义（如果有的话）。

具体来说比如我们对多租户系统的 RBAC 权限配置管理，就是元数据配置。可以参考：

-   http://www.uml.org.cn/yunjisuan/2021051944.asp?artid=23981

## 参考

-   https://linpxing.cn/cxy\_saas\_tenant\_db\_11/
-   http://www.uml.org.cn/yunjisuan/2021051944.asp?artid=23981

