注册

多租户架构设计思考

共享数据库,共享表


描述


所有租户的数据都在同一个数据库表内,以租户字段: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字段做区分,数据量或者用户量多起来,就可以直接升级到独立数据库的方式,因为独立表的方式处理起来是有些麻烦的,倒不如加个字段来的方便。


作者:失败的面
来源:juejin.cn/post/7282953307529953291

0 个评论

要回复文章请先登录注册