15

我有一个用于基于 Web 的数据服务的 MySQL 连接池。当它开始为请求提供服务时,它会从池中获取一个连接以供使用。问题是,如果在使用该特定连接后出现了明显的暂停,则服务器可能已将其超时并关闭其结束。我希望能够在池管理代码中检测到这一点。

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

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

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

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

Vlad'sDO 1也是我所追求的那种东西,而且由于其他 hack 在 JDBC 之外不可用,我将使用它。

感谢所有精彩的讨论,尤其是@Vlad!

4

3 回答 3

18

如果不通过线路,您将不会知道连接的真实状态,并且SELECT 1是一个足够好的候选者(可以说您可以提出一个更短的命令,它需要更少的时间来解析,但与网络甚至环回延迟相比,这些节省会微不足道。)

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

您可能应该简单地让您的连接池管理器强制执行其自己的保持活动(超时)策略,以避免被服务器断开连接(缺少更严重的干预连接问题,这可能会影响您在常规操作中间的打击 -并且您的连接池管理器无论如何都无法提供帮助),以及为了避免不必要地占用数据库(考虑文件句柄和内存使用)。

因此,在我看来,在从池中检查连接之前测试连接条件的真正价值是值得怀疑的。在将连接签入回池之前测试连接状态可能是值得的,但这可以通过在出现 SQL 硬错误(或等效异常)时简单地将连接标记为脏来隐式完成(除非您正在使用的 API 已经为您公开一个类似is-bad的调用。)

因此,我建议:

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

更新

从您的评论中可以看出您真的很想ping 连接(我认为这是因为您无法完全控制或了解 MySQL 服务器上的超时特征或代理等网络设备)

在这种情况下,您可以DO 1使用SELECT 1; 它稍微快一点——解析时间更短,并且它不返回实际数据(尽管你得到 TCP ack,所以你仍然会进行往返验证连接是否仍然建立。)

更新 2

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

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

于 2010-03-30T16:38:39.640 回答
6

我不确定您当前使用的是什么 API(或什么语言),但对于 Java,JDBC 驱动程序可以做一个特殊的技巧。

标准测试查询是:

select 1

正如你所指出的。如果将其修改为:

/* ping */ select 1

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

我在 Sun 的“Deep Dive”一集中了解到这一点,题为Mark Matthews 为 Java 开发人员提供的 MySQL 技巧

即使您不使用 Java,也许其他 mysql 驱动程序已经实现了相同的技巧?我假设服务器需要知道这个特殊数据包,以便它可以发送响应......

于 2010-03-30T23:38:03.237 回答
1

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

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

于 2010-03-30T16:35:45.607 回答