为了账号安全,请及时绑定邮箱和手机立即绑定

Golang RESTful API 负载测试导致数据库连接过多

Golang RESTful API 负载测试导致数据库连接过多

Go
慕斯709654 2021-08-23 17:44:48
我想我在 Golang 中管理数据库连接池时遇到了严重的问题。我使用 Gorilla web 工具包构建了一个 RESTful API,当只有很少的请求被发送到服务器时,它工作得很好。但是现在我开始使用 loader.io 站点执行负载测试。我为这篇长文章道歉,但我想给你完整的图片。在继续之前,这里有一些关于运行 API 和 MySQL 的服务器的信息: Dedicated Hosting Linux 8GB RAM Go version 1.1.1 使用 go-sql-driver MySQL 5.1 的数据库连接使用 loader.io 我可以毫无问题地发送 1000 个 GET 请求/15 秒。但是当我发送 1000 个 POST 请求/15 秒时,我收到很多错误,所有这些错误都是 ERROR 1040 数据库连接过多。许多人在网上报告了类似的问题。请注意,我现在只测试一个特定的 POST 请求。对于这个帖子请求,我确保了以下内容(网上许多其他人也建议这样做)我确保我不使用 Open 和 Close *sql.DB 作为短期函数。所以我只为连接池创建了全局变量,正如你在下面的代码中看到的,尽管我在这里接受建议,因为我不喜欢使用全局变量。我确保在可能的情况下使用 db.Exec,并且只在预期结果时使用 db.Query 和 db.QueryRow。由于上面没有解决我的问题,我尝试设置db.SetMaxIdleConns(1000),它解决了1000个POST请求/15秒的问题。这意味着不再有 1040 个错误。然后我将负载增加到 2000 个 POST 请求/15 秒,我再次开始收到 ERROR 1040。我试图增加 db.SetMaxIdleConns() 中的值,但这并没有什么区别。这是我通过运行 SHOW STATUS WHERE variable_name= 'Threads_connected'从 MySQL 数据库中获得的连接数的一些连接统计信息;对于 1000 个 POST 请求/15 秒:观察到 #threads_connected ~= 100 对于 2000 个 POST 请求/15 秒:观察到 #threads_connected ~= 600我还在 my.cnf 中增加了 MySQL 的最大连接数,但这并没有什么不同。你有什么建议?代码看起来好吗?如果是,那么可能是连接有限。您将在下面找到代码的简化版本。var db *sql.DBfunc main() {    db = DbConnect()    db.SetMaxIdleConns(1000)    http.Handle("/", r)    err := http.ListenAndServe(fmt.Sprintf("%s:%s", API_HOST, API_PORT), nil)    if err != nil {       fmt.Println(err)    }}func DbConnect() *sql.DB {    db, err := sql.Open("mysql", connectionString)    if err != nil {        fmt.Printf("Connection error: %s\n", err.Error())        return nil    }    return db}func PostBounce(w http.ResponseWriter, r *http.Request) {    userId, err := AuthRequest(r)    //error checking    //ready requesy body and use json.Unmarshal    bounceId, err := CreateBounce(userId, b)    //return HTTP status code here}func AuthRequest(r *http.Request) (id int, err error) {    //parse header and get username and password    query := "SELECT Id FROM Users WHERE Username=? AND Password=PASSWORD(?)"    err = db.QueryRow(query, username, password).Scan(&id)    //error checking and return}
查看完整描述

3 回答

?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

Godatabase/sql不会阻止您创建无限数量的数据库连接。如果池中有空闲连接,则使用它,否则创建一个新连接。

因此,在负载下,您的请求处理程序 sql.DB 可能找不到空闲连接,因此在需要时会创建一个新连接。这会造成一些影响 - 在可能的情况下重用空闲连接并在需要时创建新连接 - 最终达到 Db 的最大连接数。而且,不幸的是,在 Go 1.1 中没有一种方便的方法(例如SetMaxOpenConns)来限制打开的连接。

升级到较新版本的 Golang。在Go 1.2+ 中,你得到SetMaxOpenConns。并查看 MySql 文档以开始设置然后进行调整。

db.SetMaxOpenConns(100) //tune this

如果你必须使用 Go 1.1,你需要确保你的代码一次*sql.DB只被 N 个客户端使用。


查看完整回答
反对 回复 2021-08-23
?
catspeake

TA贡献1111条经验 获得超0个赞

需要注意的另一件事是将 my.cnf 文件中的 back_log 设置为更高的值,例如几百或 1000。这将有助于每秒处理更多连接。请参阅每秒高连接数


查看完整回答
反对 回复 2021-08-23
  • 3 回答
  • 0 关注
  • 239 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信