I'm developing rest api with gin-gonic and I'm getting too many connections
error. How to handle it ?
I'm on digital ocean 1GB RAM / 1CPU with mysql 5.7.9
my implementation
type Impl struct {
DB gorm.DB
}
var i Impl
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
i.InitDB()
r.GET("/questions", func(c *gin.Context) {
questions := i.GetRandomQuestions("userID", 10)
c.JSON(200, gin.H{"question": questions})
})
r.Run(":" + os.Getenv("PORT"))
}
func (i *Impl) InitDB() {
var err error
i.DB, err = gorm.Open("mysql", "conn str")
if err != nil {
log.Fatalf("Got error when connect database, the error is '%v'", err)
}
i.DB.LogMode(true)
i.DB.DB().SetMaxIdleConns(10)
i.DB.DB().SetMaxOpenConns(100)
}
func (i *Impl) GetRandomQuestions(userID string, count int) []Question {
var waitGroup sync.WaitGroup
waitGroup.Add(count)
questions := make([]Question, count)
items := make([]Item, count)
i.DB.Where("user_id = ? AND is_answered = ? AND RAND()<(SELECT ((?/COUNT(*))*10) FROM items)", userID, false, count).Order("RAND()").Limit(count).Find(&items)
for index, item := range items {
go func(item Item, index int) {
defer waitGroup.Done()
questions[index].Text = item
}(item, index)
}
waitGroup.Wait()
return questions
}
I think this is your mysql setting problem, it can't accept that many connections.
Gorm's SetMaxOpenConns is using golang sql database package's method, if it has problem, it might be driver's issue.
抱歉, 我使用了中文来描述我的问题
在postgresql 上, 我也遇到同样的问题, gorm 占用了太多连接(这些连接应该是没有在代码执行后及时关闭), 导致使用同一pgsql 服务的其他应用(非golang)报告连接不够. 重启gorm所在应用问题解决. 由于使用gorm的应用是一个较小访问量的应用, 理论上不应该会出现该问题
所以, 我的问题是: gorm应该在何时关闭连接 , 在文档中, 我没有发现这方面的信息, 通常orm 都会提及这方面的正确举措, 而不管gorm或是xorm, 我都只看到一个通常用于全局的open后, 后面都没有关闭这方面的信息.
@jiangjianxiao 你可以用 db.DB().Close()
来关闭链接,不过我感觉你可以使用错误,你的 DB 是建好一个 connection,然后全局使用么?是不是每一个请求都建了一个连接?
如果全局共享链接的话,db.DB().SetMaxOpenConns(10)
设置一个最大打开链接数,就应该不会出现连接不够的问题
我也出现了这种情况
for ... {
g.Db.Table("xxx").Where("id=?",i).First(&item)
}
@jiangjianxiao 你可以用
db.DB().Close()
来关闭链接,不过我感觉你可以使用错误,你的 DB 是建好一个 connection,然后全局使用么?是不是每一个请求都建了一个连接?如果全局共享链接的话,
db.DB().SetMaxOpenConns(10)
设置一个最大打开链接数,就应该不会出现连接不够的问题
然而, 依然没用, 设置了这个, EST 的连接数会降下来, 但是 TIME_WAIT 依然维持高位, 哪个设置能降低 TIME_WAIT 的指标?
@jiangjianxiao 你可以用
db.DB().Close()
来关闭链接,不过我感觉你可以使用错误,你的 DB 是建好一个 connection,然后全局使用么?是不是每一个请求都建了一个连接?
如果全局共享链接的话,db.DB().SetMaxOpenConns(10)
设置一个最大打开链接数,就应该不会出现连接不够的问题然而, 依然没用, 设置了这个, EST 的连接数会降下来, 但是 TIME_WAIT 依然维持高位, 哪个设置能降低 TIME_WAIT 的指标?
我也出现了这种情况,只见了一个链接,然后SetMaxOpenConns(100)。会报Host is blocked because of many connection errors的错误
@followtimes 请问你的解决了嘛?我的出现了类似情况,海量的 TIME_WAIT
同样的问题
有解决吗?也是出现大量的time_wait
有解决吗?也是出现大量的time_wait
你可以设置最大连接数和最小连接数,让它们相等看看
有解决吗?也是出现大量的time_wait
你可以设置最大连接数和最小连接数,让它们相等看看
不行~依旧大量time wait
@jinzhu 大量的time wait是怎么回事啊
@Atevens 因为连接池没有配置好。所以估计你们在压测的时候,到了timeout
时间,连接断开,连接池会创建新的连接。因此,会不断的创建新的连接,不断的断开连接,自然会有大量time_wait
。
@Atevens 怕你不知道,多说一句哈,open
返回的不仅仅是一个连接,而是一个连接池。
@Atevens 因为连接池没有配置好。所以估计你们在压测的时候,到了
timeout
时间,连接断开,连接池会创建新的连接。因此,会不断的创建新的连接,不断的断开连接,自然会有大量time_wait
。
我压测的时候都是等连接数降到正常水平,time_wait数降到0后才开始,连接池大小都配过,而且同样的连接数配置用原生的以及xorm都没出现time wait的情况。所以不太清楚啥原因~
@ONG-YA
我们这段代码是可以的:
var err error
var db *gorm.DB
connCfg := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=disable",
host, port, dbUser, dbName, password)
db, err = gorm.Open("postgres", connCfg)
db.DB().SetConnMaxLifetime(5 * time.Second)
db.DB().SetMaxOpenConns(10)
db.DB().SetMaxIdleConns(10)
// db = DB.Debug()
return db, nil
@Atevens 怕你不知道,多说一句哈,
open
返回的不仅仅是一个连接,而是一个连接池。
我使用的配置和你差不多,正常使用情况下会出现大量wait timeout ,而且事务都检查了都有提交,查询语句rows.next()也使用了scan(),都不知道哪里还有问题
@Atevens 你是否是单例模式?不要多次调用open
函数。
@Atevens 你是否是单例模式?不要多次调用
open
函数。
是单例,sync.Once.Do 初始化的
使用sql_calc_found_rows做分页查询遇到了同样的问题,分页查询代码如下
`
sql := fmt.Sprintf("select sql_calc_found_rows * from %s order by id limit %d,%d", table, (p.Page-1)*p.Count, p.Count)
err := GetDB().Raw(sql).Scan(result).Error
rows, err := GetDB().Raw("select found_rows()").Rows()
for 循环压测必现,debug发现只要不查询GetDB().Raw("select found_rows()").Rows()就不会出现too many connections,于是改为下面代码后, 问题解决
sql := fmt.Sprintf("select sql_calc_found_rows * from %s order by id limit %d,%d", table, (p.Page-1)*p.Count, p.Count)
type Count struct {
Count int
}
c := Count{}
err = GetDB().Raw("select found_rows() as count").Scan(&c).Error
`
只是换了种写法, 没有深入研究为什么,请指教