Golang上全局数据库连接和每次打开连接的性能差异

Mer*_*rin 4 sql performance connection-pooling go

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

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()

}
Run Code Online (Sandbox Code Playgroud)

我在搜索别人的代码时看到,大部分开发者都创建了一个数据库连接的全局变量,设置在main上,然后在整个项目中使用这个变量。

我想知道这些方法有什么区别吗?如果我使用全局变量,当 5 个不同的用户请求注册/登录等时,会不会有任何延迟。提出请求。像一个简单的负载均衡器,我不知道?

抱歉有多个问题。谢谢!

icz*_*cza 5

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

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 - 查询性能似乎一直很慢(500-650 毫秒)