gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-29 00:50:27 28 4
gpt4 key购买 nike

我认为我在使用 Golang 管理数据库连接池时遇到了严重的问题。我使用 Gorilla Web 工具包构建了一个 RESTful API,当只有很少的请求被发送到服务器时,它工作得很好。但现在我开始使用 loader.io 站点执行负载测试。对于这篇冗长的帖子,我深表歉意,但我想为您提供全貌。

在继续之前,这里有一些关于运行 API 和 MySQL 的服务器的信息:专用主机 Linux8GB 内存转到版本 1.1.1使用 go-sql-driver 连接数据库MySQL 5.1

使用 loader.io 我可以毫无问题地发送 1000 个 GET 请求/15 秒。但是当我发送 1000 个 POST 请求/15 秒时,我会收到很多错误,所有这些错误都是 ERROR 1040 too many database connections。很多人在网上反射(reflect)过类似的问题。请注意,我现在只测试一个特定的 POST 请求。对于这个帖子请求,我确保了以下内容(这也是许多其他人在线建议的)

  1. 我确保我不使用 Open 和 Close *sql.DB 作为短期函数。因此,我只为连接池创建了全局变量,如您在下面的代码中所见,尽管我愿意在这里征求建议,因为我不喜欢使用全局变量。

  2. 我确保尽可能使用 db.Exec,并且只在需要结果时使用 db.Query 和 db.QueryRow。

由于上面没有解决我的问题,我尝试设置db.SetMaxIdleConns(1000),解决了1000个POST请求/15秒的问题。意味着不再有 1040 错误。然后我将负载增加到 2000 个 POST 请求/15 秒,我又开始收到错误 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.DB

func 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
}

func CreateBounce(userId int, bounce NewBounce) (bounceId int64, err error) {
//initialize some variables
query := "INSERT INTO Bounces (.....) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
result, err := db.Exec(query, ......)

//error checking

bounceId,_ = result.LastInsertId()

//return
}

最佳答案

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

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

升级到更新版本的 Golang。在 Go 1.2+你得到 SetMaxOpenConns .和 check out the MySql docs for starting setting然后调整。

db.SetMaxOpenConns(100) //tune this

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

关于mysql - Golang RESTful API 负载测试导致数据库连接过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26564084/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com