Сервер MariaDB прерывает клиентское соединение через 600 секунд

Мой сервер MariaDB синхронизирует мой клиент C++ (используя libmariadb) после 600 секунд (10 минут) бездействия, и я не уверен почему, потому что я не могу найти никаких настроенных тайм-аутов, которые указывают это число.

Вот мой код, где я выполняю простой запрос 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;
}

Stdout серверного процесса сообщает, что истекло время моего соединения:

$ 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, который закрывает соединение.

Причина, по которой я озадачен, заключается в том, что я не изменил ни одно из значений времени ожидания по умолчанию, ни одно из которых не составляет даже 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, поэтому я смотрю на трафик в / из этого одного клиентского соединения. Пакет FIN, отправляемый сервером, является пакетом 1199, ровно через 600 секунд после предыдущего пакета (884). pcap открыт в wireshark

2 ответа

Решение

wait_timeout это сложно. Из того же соединения сделать

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: Разрешить интерактивное время бездействия в секундах (вместо секунд ожидания в течение секунд) перед закрытием соединения. Для переменной сеанса wait_timeout клиента установлено значение переменной session_timeout сессии.

https://dev.mysql.com/doc/relnotes/connector-cpp/en/news-1-1-5.html (MySQL Connector / C++ 1.1.5)

Также можно получить и установить ограничение времени выполнения оператора, используя методы MySQL_Statement::getQueryTimeout() и MySQL_Statement::setQueryTimeout().

Также может быть время ожидания 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/

Я надеюсь, что это поможет, или, по крайней мере, это поможет вам решить проблему:) и, наконец, я думаю, что вы должны обрабатывать разъединения в своем коде, а не полагаться на тайм-ауты.

Galera кластер с балансировкой нагрузки Haproxy. Изменить этот параметр в настройках haproxy по умолчанию timeout connect 10s timeout client 30s timeout server 30s

Другие вопросы по тегам