如果不使用,数据库会挂起
Posted
技术标签:
【中文标题】如果不使用,数据库会挂起【英文标题】:Database hangs if not used 【发布时间】:2015-07-07 03:14:19 【问题描述】:我正在启动一个 Web 应用程序。启动时工作正常,但如果我离开它(比如说,一个小时)并用另一个请求点击它,查询就会挂起。我曾考虑在每次查询后关闭它,然后打开一个新连接,但文档明确说“关闭数据库是很少见的,因为数据库句柄是长期存在的,并且在许多 goroutine 之间共享。”。我做错了什么?
package main
import (
"database/sql"
"log"
"net/http"
_ "github.com/lib/pq"
)
var Db *sql.DB
func main()
var err error
Db, err = sql.Open("postgres", "user=me password=openupitsme host=my.host.not.yours dbname=mydb sslmode=require")
if err != nil
log.Fatal("Cannot connect to db: ", err)
http.HandleFunc("/page", myHandler)
http.ListenAndServe(":8080", nil)
func myHandler(w http.ResponseWriter, r *http.Request)
log.Println("Handling Request....", r)
query := `SELECT pk FROM mytable LIMIT 1`
rows, err := Db.Query(query)
if err != nil
log.Println(err)
defer rows.Close()
for rows.Next()
var pk int64
if err := rows.Scan(&pk); err != nil
log.Println(err)
log.Println(pk)
log.Println("Request Served...")
编辑#1: 我的 postgres 日志显示:
2015-07-08 18:10:01 EDT [7710-1] user@here LOG: could not receive data from client: Connection reset by peer
2015-07-08 18:20:01 EDT [7756-1] user@here LOG: could not receive data from client: Connection reset by peer
【问题讨论】:
应该有错误信息。 “查询挂起”描述性不够。 数据库与应用程序位于同一台机器上,还是单独的?是否涉及防火墙/NAT(状态可能由于不活动而超时。当应用挂起时,netstat 是否仍将连接显示为活动? 你在哪里运行数据库?是在heroku上吗?如果不使用 Heroku 会“休眠”,因此下一个实时查询需要时间。另外,请注意,您不需要为每个查询打开和关闭连接,但您应该在程序末尾有一个 close 语句。 @AnshuPrateek 注意main()
中的defer db.Close()
如果您的应用程序被发送SIGINT
(通过键盘或进程管理器)将不会被执行 - 您必须明确抓住那个案子。它不会在功能上对大多数应用程序产生影响。
查看设置db.SetMaxIdleConns(x)
(5 - 10 空闲是一个很好的起点)。没有它,池可能需要一些设置时间来重新验证并为您提供可用的连接。
【参考方案1】:
我也遇到过类似的问题。在我们的案例中,问题是由位于客户端计算机和数据库之间的连接跟踪防火墙引起的。
此类防火墙会跟踪 TCP 级别的连接,并且为了限制资源使用,然后会超时在它们看来长时间处于非活动状态的连接。我们在本例中观察到的症状与您的非常相似:在客户端,连接似乎挂起,而在服务器端您可以看到connection reset by peer
。
防止这种情况的一种方法是确保启用TCP Keepalives,并且保持活动间隔小于导致连接问题的防火墙、路由器等的超时。这由您可以在连接字符串中设置的 libpq 连接参数 keepalives
、keepalives_idle
、keepalives_interval
和 keepalives_count
控制。有关这些参数的说明,请参阅manual。
keepalive
判断是否启用了keepalive功能。它默认为1
(启用),因此您可能不需要指定它。
keepalives_idle
确定在发送保活之前的空闲时间量。如果您不指定此项,它将默认为操作系统的默认值。
在 Linux 系统中,您可以通过检查 /proc/sys/net/ipv4/tcp_keepalive_time
查看默认值 - 在我的服务器中,它设置为 7200 秒,在您的情况下这太长了,因为您观察到连接在大约 1 小时后断开.
您可以尝试将其设置为 2500 秒。
Linux 文档项目提供了一个有用的TCP Keepalive HOWTO 文档,其中详细描述了它们的工作原理。
请注意,并非所有操作系统都支持 TCP keepalive。如果您无法在此处启用 keepalive,您可能需要考虑其他一些选项:
如果它在您的控制范围内,请重新配置正在断开连接的防火墙/路由器,这样它就不会为 Postgresql 客户端连接这样做
1234563如果您的编程环境提供连接缓存(从我收集的 cmets 提供),那么这可能会很棘手。【讨论】:
以上是关于如果不使用,数据库会挂起的主要内容,如果未能解决你的问题,请参考以下文章
为啥这个简单的 Node, Sequelize Promise 代码会挂起?
Java JDBC Oracle SQL 查询每隔几个月就会挂起一次