go 数据库/SQL:设置SetConnMaxIdleTime但没有设置SetConnMaxLifetime无效,

lokaqttq  于 6个月前  发布在  Go
关注(0)|答案(9)|浏览(54)

你使用的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 来修复。
iqxoj9l9

iqxoj9l93#

我们应该关闭这个吗?

laik7k3q

laik7k3q4#

我不认为那个CL中的逻辑是正确的,也不认为它能解决这个问题,但我可能是误解了。在那之后的CL中,如果maxIdle小于0,它会被返回。我认为期望的是maxLifetime为MAX(minIdleTimeout, maxLifetime)

o4hqfura

o4hqfura5#

我认为塞思是正确的。https://go-review.googlesource.com/c/go/+/248817/ 会无意中修复这个问题的一些案例。我认为CL也没有完全解决它原本打算解决的问题。我会考虑把一些东西放在一起来彻底解决这个问题。

des4xlb0

des4xlb06#

https://golang.org/cl/255966提到了这个问题:database/sql: add unit test confirming lifetimes

63lcw9qa

63lcw9qa7#

连接的空闲时间有以下约束。

idleTime <= maxIdleTime && idleTime <= maxLifeTime

这可以重写为以下内容。

idleTime <= min(maxIdleTime, maxLifeTime)

连接的生命周期也有以下约束。

lifeTime <= maxLifeTime

shortestIdleTimeLocked 用作 connectionCleanerRunLocked 的间隔。
connectionCleanerRunLocked 应该在每个可能发生过期的时间间隔内运行,因此间隔应该是 min(maxIdleTime, maxLifeTime)。
我理解错了吗?

du7egjpx

du7egjpx8#

我整理了一个CL,通过测试确认了这种行为:
https://golang.org/cl/255966
我和Seth都错误地认为这里有一个bug。

0lvr5msh

0lvr5msh9#

@jeremyfaller 如果我理解正确的话,这个可以关闭吗?

相关问题