mysql已经消失了:连接错误\u对等地址\u高数字

lnlaulya  于 2021-06-18  发布在  Mysql
关注(0)|答案(1)|浏览(363)

我们有MySQL5.7主-从复制,在从服务器端,我们的应用程序监控工具(tideways和php7.0)可能会不时报告
mysql已经消失了。
检查mysql端:

show global status like '%Connection%';

+-----------------------------------+----------+
| Variable_name                     | Value    |
+-----------------------------------+----------+
| Connection_errors_accept          | 0        |
| Connection_errors_internal        | 0        |
| Connection_errors_max_connections | 0        |
| Connection_errors_peer_address    | 323      |
| Connection_errors_select          | 0        |
| Connection_errors_tcpwrap         | 0        |
| Connections                       | 55210496 |
| Max_used_connections              | 387      |
| Slave_connections                 | 0        |
+-----------------------------------+----------+

这个 Connection_errors_peer_address 显示323。如何进一步调查造成双方问题的原因:
mysql已经消失了

连接\u错误\u对等\u地址
编辑:
主服务器

net_retry_count = 10 
net_read_timeout = 120 
net_write_timeout = 120 
skip_networking = OFF
Aborted_clients = 151650

从属服务器1

net_retry_count = 10
net_read_timeout = 30 
net_write_timeout = 60 
skip_networking = OFF
Aborted_clients = 3

从属服务器2

net_retry_count = 10
net_read_timeout = 30 
net_write_timeout = 60 
skip_networking = OFF
Aborted_clients = 3
rdrgkggo

rdrgkggo1#

在MySQL5.7中,当一个新的tcp/ip连接到达服务器时,服务器会执行一些检查,在中实现 sql/sql_connect.cc 在功能上 check_connection() 这些检查之一是获取客户端连接的ip地址,如下所示:

static int check_connection(THD *thd)
{
...
  if (!thd->m_main_security_ctx.host().length)     // If TCP/IP connection
  {
...
    peer_rc= vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST);
    if (peer_rc)
    {
      /*
        Since we can not even get the peer IP address,
        there is nothing to show in the host_cache,
        so increment the global status variable for peer address errors.
      */
      connection_errors_peer_addr++;
      my_error(ER_BAD_HOST_ERROR, MYF(0));
      return 1;
    }
...
}

失败时,状态变量 connection_errors_peer_addr 则拒绝连接。 vio_peer_addr() 在中实现 vio/viosocket.c (代码简化为仅显示重要调用)

my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,
                      size_t ip_buffer_size)
{
  if (vio->localhost)
  {
...
  }
  else
  {
    /* Get sockaddr by socked fd. */

    err_code= mysql_socket_getpeername(vio->mysql_socket, addr, &addr_length);

    if (err_code)
    {
      DBUG_PRINT("exit", ("getpeername() gave error: %d", socket_errno));
      DBUG_RETURN(TRUE);
    }

    /* Normalize IP address. */

    vio_get_normalized_ip(addr, addr_length,
                          (struct sockaddr *) &vio->remote, &vio->addrLen);

    /* Get IP address & port number. */

    err_code= vio_getnameinfo((struct sockaddr *) &vio->remote,
                              ip_buffer, ip_buffer_size,
                              port_buffer, NI_MAXSERV,
                              NI_NUMERICHOST | NI_NUMERICSERV);

    if (err_code)
    {
      DBUG_PRINT("exit", ("getnameinfo() gave error: %s",
                          gai_strerror(err_code)));
      DBUG_RETURN(TRUE);
    }
...
  }
...
}

简言之,唯一的失败途径 vio_peer_addr() 当呼叫 mysql_socket_getpeername() 或者 vio_getnameinfo() 失败。
mysql\u socket\u getpeername()只是getpeername()之上的一个 Package 器。
这个 man 2 getpeername 手册列出了以下可能的错误:
名称

getpeername - get name of connected peer socket

错误

EBADF  The argument sockfd is not a valid descriptor.

   EFAULT The addr argument points to memory not in a valid part of the process address space.

   EINVAL addrlen is invalid (e.g., is negative).

   ENOBUFS
          Insufficient resources were available in the system to perform the operation.

   ENOTCONN
          The socket is not connected.

   ENOTSOCK
          The argument sockfd is a file, not a socket.

在这些错误中,只有 ENOBUFS 是有道理的。
至于 vio_getnameinfo() ,它只是getnameinfo()上的一个 Package ,根据手册页 man 3 getnameinfo 可能由于以下原因而失败:
名称

getnameinfo - address-to-name translation in protocol-independent manner

返回值

EAI_AGAIN
          The name could not be resolved at this time.  Try again later.

   EAI_BADFLAGS
          The flags argument has an invalid value.

   EAI_FAIL
          A nonrecoverable error occurred.

   EAI_FAMILY
          The address family was not recognized, or the address length was invalid for the specified family.

   EAI_MEMORY
          Out of memory.

   EAI_NONAME
          The name does not resolve for the supplied arguments.  NI_NAMEREQD is set and the host's name cannot be located, or neither

请求了主机名或服务名。

EAI_OVERFLOW
          The buffer pointed to by host or serv was too small.

   EAI_SYSTEM
          A system error occurred.  The error code can be found in errno.

   The gai_strerror(3) function translates these error codes to a human readable string, suitable for error reporting.

这里可能发生许多故障,基本上是由于重载或网络。
为了理解这段代码背后的过程,mysql服务器实际上在做一个反向dns查找,以:
查找客户端的主机名
找到与此主机名对应的ip地址,以便稍后再次将此ip地址转换为主机名(请参阅下面的对ip\ to\ U hostname()的调用)。
总的来说,失败是由 Connection_errors_peer_address 可能是由于系统负载(导致内存不足等瞬时故障)或影响dns的网络问题。
披露:我恰好是实施这个计划的人 Connection_errors_peer_address mysql中的status变量,作为在代码的这个区域中具有更好的可见性/可观察性的努力的一部分。
[编辑]跟进更多细节和/或指南:
什么时候 Connection_errors_peer_address 则根本原因不会打印在日志中。这是不幸的故障排除,但也避免洪水日志造成更大的损害,这里有一个权衡。请记住,在登录之前发生的任何事情都是非常敏感的。。。
如果服务器的内存真的用完了,很有可能其他很多东西都会坏掉,而且服务器会很快宕机。通过监视 mysqld ,并监控 uptime ,应该很容易确定故障是“仅”导致连接关闭,而服务器仍在运行,还是服务器本身发生灾难性故障。
假设服务器一直处于故障状态,则更可能的罪魁祸首是第二个调用,即 getnameinfo .
使用 skip-name-resolve 不会有任何效果,因为此检查稍后会发生(请参阅 specialflag & SPECIAL_NO_RESOLVE 在代码中 check_connection() )
什么时候 Connection_errors_peer_address 如果失败,请注意服务器会干净地返回错误 ER_BAD_HOST_ERROR 然后关闭套接字。这不同于只是突然关闭一个套接字(比如在崩溃中):前者应该由客户机报告为 "Can't get hostname for your address" ,后者报告为 "MySQL has gone away" .
客户端连接器是否真的 ER_BAD_HOST_ERROR 另一种情况是插座关闭方式不同
考虑到此故障总体上似乎与dns查找有关,我将检查以下项目:
看看这一行有多少行 performance_schema.host_cache table。
将其与主机缓存的大小进行比较,请参见 host_cache_size 系统变量。
如果主机缓存看起来已满,请考虑增大其大小:这将减少dns调用的总体数量,减轻dns的压力,并希望(不可否认,这只是一个暗中一击)dns瞬时故障将消失。
5500万个连接中的323个看起来确实是暂时的。假设监控客户机有时确实正确连接,请检查该客户机的表host\ U缓存中的行:它可能包含报告的其他故障。
performance_schema.host_cache 文档:
https://dev.mysql.com/doc/refman/5.7/en/host-cache-table.html
进一步阅读:
http://marcalff.blogspot.com/2012/04/performance-schema-nailing-host-cache.html
[编辑2]根据可用的新数据:
这个 Aborted_clients status变量显示服务器强制关闭的一些连接。这通常发生在会话空闲很长时间的情况下。
发生这种情况的典型情况是:
客户端打开一个连接,并发送一些查询
然后,客户端在一段较长的时间内不执行任何操作(大于net\u read\u超时)
由于缺少通信量,服务器将关闭会话,然后重新连接
然后客户端发送另一个查询,看到一个关闭的连接,并报告“mysql已经消失”
请注意,忘记干净地关闭会话的客户机应用程序将执行1-3,这可能是主服务器上中止的\u客户机的情况。在这里进行一些清理来修复使用主服务器的客户端应用程序,这将有助于减少资源消耗,因为让151650个会话在超时时关闭是有代价的。
执行1-4的客户机应用程序可能会导致服务器上的\u客户机中止,而客户机上的mysql已经消失。报告“mysql已经消失”的客户端应用程序很可能是罪魁祸首。
如果一个监视应用程序每n秒检查一次服务器,那么请确保超时时间(这里是30秒和60秒)明显大于n,否则服务器将终止监视会话。

相关问题