确定 MySQL 连接是否仍然有效的最便宜的方法
题
我有一个用于基于 Web 的数据服务的 MySQL 连接池。当它开始服务请求时,它会从池中获取一个连接来使用。问题是,如果自使用该特定连接以来出现了明显的暂停,服务器可能会超时并关闭其结束。我希望能够在池管理代码中检测到这一点。
诀窍是这样的:我编码的环境只为我提供了一个非常抽象的连接 API。我基本上只能执行SQL语句。我无法访问实际的套接字或直接访问 MySQL 客户端 API。
所以,问题是: 我可以在连接上执行以确定它是否正常工作的最便宜的 MySQL 语句是什么。例如 SELECT 1;
应该可以,但我想知道是否有更便宜的东西?也许有些东西甚至不通过网络,而是在 MySQL 客户端库中处理并有效地回答相同的问题?
澄清: 我不关心检查 MySQL 服务器是否正在运行,或者它的数据库配置是否足以回答查询。如果这些事情发生了,那么服务执行的后续 SQL 将获取并处理适当的错误。我只真正关心 TCP 连接是否打开......因为如果服务器关闭它,那么 Web 服务的 SQL 将收到一个错误,这意味着“只需重新连接并重试”,并且一旦关闭就会很不方便服务代码的垃圾。
关闭: 这 /* ping */
hack 正是我正在寻找的东西,但可惜只能通过 JDBC 获得。通读该黑客的文档,很明显它是为了 确切地 和我想要它的原因一样。为了好奇,我正在工作 哈斯克尔, , 使用 HDBC 和 HDBC-mysql. 。我要请HDBC-mysql的作者添加一个调用的方式 mysql_ping()
直接或通过类似的黑客。
弗拉德的 DO 1
这也是我所追求的东西,并且由于其他 hack 在 JDBC 之外不可用,所以我将使用它。
感谢所有精彩的讨论,尤其是@Vlad!
解决方案
你 不通过线路就无法知道连接的真实状态, , 和 SELECT 1
是一个足够好的候选者(可以说你可以想出一个更短的命令,它需要更少的时间来解析,但与网络甚至环回延迟相比,这些节省是微不足道的。)
话虽如此,我认为 对连接执行 ping 操作 前 从池中检查并不是最好的方法.
您可能应该简单地拥有连接池管理器 执行自己的保持活动(超时)策略 避免被服务器断开连接(如果没有更严重的干预连接问题,这可能会影响您在常规操作中的表现 - 而且您的连接池管理器无论如何也无法提供帮助),以及 为了不占用数据库 (想想文件句柄和内存使用)不必要的。
因此,在我看来,在从池中检查连接之前测试连接条件到底有什么价值是值得怀疑的。可能值得测试连接状态 在连接重新签入池之前, ,但这可以通过在出现 SQL 硬错误(或等效异常)时简单地将连接标记为脏连接来隐式完成(除非您使用的 API 已经公开了 is-bad
-就像打电话给你一样。)
因此我建议:
- 实施客户端保持活动策略
- 从池中检出连接时不执行任何检查
- 在连接返回池之前执行脏检查
- 让应用程序代码处理其他(非超时)异常连接情况
更新
从你的评论中可以看出你确实 真的 想要 ping 连接(我认为这是因为您没有完全控制或了解 MySQL 服务器或中间网络设备(例如代理等)的超时特征。)
在这种情况下你可以使用 DO 1
作为替代 SELECT 1
;这是 边际地 更快——解析更短,并且它不返回实际数据(尽管你 将要 获取 TCP ack
s,因此您仍将进行往返验证连接是否仍已建立。)
更新2
关于 约书亚的帖子, ,这是各种场景的数据包捕获跟踪:
SELECT 1;
13:51:01.463112 IP client.45893 > server.mysql: P 2270604498:2270604511(13) ack 2531191393 win 1460 <nop,nop,timestamp 2983462950 59680547>
13:51:01.463682 IP server.mysql > client.45893: P 1:57(56) ack 13 win 65306 <nop,nop,timestamp 59680938 2983462950>
13:51:01.463698 IP client.45893 > server.mysql: . ack 57 win 1460 <nop,nop,timestamp 2983462951 59680938>
DO 1;
13:51:27.415520 IP client.45893 > server.mysql: P 13:22(9) ack 57 win 1460 <nop,nop,timestamp 2983488906 59680938>
13:51:27.415931 IP server.mysql > client.45893: P 57:68(11) ack 22 win 65297 <nop,nop,timestamp 59681197 2983488906>
13:51:27.415948 IP client.45893 > server.mysql: . ack 68 win 1460 <nop,nop,timestamp 2983488907 59681197>
mysql_ping
14:54:05.545860 IP client.46156 > server.mysql: P 69:74(5) ack 78 win 1460 <nop,nop,timestamp 2987247459 59718745>
14:54:05.546076 IP server.mysql > client.46156: P 78:89(11) ack 74 win 65462 <nop,nop,timestamp 59718776 2987247459>
14:54:05.546092 IP client.46156 > server.mysql: . ack 89 win 1460 <nop,nop,timestamp 2987247459 59718776>
正如你所看到的,除了以下事实: mysql_ping
数据包是 5 个字节而不是 DO 1;
的 9 个字节,往返次数(以及由此导致的网络引起的延迟)完全相同。您支付的唯一额外费用 DO 1
相对于 mysql_ping
是解析 DO 1
, ,这是微不足道的。
其他提示
我不知道你目前正在使用(或什么语言),但对于Java中,有一个特殊的技巧JDBC驱动程序可以做的API。
在标准测试查询是:
select 1
为你指示。如果你把它修改为:
/* ping */ select 1
JDBC驱动程序将注意到这一点,并只发送单个分组到MySQL服务器得到的响应。
我得知这个情况在太阳深潜“插曲名为的MySQL提示Java开发人员标记马修斯。
即使你不使用Java,或许这同样的技巧已经在其他MySQL驱动程序实现的?我假定服务器将需要了解这个特殊的数据包,因此它可以发送一个响应......
“连接”具有多个含义。 MySQL的侦听一个承插这是网络级的“连接”。 MySQL的维护“数据库连接”,其中包括查询执行和其他开销的上下文。
如果你只是想知道,如果该服务被监听,你应该能够执行网络级通话,看是否端口(不知道默认的是什么)正在监听的目标IP。如果你想获得MySQL的引擎反应,我觉得你的SELECT 1
的想法是睦邻它实际上并没有从数据库中获取任何数据,但不确认发动机旋转加速和响应。