同 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 才行吗?还有其他方法吗?

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

2466 次点击
所在节点    数据库
42 条回复
ZZ74
2023-12-12 13:52:20 +08:00
每次执行前 根据当前租户 执行 set schema 不就好了
boolstone
2023-12-12 14:54:19 +08:00
你 20 楼给的文档这个仅单词同名而已,
totoro52
2023-12-12 14:59:38 +08:00
都单独数据库了,不如也单独服务器算了, 这样就不用考虑多租户的问题了,单独数据库维护难度系数随着时间和商户的推移会越来越大。
totoro52
2023-12-12 15:09:43 +08:00
1.一个链接是建立在账号密码基础上的, 怎么可能能切到其他用户,mysql 也没有 schema 这个概念, 如果非要可以使用 PostgreSQL ,基本可以无痛迁移。
2.正确的思路是你这个用户是高权限,可以访问到其他库, 但这样还是和你一开始的想法冲突了, 说到底你还是得一个商户一个池,控制好池的大小和回收时间, 哪些商户流量大就给他多分配,哪些小就给他分配少, 这个更适合你的需求。
3.业务量小搞独立数据库纯纯玩死自己,就和小公司上来就来一套 springcloud 而不考虑运维成本一样,我做过的系统都是采取逻辑隔离,但我们的机制是当某个用户流量大的时候就会单独给他迁移出来,以免影响其他用户。
weijancc
2023-12-12 17:29:18 +08:00
schema 是 SQL 标准定义的, mysql 的 database 就是直接对应了 schema, 个人认为你应该在应用层限制租户可以访问哪些表
whp1473
2023-12-12 17:59:41 +08:00
(1)业务量比较小建议,使用租户 ID 做逻辑隔离
(2)业务量大可以考虑使用 独立 MySQL 进程-Database 来确定租户的数据位置,给予最高访问权限,然后同一个连接切换 Database
(3)业务继续增大,随着 MySQL 进程增多,所有服务端都连接所有 Database 可能会造成连接池耗尽。第一可以设置连接池没有最小连接数,一定时间不用都必须回收;第二在网关层将请求路由到不同分组的服务,该分组服务只优先连接对应 MySQL ,只有当该请求过多时才分流到其他服务
(4)分库分表导致数据的查询和统计困难,可以通过异构数据到 kafka 至 ES 查询。统计可以通过定时任务统计。
(5)数据量过大定时任务都无法统计,可以通过 Datax 抽取到 Hive 中做批处理然后统计结果回写到 MySQL
whp1473
2023-12-12 18:02:28 +08:00
@whp1473 理论上这套方法可以承载所有业务场景的数据,因为每个节点都可以水平扩容。MySQL 、ES 、Hive 、Hdfs 、Yarn
visper
2023-12-12 18:03:24 +08:00
不要搞黑魔法。直接多个连接池,最多配置下空闲回收策略。
netnr
2023-12-12 19:00:26 +08:00
我没明白多住户同 database 不同 schema
在 mysql 中怎么体现的,所以是一个租户一个库还是一个库里面表分租户
liaojl
2023-12-12 19:13:30 +08:00
MySQL 的 schema 和 database 是同一个东西,估计你得重新描述你当前的方案?我猜你说的应该是,同一个 MySQL 实例上不同的 database ?
Kenyore
2023-12-12 20:46:20 +08:00
@tomorrow092 我同意背离池化思想的这个看法。OP 这种场景更合适的方案其实还是每个租户一个连接池。空闲连接可以适当设置小一点
sampeng
2023-12-13 00:15:42 +08:00
做技术不要钻牛角尖。上千个连接也死不了人的。
sampeng
2023-12-13 00:17:35 +08:00
php 可是没有连接池的。新浪,微博,facebook 也没看死掉。真到你需要考虑连接数的时候用户数已经有商业价值了。也没啥问题
kd9yYw2RyhQwAwzn
2023-12-13 08:53:35 +08:00
po 主跟我们的场景很相似
我们参考了 AbstractRoutingDataSource 的思路 重新基于 AbstractDataSource 实现了个数据源 在 getConnection 方法做了增强
大致也是在运行时确认租户/一个方法内切换别的租户 为了适配这个有简单的实现了一个自定义的事务控制
目前对 mybatis 支持没有问题 JpaRepository 的一些默认方法支持会有问题
5sheep
2023-12-13 09:02:31 +08:00
为何如此拧巴,用 schema 做多租户解决方案
SilenceLL
2023-12-13 09:58:26 +08:00
重写 AbstractRoutingDataSource ,determineCurrentLookupKey 的 key 使用租户的数据库连接信息,
HaibaraDP
2023-12-13 10:46:52 +08:00
池化的东西必须一样,不一样的必须隔离开,要不以后排查问题非常麻烦
dandankele
2023-12-13 16:14:30 +08:00
@kd9yYw2RyhQwAwzn 我也用的 AbstractRoutingDataSource ,但你们租户之间都是用的同一个数据库帐号密码进行连接的吗?我现在卡在了数据库帐号密码切换上
dandankele
2023-12-13 16:15:51 +08:00
稍微看了下。。我主要问题好像应该还是在 user+password 的切换上,只要能切换用户,那么 set schema 就不是问题。虽然 mysql 的底层 Driver 支持在同一个连接中 changeUser(username,password),但上层的很多库如 mybatis 、hikari 等都不支持明确的对一个连接切换用户,除非我是直接使用底层驱动开发,这显然不是太好。似乎只能采取一些折中的方式了?
kd9yYw2RyhQwAwzn
2023-12-14 11:03:11 +08:00
@dandankele 继承 DelegatingDS 把各个 database 的用户名密码设置为属性 重写 getConnection 方法手动设置用户名密码 然后 hikaridatasource 的底层数据源用 DelegatingDS 的继承类

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

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

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

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

© 2021 V2EX