我想我在 Golang 中管理數(shù)據(jù)庫連接池時遇到了嚴(yán)重的問題。我使用 Gorilla web 工具包構(gòu)建了一個 RESTful API,當(dāng)只有很少的請求被發(fā)送到服務(wù)器時,它工作得很好。但是現(xiàn)在我開始使用 loader.io 站點(diǎn)執(zhí)行負(fù)載測試。我為這篇長文章道歉,但我想給你完整的圖片。在繼續(xù)之前,這里有一些關(guān)于運(yùn)行 API 和 MySQL 的服務(wù)器的信息: Dedicated Hosting Linux 8GB RAM Go version 1.1.1 使用 go-sql-driver MySQL 5.1 的數(shù)據(jù)庫連接使用 loader.io 我可以毫無問題地發(fā)送 1000 個 GET 請求/15 秒。但是當(dāng)我發(fā)送 1000 個 POST 請求/15 秒時,我收到很多錯誤,所有這些錯誤都是 ERROR 1040 數(shù)據(jù)庫連接過多。許多人在網(wǎng)上報(bào)告了類似的問題。請注意,我現(xiàn)在只測試一個特定的 POST 請求。對于這個帖子請求,我確保了以下內(nèi)容(網(wǎng)上許多其他人也建議這樣做)我確保我不使用 Open 和 Close *sql.DB 作為短期函數(shù)。所以我只為連接池創(chuàng)建了全局變量,正如你在下面的代碼中看到的,盡管我在這里接受建議,因?yàn)槲也幌矚g使用全局變量。我確保在可能的情況下使用 db.Exec,并且只在預(yù)期結(jié)果時使用 db.Query 和 db.QueryRow。由于上面沒有解決我的問題,我嘗試設(shè)置db.SetMaxIdleConns(1000),它解決了1000個POST請求/15秒的問題。這意味著不再有 1040 個錯誤。然后我將負(fù)載增加到 2000 個 POST 請求/15 秒,我再次開始收到 ERROR 1040。我試圖增加 db.SetMaxIdleConns() 中的值,但這并沒有什么區(qū)別。這是我通過運(yùn)行 SHOW STATUS WHERE variable_name= 'Threads_connected'從 MySQL 數(shù)據(jù)庫中獲得的連接數(shù)的一些連接統(tǒng)計(jì)信息;對于 1000 個 POST 請求/15 秒:觀察到 #threads_connected ~= 100 對于 2000 個 POST 請求/15 秒:觀察到 #threads_connected ~= 600我還在 my.cnf 中增加了 MySQL 的最大連接數(shù),但這并沒有什么不同。你有什么建議?代碼看起來好嗎?如果是,那么可能是連接有限。您將在下面找到代碼的簡化版本。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貢獻(xiàn)1864條經(jīng)驗(yàn) 獲得超6個贊
Godatabase/sql
不會阻止您創(chuàng)建無限數(shù)量的數(shù)據(jù)庫連接。如果池中有空閑連接,則使用它,否則創(chuàng)建一個新連接。
因此,在負(fù)載下,您的請求處理程序 sql.DB 可能找不到空閑連接,因此在需要時會創(chuàng)建一個新連接。這會造成一些影響 - 在可能的情況下重用空閑連接并在需要時創(chuàng)建新連接 - 最終達(dá)到 Db 的最大連接數(shù)。而且,不幸的是,在 Go 1.1 中沒有一種方便的方法(例如SetMaxOpenConns)來限制打開的連接。
升級到較新版本的 Golang。在Go 1.2+ 中,你得到SetMaxOpenConns。并查看 MySql 文檔以開始設(shè)置然后進(jìn)行調(diào)整。
db.SetMaxOpenConns(100) //tune this
如果你必須使用 Go 1.1,你需要確保你的代碼一次*sql.DB
只被 N 個客戶端使用。

catspeake
TA貢獻(xiàn)1111條經(jīng)驗(yàn) 獲得超0個贊
需要注意的另一件事是將 my.cnf 文件中的 back_log 設(shè)置為更高的值,例如幾百或 1000。這將有助于每秒處理更多連接。請參閱每秒高連接數(shù)。
- 3 回答
- 0 關(guān)注
- 269 瀏覽
添加回答
舉報(bào)
0/150
提交
取消