【发布时间】:2018-10-26 02:28:13
【问题描述】:
我有一个简单的 Go 文件,目的是返回客户信息的 json 响应。当我使用 apache benchmark 对该脚本进行基准测试时,请求保持活动状态
ab -t 10s -kc 1000 http://127.0.0.1:8080/clients/show/1
但是当请求没有保持活跃时,我不会受到这种恐慌
ab -t 10s -c 1000 http://127.0.0.1:8080/clients/show/1
错误:
2018/10/26 03:26:42 http:恐慌服务 127.0.0.1:44800:错误 1040: 连接太多 goroutine 220522 [正在运行]: net/http.(*conn).serve.func1(0xc001779e00)
我的代码:
package main
import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
"net/http"
"runtime"
)
type Client struct {
ID int `json:"id"`
UserID int `json:"user_id"`
Name string `json:"name"`
Telephone string `json:"telephone"`
Email string `json:"email"`
Category sql.NullString `json:"string"`
Notes string `json:"notes"`
Additional sql.NullString `json:"additional"`
CreatedAt sql.NullString `json:"created_at"`
UpdatedAt sql.NullString `json:"updated_at"`
DeletedAt sql.NullString `json:"deleted_at"`
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
r := mux.NewRouter()
r.HandleFunc("/clients/show/{id}", showClient).Methods("GET")
http.ListenAndServe(":8080", r)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func showClient(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("mysql", "root@tcp(127.0.0.1:3306)/crm")
if err != nil {
panic(err.Error())
}
var client Client
// Execute the query
err = db.QueryRow("SELECT * FROM clients where id = ?", 1).Scan(
&client.ID,
&client.UserID,
&client.Name,
&client.Telephone,
&client.Email,
&client.Category,
&client.Notes,
&client.Additional,
&client.CreatedAt,
&client.UpdatedAt,
&client.DeletedAt,
)
if err != nil {
panic(err.Error())
}
db.Close()
json.NewEncoder(w).Encode(client)
}
有人可以解释一下为什么会在如此低的并发请求率下发生这种情况,以及解决这个问题的正确方法是什么。
【问题讨论】:
-
当您调用
sql.Open时,您将获得一个应该重复使用的连接池。您应该在启动服务器之前打开它,让您的处理程序引用一个池。 -
golang.org/pkg/database/sql/#Open > 返回的 DB 对于多个 goroutine 并发使用是安全的,并维护自己的空闲连接池。因此,Open 函数应该只被调用一次。很少需要关闭数据库。
标签: go