likes
comments
collection
share

多租户架构设计思考

作者站长头像
站长
· 阅读数 19

共享数据库,共享表

描述

所有租户的数据都在同一个数据库表内,以租户字段:tenant_id来区分。

优点

成本低,实现方式简单,适合中小型项目的快速实现。

缺点

  • 数据隔离性差,某一个租户的数据量大的时候,会影响其他租户数据的操作效率。
  • 需要在表上增加租户字段,对系统有一定的侵入性。
  • 数据备份困难,因为所有租户的数据混合在一起,所以针对某个租户数据的备份、恢复会比较麻烦。
  • 安全性,租户如果

实现方式

**方式一:**编写Mybatis拦截器,拦截增删改查操作,动态的增加租户条件,如:

SELECT * FROM sys_user;

修改成:

SELECTG * FROM sys_user WHERE tenant_id = 100;

这种方案并不靠谱,因为动态修改SQL语句不是一个好的处理方式,如果SQL解析没有做好,或者出现复杂SQL,那么很容器产生bug。

**方式二:**编写Mybatis拦截器,拦截增删改查操作,判断是否有租户条件,如:

SELECT * FROM sys_user WHERE id=1;

使用jsqlparser工具解析SQL,判断出该SQL语句没有tenant_id的条件,那么抛出异常,不允许执行。

这种方案比较稳妥,因为只做判断不做修改。

查询操作的优先级不高,如果不在乎数据敏感,可以不拦截。

要注意的是修改操作,稍不注意容易被某一个租户影响其他租户的数据。

共享数据库,独立一张表

描述

所有租户的数据都在同一个数据库中,但是各自有一个独立的表,如:

# 1号租户的用户表
sys_user_1

# 2号租户的用户表
sys_user_2

...

优点

成本低,数据隔离性比共享表稍好,并且不用新增租户字段,对系统没有侵入性。

缺点

  • 数据隔离性虽然比共享表好了些,但是因为仍在同一数据库下,所以某一个租户影响其他租户的数据操作效率问题依然存在。
  • 数据备份困难的问题依然存在。

实现方式

**方式一:**编写Mybatis拦截器,拦截增删改查操作,动态的修改表名称,如:

SELECT * FROM sys_user;

修改成:

SELECT * FROM sys_user_1;

同样的,这种动态修改SQL语句的方式并不推荐,所以我们有另一种方式。

**方式二:**将表名作为参数传入

本来在Mapper.xml中,查询语句是这样的:

SELECT * FROM sys_user WHERE id = #{userId};

现在改成:

SELECT * FROM #{tableName} WHERE id = #{userId};

这样可以避免动态修改SQL语句操作。

独立数据库

描述

每个租户都单独分配一个数据库,数据完全独立,如:

database_1;
database_2;
...

优点

  • 数据隔离性最好,不需要添加租户id字段,租户之间不会被彼此影响。
  • 便于数据备份和恢复。
  • 便于扩展。

缺点

  • 经费成本高,尤其在有多个租户的情况下。
  • 运维成本高。

结论

一般来说,当数据量不高的时候,选择共享数据库共享表的方式,表内加个租户id字段做区分,数据量或者用户量多起来,就可以直接升级到独立数据库的方式,因为独立表的方式处理起来是有些麻烦的,倒不如加个字段来的方便。