最便宜的方法来确定MySQL连接是否仍然存在

时间:2010-03-30 16:31:12

标签: mysql libmysql hdbc

我有一个基于Web的数据服务的MySQL连接池。当它开始为请求提供服务时,它需要从池中连接才能使用。问题是如果自从使用该特定连接以来已经存在显着的暂停,则服务器可能已经将其计时并且关闭其结束。我希望能够在池管理代码中检测到这一点。

诀窍是:我编码的环境只给我一个非常抽象的API连接。我基本上只能执行SQL语句。我无权访问实际套接字或直接访问MySQL客户端API。

所以,问题是:我可以在连接上执行的最便宜的MySQL语句是什么,以确定它是否正常工作。例如SELECT 1;应该可以工作,但我想知道是否有更便宜的东西?也许某些东西甚至没有通过电子邮件,但是在MySQL客户端库中处理并有效地回答了同样的问题?

澄清:我不关心检查MySQL服务器是否正在运行,或者它的数据库配置是否足以回答查询。如果这些事情发生故障,那么服务执行的后续SQL将获取并处理相应的错误。我真的只关心TCP连接是否打开...因为如果服务器关闭它,那么Web服务的SQL将收到一个错误,意味着“只需重新连接并再试一次”,这样就不方便了。服务代码的渣土。

关闭: /* ping */ hack正是我想要的那种,但唉只能通过JDBC获得。通过文档阅读该hack,很明显它被放在那里完全与我想要的原因相同。好奇的是,我使用HaskelHDBCHDBC-mysql工作。我将要求HDBC-mysql的作者添加一种方法来直接或通过类似的黑客调用mysql_ping()

Vlad的DO 1也是我追求的那种东西,而且由于另一种hack在JDBC之外是不可用的,我将使用它。

感谢所有精彩的讨论,特别是@Vlad!

3 个答案:

答案 0 :(得分:13)

在没有通过电话的情况下不会知道连接的真实状态,并且SELECT 1是一个足够好的候选人(可以说你可以提出一个更短的命令是时候解析,但与网络甚至环回延迟相比,这些节省是微不足道的。)

话虽如此,我认为在从池中检出连接之前ping 并不是最好的方法

您可能只是让您的连接池管理器强制执行其自己的保持活动(超时)策略,以避免被服务器断开连接(没有更严重的干预连接问题,这可能会影响您无论如何,在常规操作的中间 - 你的连接池管理器无论如何都无法帮助),以及为了不占用数据库(想想文件句柄和内存使用)不必要

因此,在我看来,在检查来自池的连接之前确定连接条件的价值是值得怀疑的。在将连接重新检入池中之前,可能需要测试连接状态 ,但是当出现SQL硬错误(或等效异常)时,只需将连接标记为脏即可隐式执行此操作(除非您使用的API已经公开is-bad - 就像您的呼叫一样。)

因此我建议:

  • 实施客户端保持活力策略
  • 在检查池中的连接时未执行任何检查
  • 在连接返回池之前执行脏检查
  • 让应用程序代码处理其他(非超时)异常连接条件

更新

从您的评论中可以看出,您确实确实想要ping连接(我认为这是因为您无法完全控制或了解MySQL服务器上的超时特性或干预网络设备,如代理等。)

在这种情况下,您可以使用DO 1替代SELECT 1;它略微更快 - 解析时更短,并且它不会返回实际数据(尽管 将获得TCP ack,所以你仍然会这样做验证连接仍然建立的往返。)

更新2

关于Joshua's post,这里是各种场景的数据包捕获跟踪:

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的解析,这是微不足道的。

答案 1 :(得分:6)

我不确定您当前正在使用哪种API(或使用什么语言),但对于Java,JDBC驱动程序可以执行一项特殊操作。

标准测试查询是:

select 1
正如你所指出的那样。如果您将其修改为:

/* ping */ select 1

JDBC驱动程序会注意到这一点,并且只向MySQL服务器发送一个数据包以获得响应。

我在题为MySQL Tips for Java Developers With Mark Matthews的太阳'深潜'一集中了解到这一点。

即使你没有使用Java,也许在其他mysql驱动程序中实现了同样的技巧?我假设服务器需要知道这个特殊的数据包,所以它可以发送响应......

答案 2 :(得分:1)

这种情况下的“连接”有多种含义。 MySQL侦听套接字 - 这是网络级别的“连接”。 MySQL维护“数据库连接”,其中包括查询执行和其他开销的上下文。

如果您只想知道服务是否正在侦听,您应该能够执行网络级调用,以查看端口(不知道默认值是什么)是否正在侦听目标IP。如果你想让MySQL引擎做出响应,我认为你的SELECT 1想法是好的 - 它实际上并没有从数据库中获取任何数据,而是确认引擎已经启动并响应。