多租户最佳实践
概述
多租户有多种方案 https://zhuanlan.zhihu.com/p/143737554 。 我们是多数据源,只支持不同数据库的方案。
要点
假设我们设计一个多租户系统,每个城市一个数据库,已有 shanghai,chengdu,guangzhou
不同租户如何动态路由到对应数据库?
如果你一个请求下不会涉及到多个租户,建议参考无注解方案里的拦截器。 用户登录后返回租户信息给前端,前端后续请求都带一个 header 如 tenant: shanghai。 拦截器里手动设置数据源,那后续的请求都是 shanghai 这个库。
如果也会涉及在其他库也没有关系,仍然可以采用上面的方案,在需要切换其他库的时候用 @DS 切换即可。
看的出来作者比较倾向无注解,因为总的来说 @DS 是基于 AOP 的,开销和代码侵入性都相对来说比拦截器大一些。 不喜欢拦截器就喜欢 @DS 的,可以阅读 进阶使用-动态解析数据源。
场景
每一个场景都是上一个场景的递进。
场景一: 租户少比较固定
比如你租户比较固定,可能半年才会有一个新租户,就正常在 yml 配置即可。
场景二: 租户多但比较固定
需要关注的的文档
- 自定义-自定义数据源来源
- 进阶使用-无数据源启动
结合以上内容: 我们可以启动的时候不配置数据源,所有数据源动态从数据库中加载出来。减少 yml 的配置。
场景三: 租户多且不固定
有些系统租户需要动态的增减。
需要关注的文档 进阶使用-动态添加移除数据源
基于以上文档可以在系统运行过程中动态的新增移除数据源。
场景四: 租户多且不固定且多服务
在更大型系统,单机多租户已经不能满足运行需求,需要拆分多个服务。 这个时候动态新增就会遇到一个问题? 我一个新增数据源请求只会路由到一台服务,怎么让所有机器都新增一个数据源?
需要关注的文档 进阶使用-手动注入多数据源 知识库-辅助知识
答案是: 结合拦截器。
有一个表是非租户的主数据库,里面有个表存租户的信息,添加租户的使用就往租户表里插入新租户的相关数据库信息即可。
在拦截器中手动注入多数据源, 前端传来租户的 header 并解析,比如传来 guangzhou。 我们从多数据源里取出现有所有数据库的名称,判断有没有,没有就去主库里 sql 查找出来并动态添加到多数据源里。
这样所有机器都会逐渐加载新租户的数据源了。
但是怎么让所有服务都减少一个数据源呢? 可以尝试结合 redis 的 listener。 所有机器监听一个事件消息。