你使用的Go版本是什么( go version
)?
$ go version
go version devel +b5c8d88bba Tue Aug 25 12:10:40 2020 -0400 darwin/amd64
自定义版本的 go branch [dev.link]
(大约一周前是1.16版本)。
这个问题在最新版本中是否重现?
是的。
你正在使用什么操作系统和处理器架构( go env
)?
go env
输出
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN="/Users/jfaller/go/bin"
GOCACHE="/Users/jfaller/Library/Caches/go-build"
GOENV="/Users/jfaller/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/jfaller/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/jfaller/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/jfaller/src/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/jfaller/src/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/jfaller/go/db_test/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/kt/9h7gfgy955lgbm_cys108l2c002pwh/T/go-build532706798=/tmp/go-build -gno-record-gcc-switches -fno-common"
你做了什么?
运行以下命令:
package main
import (
"database/sql"
"fmt"
"os"
"strconv"
"time"
)
func getVar(name string) int {
val := os.Getenv(name)
if len(val) == 0 {
panic(fmt.Sprintf("error getting: %v", name))
}
v, err := strconv.Atoi(val)
if err != nil {
panic(fmt.Sprintf("error parsing %v %v", name, err))
}
return v
}
func main() {
db, err := // connect to the db of your choice.
if err != nil {
panic(err)
}
defer db.Close()
db.SetConnMaxIdleTime(time.Second * time.Duration(getVar("MAXIDLE")))
db.SetConnMaxLifetime(time.Second * time.Duration(getVar("MAXLIFE")))
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(1)
sleep := time.Second*time.Duration(getVar("SLEEP"))
for i := 0; i < 10; i++ {
db.Ping()
time.Sleep(sleep)
print("\r", i)
}
fmt.Printf("\n%+v\n", db.Stats())
}
如果你使用以下命令运行:MAXIDLE=1 MAXLIFE=0 SLEEP=5 go run .
你预计会看到一些空闲连接被关闭。如果你设置了MAXLIFE,程序可以正常工作,例如:MAXIDLE=1 MAXLIFE=2 SLEEP=5 go run .
你预期看到什么?
SetConnMaxIdleTime
在不设置 SetConnMaxLifetime
的情况下应该有效果。
你看到了什么?
SetConnMaxIdleTime
应该:
- 在不调用
SetConnMaxLifetime
的情况下产生效果 - 或者在文档中被记录为在不调用
SetConnMaxLifetime
的情况下没有效果。错误可能通过调整调用站点附近的shortestIdleTimeLocked
来修复。
9条答案
按热度按时间djp7away1#
/cc @kardianos
9wbgstp72#
这很可能是使用以下代码修复的:
https://go-review.googlesource.com/c/go/+/248817/
iqxoj9l93#
我们应该关闭这个吗?
laik7k3q4#
我不认为那个CL中的逻辑是正确的,也不认为它能解决这个问题,但我可能是误解了。在那之后的CL中,如果maxIdle小于0,它会被返回。我认为期望的是maxLifetime为
MAX(minIdleTimeout, maxLifetime)
。o4hqfura5#
我认为塞思是正确的。https://go-review.googlesource.com/c/go/+/248817/ 会无意中修复这个问题的一些案例。我认为CL也没有完全解决它原本打算解决的问题。我会考虑把一些东西放在一起来彻底解决这个问题。
des4xlb06#
https://golang.org/cl/255966提到了这个问题:
database/sql: add unit test confirming lifetimes
63lcw9qa7#
连接的空闲时间有以下约束。
这可以重写为以下内容。
连接的生命周期也有以下约束。
shortestIdleTimeLocked
用作connectionCleanerRunLocked
的间隔。connectionCleanerRunLocked 应该在每个可能发生过期的时间间隔内运行,因此间隔应该是 min(maxIdleTime, maxLifeTime)。
我理解错了吗?
du7egjpx8#
我整理了一个CL,通过测试确认了这种行为:
https://golang.org/cl/255966
我和Seth都错误地认为这里有一个bug。
0lvr5msh9#
@jeremyfaller 如果我理解正确的话,这个可以关闭吗?