4 回答
TA贡献1775条经验 获得超11个赞
MySQL 和 Postgres 都不允许在多个数据库用户之间共享连接,在连接凭据中指定单个数据库用户。如果您的意思是您的不同用户拥有自己的数据库凭据,那么就不可能在他们之间共享连接。
如果“不同用户”是指您的应用程序用户,并且如果他们共享单个数据库用户以在应用程序中更深入地访问数据库,那么您不需要对“缓存”连接做任何特别的事情。sql.DB
默认情况下,保留并重用其池中的打开连接。
Go 会自动打开、关闭和重用带有*database/sql.DB
. 默认情况下,它最多保持 2 个连接打开(空闲),并在所有打开的连接都已经忙时同时打开无限数量的新连接。
如果您需要对池效率与数据库负载进行微调,您可能需要sql.DB
使用方法更改配置.Set*
,例如SetMaxOpenConns
.
TA贡献1810条经验 获得超4个赞
你似乎有很多未知数。在这种情况下,我会应用良好的、旧的敏捷,并从您想要使用您已经知道的工具实现的原型开始,然后对性能进行基准测试。我想你可能会惊讶 go 可以处理多少。
既然您了解如何map[string]*sql.DB
用于此目的,我会同意的。你达到了一些极限?在 haproxy 后面添加另一台机器。解决扩展问题并不一定意味着在 go 中编写新的数据库池。显然,如果你需要这种能力,你总是可以做到的——pgx postgres 驱动程序有它自己的池实现,所以你可以在那里获得灵感。然而,现在这样做似乎是过早的优化——解决你还没有的问题。构建原型map[string]*sql.DB
很容易,测试它,基准它,你会看看你是否需要更多。
ps顺便说一句,您很可能会在耗尽内存之前达到第一个文件描述符限制。
TA贡献1829条经验 获得超9个赞
假设您有多个用户拥有多个具有 N 到 N 关系的数据库,您可以将数据库 URL 映射到数据库详细信息(如下所述)。
应该使用 configmap 或核心数据库来处理哪些用户可以访问哪些数据库的事实;对于数据库详细信息,我们可以有一个这样的结构:
type DBDetail {
sync.RWMutex
connection *sql.DB
}
该映射将是数据库详细信息(dbDetail) 的数据库 URL,如果用户正在写入,它将调用:
dbDetail.Lock()
defer dbDetail.Unock()
而对于读取而不是上面的,只需使用RLock。
正如 vearutop 所说,连接可能很痛苦,但使用它你可以有一个连接,或者在Lock之后通过另一个变量的增量和减量来设置限制。
TA贡献1786条经验 获得超11个赞
这里不一定有正确的架构答案。这取决于系统的一些约束。
我可以选择使用
map[string]*sql.DB
where key 是数据库的 url,但是当我们有大量数据库时,它很难扩展。
这是否会充分扩展取决于对数据库数量的预期。如果预计在不久的将来会有数十或数百个并发用户,可能就足够了。使用地图后的下一步通常是过渡到功能更全的缓存(例如https://github.com/dgraph-io/ristretto)。
决定使用地图还是缓存的一个因素是您如何想象数据库连接的生命周期。打开连接后,该连接是否可以在进程的剩余生命周期内保持打开状态,或者是否需要在几分钟无用后关闭连接以释放资源。
我们是否应该为每个通过连接 url 分片的传入请求设置一个分片层,这样每台机器将包含适量的数据库连接,形式为
map[string]*sql.DB
?
这里的正确答案取决于预期有多少处理节点,以及是否会从将请求路由到特定机器中获得额外的好处。例如,行级缓存和将用户与彼此的请求隔离是一个优势,可以通过在池中共享用户来获得。但缺点是您最终可能会使用“热”节点,因为单个用户可能会产生大部分流量。
通常,对于这种情况,一个好的策略是真正明确地说明问题的约束。Jeff Dean 为这样的情况创造了一条经验法则:
如果规模变化 10 倍或 20 倍,请确保您的设计有效,但 X 的正确解决方案 [is] 通常不是 100 倍的最佳解决方案
https://static.googleusercontent.com/media/research.google.com/en//people/jeff/stanford-295-talk.pdf
所以,如果在不久的将来,系统需要支持几十个并发用户。最简单的支持数十到数百个并发用户(可能没有用户分片的地图或缓存就足够了)。在系统能够支持成千上万的并发用户之前,必须改变这种设计。扩展系统通常是一个很好的问题,因为它通常表明项目成功。
- 4 回答
- 0 关注
- 333 浏览
添加回答
举报