我有一个Go API端点,可以进行多个MySQL查询。当端点收到少量请求时,它可以正常工作。但是,我现在正在使用带有100个请求的apache bench来测试它。前100个都经过了。但是,第二个100导致出现此错误
2014/01/15 12:08:03 http: panic serving 127.0.0.1:58602: runtime error: invalid memory address or nil pointer dereference
goroutine 973 [running]:
net/http.func·009()
/usr/local/Cellar/go/1.2/libexec/src/pkg/net/http/server.go:1093 +0xae
runtime.panic(0x402960, 0x9cf419)
/usr/local/Cellar/go/1.2/libexec/src/pkg/runtime/panic.c:248 +0x106
database/sql.(*Rows).Close(0x0, 0xc2107af540, 0x69)
/usr/local/Cellar/go/1.2/libexec/src/pkg/database/sql/sql.go:1576 +0x1e
store.findProductByQuery(0xc2107af540, 0x69, 0x0, 0xb88e80, 0xc21000ac70)
/Users/dennis.suratna/workspace/session-go/src/store/product.go:83 +0xe3
store.FindProductByAppKey(0xc210337748, 0x7, 0x496960, 0x6, 0xc2105eb1b0)
/Users/dennis.suratna/workspace/session-go/src/store/product.go:28 +0x11c
api.SessionHandler(0xb9eff8, 0xc2108ee200, 0xc2108f5750, 0xc2103285a0, 0x0, ...)
/Users/dennis.suratna/workspace/session-go/src/api/session_handler.go:31 +0x2fb
api.func·001(0xb9eff8, 0xc2108ee200, 0xc2108f5750, 0xc2103285a0)
/Users/dennis.suratna/workspace/session-go/src/api/api.go:81 +0x4f
reflect.Value.call(0x3ad9a0, 0xc2101ffdb0, 0x130, 0x48d520, 0x4, ...)
/usr/local/Cellar/go/1.2/libexec/src/pkg/reflect/value.go:474 +0xe0b
reflect.Value.Call(0x3ad9a0, 0xc2101ffdb0, 0x130, 0xc2103c4a00, 0x3, ...)
/usr/local/Cellar/go/1.2/libexec/src/pkg/reflect/value.go:345 +0x9d
github.com/codegangsta/inject.(*injector).Invoke(0xc2103379c0, 0x3ad9a0, 0xc2101ffdb0, 0x4311a0, 0x1db94e, ...)
看起来它不是由并发请求的数量引起的,而是由于没有正确关闭的东西引起的。我已经关闭了我在代码中创建的每个准备语句。我想知道是否有人以前见过这个。
编辑: 这就是我初始化MySQL连接的方式:
func InitStore(environment string) error {
db, err := sql.Open("mysql", connStr(environment))
....
S = &Store{
Mysql: db,
Environment: environment,
}
}
在我启动服务器时只发生一次。
答案 0 :(得分:1)
如果使用Go 1.2.x,则可以使用db.SetMaxOpenConns告诉sql包不要打开多于X个连接。在X连接已经打开(和忙)之后需要数据库连接的查询将阻塞,直到有可用的连接。
话虽如此:“堆栈跟踪”的下一行是什么?当您的服务函数失败时,http / server.go中的行~1093是恢复代码。它看起来更像是你只是错误地处理了一些数据而导致它失败,或者你错过了错误检查,然后在你真正返回错误时尝试处理数据等等。
答案 1 :(得分:1)
好的,所以我能够解决这个问题,现在我可以发送~500个请求,包含10个并发,不再有Broken pipe
或Too many connections error
。
我认为这一切都归结为遵循最佳实践。当您不希望向用户QueryRow
而不是Query
返回多行时,请将其与Scan
链接
db.QueryRow(...).Scan(...)
如果您不希望返回行,并且您不打算重复使用语句,请使用Exec
而不是Prepare
。
如果您已准备好语句或查询多行。不要忘记Close()
从
获得以上所有内容