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

2023-12-12 10:32:47 +08:00
 dandankele

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

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

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

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

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

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

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


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

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

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

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

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

一个可能的危险设计是: 顶层使用 root, 密码校验交由服务层, 改写 sql 生成逻辑行 java.sql.Connection#nativeSQL
dandankele
2023-12-12 13:30:25 +08:00
我在 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
2023-12-12 13:40:27 +08:00
另外关于 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