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

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

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

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

关闭:/* ping */ hack 正是我正在寻找的东西,但可惜只能通过 JDBC 获得。通读该黑客的文档,很明显它是为了 确切地 和我想要它的原因一样。为了好奇,我正在工作 哈斯克尔, , 使用 HDBCHDBC-mysql. 。我要请HDBC-mysql的作者添加一个调用的方式 mysql_ping() 直接或通过类似的黑客。

弗拉德的 DO 1 这也是我所追求的东西,并且由于其他 hack 在 JDBC 之外不可用,所以我将使用它。

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

有帮助吗?

解决方案

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

话虽如此,我认为 对连接执行 ping 操作 从池中检查并不是最好的方法.

您可能应该简单地拥有连接池管理器 执行自己的保持活动(超时)策略 避免被服务器断开连接(如果没有更严重的干预连接问题,这可能会影响您在常规操作中的表现 - 而且您的连接池管理器无论如何也无法提供帮助),以及 为了不占用数据库 (想想文件句柄和内存使用)不必要的。

因此,在我看来,在从池中检查连接之前测试连接条件到底有什么价值是值得怀疑的。可能值得测试连接状态 在连接重新签入池之前, ,但这可以通过在出现 SQL 硬错误(或等效异常)时简单地将连接标记为脏连接来隐式完成(除非您使用的 API 已经公开了 is-bad-就像打电话给你一样。)

因此我建议:

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

更新

从你的评论中可以看出你确实 真的 想要 ping 连接(我认为这是因为您没有完全控制或了解 MySQL 服务器或中间网络设备(例如代理等)的超时特征。)

在这种情况下你可以使用 DO 1 作为替代 SELECT 1;这是 边际地 更快——解析更短,并且它不返回实际数据(尽管你 将要 获取 TCP acks,因此您仍将进行往返验证连接是否仍已建立。)

更新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的想法是睦邻它实际上并没有从数据库中获取任何数据,但不确认发动机旋转加速和响应。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top