【问题标题】:Performance difference between global database connection and opening connection everytime on GolangGolang 上全局数据库连接和每次打开连接的性能差异
【发布时间】:2017-06-15 08:53:15
【问题描述】:

在我当前的项目中,每次用户提出请求时,我都会打开一个新的数据库连接。例如:

func login(w http.ResponseWriter, r *http.Request) {

...

db, err := sqlx.Connect("postgres", "user=postgres password=*** dbname=postgres")

if err != nil {
    ErrorWithJSON(w, err.Error(), http.StatusBadRequest)
    return
}

db.SetMaxIdleConns(0)
db.SetConnMaxLifetime(time.Second * 30)

user, err := loginManager(db, m)

...

err = db.Close()

}

当我搜索其他人的代码时,我看到大多数开发人员为数据库连接创建了一个全局变量,将其设置在 main 上并在整个项目中使用此变量。

我想知道这些方法之间有什么区别吗?如果我使用全局变量,当 5 个不同的用户请求注册/登录等时会有任何延迟。如果会有延迟,我是否应该创建多个数据库连接并将它们存储在一个切片中以供将来的请求,以便我可以在用户时随机选择提出要求。像一个简单的负载均衡器,我不知道?

很抱歉有多个问题。谢谢!

【问题讨论】:

    标签: sql performance go connection-pooling


    【解决方案1】:

    是的,可能存在巨大的性能差异(可能会有几个数量级,具体取决于您运行的查询的性质以及系统和服务器配置)。

    sqlx.DB 类型包装(嵌入)sql.DB 类型,它管理连接池:

    DB 是一个数据库句柄,代表零个或多个底层连接池。多个 goroutine 并发使用是安全的。

    sql 包自动创建和释放连接;它还维护一个空闲的空闲连接池。如果数据库有每个连接状态的概念,那么这种状态只能在事务中可靠地观察到。

    每次打开新连接,“后台”都会发生很多事情:必须解析连接字符串,必须建立TCP连接,必须进行身份验证/授权,必须分配资源在双方(客户端和服务器)等。这些只是主要的,明显的事情。尽管其中一些可以提供/实现优化、缓存,但与单个 DB 实例相比仍然存在显着开销,该实例可能在池中准备好多个已建立、经过身份验证的连接,等待使用/利用。

    同时引用sql.Open():

    返回的数据库对于多个 goroutine 并发使用是安全的,并维护自己的空闲连接池。 因此,Open 函数应该只被调用一次。很少需要关闭数据库。

    您使用的sqlx.Connect() 调用sqlx.Open()“与 sql.Open 相同,但返回 *sqlx.DB”

    总而言之,使用单个全局 sqlx.DBsql.DB 实例,并在任何地方共享/使用它。它为您提供自动连接和连接池管理。这将为您提供最佳性能。您可以使用DB.SetConnMaxLifetime()DB.SetMaxIdleConns()DB.SetMaxOpenConns() 方法微调连接池。

    空闲连接 (DB.SetMaxIdleConns()) 是那些当前未使用,但坐在池中,等待有人接它们的连接。您绝对应该拥有其中一些,例如其中5个或10个,甚至更多。 DB.SetConnMaxLifetime() 控制新连接可以使用多长时间。一旦它变得比这更老,它将被关闭(如果需要,将打开一个新的)。你不应该改变这个,默认行为是永远不会使连接过期。基本上所有默认值都是合理的,只有在遇到性能问题时才应该使用它们。另外,请阅读这些方法的文档以获得清晰的图像。

    查看这个类似的、可能重复的问题:

    mgo - query performance seems consistently slow (500-650ms)

    【讨论】:

    • 感谢您的回答 :) 我是一名自学成才的 golang 开发人员或试图成为……所以有时我真的很难找到答案。您能否分享您对我的负载/平衡器想法的看法?是否有必要或它会提高我的代码的性能?
    • @MertSerin “负载均衡器”概念是“不成熟的”,sql.DB 提供了开箱即用的功能,甚至是更复杂、更高效的连接池形式的变体,它可以配置/微调。请参阅已编辑的答案。一个sqlx.DBsql.DB 真的是你所需要的。
    • 再次感谢您。最后一个问题,我应该使用这几行代码“db.SetMaxIdleConns(0)”和“db.SetConnMaxLifetime(time.Second * 30)”吗?
    • @MertSerin 再次查看已编辑的答案。总结一下,基本上默认是好的,只有在性能问题时才应该更改它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多