同 database 不同 schema 多租户连接池问题

345 天前
 dandankele

我开发的是一个多租户的系统,使用的是mysql,采用的是同 database 不同 schema 方式的数据库隔离方式。每个租户对应一个 schema ,并且拥有特定的 username 和 password 才能连接访问。

目前在用 Hikari 尝试做数据库连接池,由于多租户的特性,我需要延时到 runtime 中才能确定哪个租户,才能使用对应的连接信息建立连接,建立连接时如果不使用 username 和 password 就无法认证和完成连接。但如果使用了 username 和 password 成功建立连接,并放入连接池,等处理下一个租户时,从连接池中拿的连接的 schema 就不对了。

但如果要为每个租户创建一个连接池,有些浪费,首先就是不确定每个租户对数据库的使用程度如何,不可能为每个租户设置特定大小的连接池,否则会存在连接数的浪费,所以势必要采用共享连接池才能最大的利用上。然后就是阿里云的 RDS 一个 database 实例有最大连接数的限制,所以更要求最好是共享连接池。

我也查了下相关的 github ,也有类似的issue还没人解决。而且 mysql 应该是不支持在一个连接中切换 user 的吧,必须 quit 断开连接使用新的 user 重新建立连接。

难道我要创建一个高权限帐号,可以访问所有 schema 才行吗?还有其他方法吗?

有处理过这问题的朋友吗?

2438 次点击
所在节点    数据库
42 条回复
bthulu
345 天前
mysql 哪来的 schema? mysql 只有 database 没有 schema!!!
28Sv0ngQfIE7Yloe
345 天前
dynamic-datasource
root71370
345 天前
mybatis 动态数据源
dandankele
345 天前
动态数据源我实现了,现在的问题是如何针对我的场景把连接进行池化复用,各位要审题啊
RedBeanIce
345 天前
提问
1 ,租户数量问题,目前一共有多少呢,一年后一共有多少呢


1 ,如果是租户数量少,一个 schema 一个数据库链接池,就简单解决问题了。不用动太多脑子。
dandankele
345 天前
@RedBeanIce 租户数量适中吧,我也想过一个 schema 一个连接池,然后每个池子最大连接数设置为 database 的最大允许的连接数量,空闲时间设置短一点,一个池子如果空闲连接多的话会释放给其他忙的池子。。但感觉又有些不妥。在每个租户都需要较为繁忙时,某个池子的空闲连接来不及释放给另一个池子
LeegoYih
345 天前
我之前实现的多租户方案是逻辑隔离,所有表都存一个租户 ID ,CRUD 自动拼接租户 ID 。
物理隔离,如果改表结构、维护基础数据还挺难受的,虽有有一些工具可以同步,但是最终还是要是人去检查一遍。
RedBeanIce
345 天前
@dandankele 我没有看过源码,不知道是否支持动态扩容。

HikariCP 的数据库连接池,是否支持动态扩容。如果支持动态扩容的话,那么给每个链接池一个较小的初始数量。
如果是该租户用的人多,那么动态的扩容。。。
RedBeanIce
345 天前
@RedBeanIce 我翻了翻 Hikari 的源码,,好像是支持自己改造数据库链接池的。
可以动态的处理。
dandankele
345 天前
@RedBeanIce 我感觉我这情况已经不是改 Hikari 内部实现的问题了,是 mysql 本身好像就不支持在一个连接中直接切换成另一个用户,不切换成另一个用户就看不到其拥有的 schema = =!
dandankele
345 天前
@LeegoYih 是的啊,各有利弊。。
Belmode
345 天前
其实最合理,最安全,最可靠的方式,就是一个租户一个连接池。
出初始连接池和最大连接池,做个限制
RedBeanIce
345 天前
@dandankele ......所以我表述的是,多个数据库连接池,连接池动态扩容。
jorneyr
345 天前
mysql 的 database 和 schema 是同一个东西,也可以理解 mysql 只有 database ,没有 schema 。
即使是 PostgreSQL 这种支持 database/schema 的,连接也是使用 database ,连接建立后 set search path 指定要访问的 schema 。
tomorrow092
345 天前
感觉这个优点背离池化思想了。本身池化就是 池子里的东西都是一样的。

而你的场景中 每个 connection 都有自己的用户名和密码, 这就导致 你在创建 connection 和 从池子里捞 connection 的时候 掺杂了自己的业务逻辑了。得不偿失,不如每个租户一个连接池。

另一方面,本身就是一个数据库,大家也可以用相同的用户名和密码呀。 把每个租户拥有特定的 username 和 password 才能连接访问 这个逻辑提到上层让业务来保证,没必要依赖数据库的密码和用户名校验把。
tomorrow092
345 天前
@tomorrow092 我号线理解偏差了。

你是 同一个数据库服务器上有多个租户的数据库, 你想搞一个连接池 连接多个库
lesismal
345 天前
看 OP 的需求应该是想 database 隔离、但是怕连接池数量太大吧,如果是这样、好像可以用同一组连接池,语句里指定 database 更好些吧,比如 select * from database.table ,但可能已有代码要改动很多
siweipancc
345 天前
连接建立后不可切换用户, 和你的需求与连接池设计违反, 真有这个需求只能抛弃池.

一个可能的危险设计是: 顶层使用 root, 密码校验交由服务层, 改写 sql 生成逻辑行 java.sql.Connection#nativeSQL
dandankele
345 天前
我在 mysql 官网上看到有提供 C 的[API 接口 mysql_change_user]( https://dev.mysql.com/doc/c-api/8.0/en/mysql-change-user.html),可以在同一个连接中重置会话,然后又看了下官方提供的 java 的 Driver 和相关代码,在 Connection 里果然发现了类似`changeUser`的封装方法。。看样子得进行一波魔改了。。不知道会不会成功
dandankele
345 天前
另外关于 mysql 中有没有 schema 概念,我也不太清楚哈,没怎么用过其他数据库。。但意思就是那个意思。。每个租户在一个数据库实例中有一个数据库。。另外我看 mysql 术语库中有提到 schema ,https://dev.mysql.com/doc/refman/8.0/en/glossary.html

@lesismal select * from database.table 之前我也看到过,可以算是一个还好的备选方案吧,相比直接在表列上增加租户标识好一点。。


另外每个租户都设置单独用户名和密码主要出于安全考虑,我们是做 toB 的 SaaS 平台,就怕某个 B 被黑了数据库,也难顺着线找到其他的 B 然后再黑一次,虽然代码是一套的= =!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/999606

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX