MariaDB 服务器在 600 秒后超时客户端连接
MariaDB server times out client connection after 600 seconds
我的 MariaDB 服务器在 600 秒(10 分钟)不活动后使我的 C++ 客户端(使用 libmariadb)超时,我不确定为什么,因为我找不到任何指定该数字的已配置超时。
这是我的代码,我在其中执行了一个简单的 SELECT 查询,等待 11 分钟,然后 运行 再次执行相同的查询并出现“服务器已关闭”错误:
#include <iostream>
#include <unistd.h>
#include <errmsg.h>
#include <mysql.h>
int main(int, char**)
{
// connect to the database
MYSQL* connection = mysql_init(NULL);
my_bool reconnect = 0;
mysql_options(connection, MYSQL_OPT_RECONNECT, &reconnect); // don't implicitly reconnect
mysql_real_connect(connection, "127.0.0.1", "testuser", "password",
"my_test_db", 3306, NULL, 0);
// run a simple query
mysql_query(connection, "select 5");
mysql_free_result(mysql_store_result(connection));
std::cout << "First query done...\n";
// sleep for 11 minutes
sleep(660);
// run the query again
if(! mysql_query(connection, "select 5"))
{
std::cout << "Second query succeeded after " << seconds << " seconds\n";
mysql_free_result(mysql_store_result(connection));
}
else
{
if(mysql_errno(connection) == CR_SERVER_GONE_ERROR)
{
// **** this happens every time ****
std::cout << "Server went away after " << seconds << " seconds\n";
}
}
// close the connection
mysql_close(connection);
connection = nullptr;
return 0;
}
服务器进程的标准输出报告我的连接超时:
$ sudo journalctl -u mariadb
...
Jul 24 17:58:31 myhost mysqld[407]: 2018-07-24 17:58:31 139667452651264 [Warning] Aborted connection 222 to db: 'my_test_db' user: 'testuser' host: 'localhost' (Got timeout reading communication packets)
...
查看 tcpdump 捕获,我还可以看到服务器向客户端发送了一个 TCP FIN 数据包,该数据包关闭了连接。
我难过的原因是因为我没有更改任何默认超时值,none 其中甚至有 600 秒:
MariaDB [(none)]> show variables like '%timeout%';
+-------------------------------------+----------+
| Variable_name | Value |
+-------------------------------------+----------+
| connect_timeout | 10 |
| deadlock_timeout_long | 50000000 |
| deadlock_timeout_short | 10000 |
| delayed_insert_timeout | 300 |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_print_lock_wait_timeout_info | OFF |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| thread_pool_idle_timeout | 60 |
| wait_timeout | 28800 |
+-------------------------------------+----------+
那么为什么服务器超时我的连接?根据文档,我原以为这是因为 wait_timeout
服务器变量,但它保留为默认的 8 小时...
顺便说一句,我正在使用 MariaDB 10.0 和 libmariadb 2.0(来自 Ubuntu Xenial Universe 存储库)
编辑:这是捕获断开连接的 tcpdump 捕获图像。我的 Wireshark 过滤器是 tcp.port == 55916
,所以我正在查看这个客户端连接的流量 to/from。服务器发送的 FIN 数据包是数据包 1199,正好比前一个数据包 (884) 晚 600 秒。
wait_timeout
很棘手。从 same 连接做
SHOW SESSION VARIABLES LIKE '%timeout%';
SHOW SESSION VARIABLES WHERE VALUE BETWEEN 500 AND 700;
您应该可以通过执行
来解决该问题
mysql_query("SET @@wait_timeout = 22222");
您是否以 'root' 的身份连接?
更多连接器详细信息:
参见: https://dev.mysql.com/doc/refman/5.5/en/mysql-options.html
CLIENT_INTERACTIVE: Permit interactive_timeout seconds of inactivity (rather than wait_timeout seconds) before closing the connection. The client's session wait_timeout variable is set to the value of the session interactive_timeout variable.
https://dev.mysql.com/doc/relnotes/connector-cpp/en/news-1-1-5.html (MySQL Connector/C++ 1.1.5)
It is also possible to get and set the statement execution-time limit using the MySQL_Statement::getQueryTimeout() and MySQL_Statement::setQueryTimeout() methods.
可能还有 TCP/IP 超时。
我不确定具体原因。但我敢肯定 wait_timeout
不是唯一对此有影响的东西。根据您在问题中包含的唯一错误消息,似乎读取数据包时出现问题。
Got timeout reading communication packets
我认为这更像是 MariaDB 在读取数据包时遇到问题,而不是尝试连接等。我还查看了 MariaDB 客户端库,发现了这个块;
if (ma_net_write_command(net,(uchar) command,arg,
length ? length : (ulong) strlen(arg), 0))
{
if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
{
my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
goto end;
}
end_server(mysql);
if (mariadb_reconnect(mysql))
goto end;
if (ma_net_write_command(net,(uchar) command,arg,
length ? length : (ulong) strlen(arg), 0))
{
my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
goto end;
}
}
https://github.com/MariaDB/mariadb-connector-c/blob/master/libmariadb/mariadb_lib.c
所以当它遇到数据包大小问题时,它似乎将错误代码设置为服务器消失了。我建议你把max_allowed_packet
变量改成一个大的值看看有没有效果。
SET @@global.max_allowed_packet = <some large value>;
https://mariadb.com/kb/en/library/server-system-variables/#max_allowed_packet
我希望它会有所帮助,或者至少它会让您走上解决问题的道路:) 最后,我认为您应该处理代码中的断开连接,而不是依赖超时。
具有 Haproxy 负载平衡的 Galera 集群。在 haproxy 上更改此参数
设置
defaults
timeout connect 10s
timeout client 30s
timeout server 30s
我的 MariaDB 服务器在 600 秒(10 分钟)不活动后使我的 C++ 客户端(使用 libmariadb)超时,我不确定为什么,因为我找不到任何指定该数字的已配置超时。
这是我的代码,我在其中执行了一个简单的 SELECT 查询,等待 11 分钟,然后 运行 再次执行相同的查询并出现“服务器已关闭”错误:
#include <iostream>
#include <unistd.h>
#include <errmsg.h>
#include <mysql.h>
int main(int, char**)
{
// connect to the database
MYSQL* connection = mysql_init(NULL);
my_bool reconnect = 0;
mysql_options(connection, MYSQL_OPT_RECONNECT, &reconnect); // don't implicitly reconnect
mysql_real_connect(connection, "127.0.0.1", "testuser", "password",
"my_test_db", 3306, NULL, 0);
// run a simple query
mysql_query(connection, "select 5");
mysql_free_result(mysql_store_result(connection));
std::cout << "First query done...\n";
// sleep for 11 minutes
sleep(660);
// run the query again
if(! mysql_query(connection, "select 5"))
{
std::cout << "Second query succeeded after " << seconds << " seconds\n";
mysql_free_result(mysql_store_result(connection));
}
else
{
if(mysql_errno(connection) == CR_SERVER_GONE_ERROR)
{
// **** this happens every time ****
std::cout << "Server went away after " << seconds << " seconds\n";
}
}
// close the connection
mysql_close(connection);
connection = nullptr;
return 0;
}
服务器进程的标准输出报告我的连接超时:
$ sudo journalctl -u mariadb
...
Jul 24 17:58:31 myhost mysqld[407]: 2018-07-24 17:58:31 139667452651264 [Warning] Aborted connection 222 to db: 'my_test_db' user: 'testuser' host: 'localhost' (Got timeout reading communication packets)
...
查看 tcpdump 捕获,我还可以看到服务器向客户端发送了一个 TCP FIN 数据包,该数据包关闭了连接。
我难过的原因是因为我没有更改任何默认超时值,none 其中甚至有 600 秒:
MariaDB [(none)]> show variables like '%timeout%';
+-------------------------------------+----------+
| Variable_name | Value |
+-------------------------------------+----------+
| connect_timeout | 10 |
| deadlock_timeout_long | 50000000 |
| deadlock_timeout_short | 10000 |
| delayed_insert_timeout | 300 |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_print_lock_wait_timeout_info | OFF |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| thread_pool_idle_timeout | 60 |
| wait_timeout | 28800 |
+-------------------------------------+----------+
那么为什么服务器超时我的连接?根据文档,我原以为这是因为 wait_timeout
服务器变量,但它保留为默认的 8 小时...
顺便说一句,我正在使用 MariaDB 10.0 和 libmariadb 2.0(来自 Ubuntu Xenial Universe 存储库)
编辑:这是捕获断开连接的 tcpdump 捕获图像。我的 Wireshark 过滤器是 tcp.port == 55916
,所以我正在查看这个客户端连接的流量 to/from。服务器发送的 FIN 数据包是数据包 1199,正好比前一个数据包 (884) 晚 600 秒。
wait_timeout
很棘手。从 same 连接做
SHOW SESSION VARIABLES LIKE '%timeout%';
SHOW SESSION VARIABLES WHERE VALUE BETWEEN 500 AND 700;
您应该可以通过执行
来解决该问题mysql_query("SET @@wait_timeout = 22222");
您是否以 'root' 的身份连接?
更多连接器详细信息:
参见: https://dev.mysql.com/doc/refman/5.5/en/mysql-options.html
CLIENT_INTERACTIVE: Permit interactive_timeout seconds of inactivity (rather than wait_timeout seconds) before closing the connection. The client's session wait_timeout variable is set to the value of the session interactive_timeout variable.
https://dev.mysql.com/doc/relnotes/connector-cpp/en/news-1-1-5.html (MySQL Connector/C++ 1.1.5)
It is also possible to get and set the statement execution-time limit using the MySQL_Statement::getQueryTimeout() and MySQL_Statement::setQueryTimeout() methods.
可能还有 TCP/IP 超时。
我不确定具体原因。但我敢肯定 wait_timeout
不是唯一对此有影响的东西。根据您在问题中包含的唯一错误消息,似乎读取数据包时出现问题。
Got timeout reading communication packets
我认为这更像是 MariaDB 在读取数据包时遇到问题,而不是尝试连接等。我还查看了 MariaDB 客户端库,发现了这个块;
if (ma_net_write_command(net,(uchar) command,arg,
length ? length : (ulong) strlen(arg), 0))
{
if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
{
my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
goto end;
}
end_server(mysql);
if (mariadb_reconnect(mysql))
goto end;
if (ma_net_write_command(net,(uchar) command,arg,
length ? length : (ulong) strlen(arg), 0))
{
my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
goto end;
}
}
https://github.com/MariaDB/mariadb-connector-c/blob/master/libmariadb/mariadb_lib.c
所以当它遇到数据包大小问题时,它似乎将错误代码设置为服务器消失了。我建议你把max_allowed_packet
变量改成一个大的值看看有没有效果。
SET @@global.max_allowed_packet = <some large value>;
https://mariadb.com/kb/en/library/server-system-variables/#max_allowed_packet
我希望它会有所帮助,或者至少它会让您走上解决问题的道路:) 最后,我认为您应该处理代码中的断开连接,而不是依赖超时。
具有 Haproxy 负载平衡的 Galera 集群。在 haproxy 上更改此参数 设置
defaults
timeout connect 10s
timeout client 30s
timeout server 30s