我们拥有MySQL 5.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已经消失
和
Connection_errors_peer_address
编辑:
主服务器
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
答案 0 :(得分:7)
在MySQL 5.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_socket_getpeername()只是getpeername()之上的包装器。
man 2 getpeername
手册列出了以下可能的错误:
NAME
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()的包装器,根据手册页man 3 getnameinfo
,它也可能由于以下原因而失败:
NAME
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服务器实际上在做的是Reverse DNS lookup,以:
总体而言,用Connection_errors_peer_address
占的失败可能是由于系统负载(导致暂时性失败,例如内存不足等)或由于网络问题影响了DNS。
披露:我恰好是在MySQL中实现此Connection_errors_peer_address
状态变量的人,以期在代码的这一方面拥有更好的可见性/可观察性。
[编辑],以了解更多详细信息和/或准则:
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
表中有多少行。host_cache_size
系统变量。表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
显示服务器强制关闭的某些连接。当会话闲置很长时间时,通常会发生这种情况。
发生这种情况的典型情况是:
请注意,忘记彻底关闭会话的客户端应用程序将执行1-3,主服务器上的Aborted_clients可能就是这种情况。在此处进行一些清理工作以使用主服务器修复客户端应用程序将有助于减少资源消耗,因为在超时时将151650个会话打开以使其死掉是有代价的。
执行1-4的客户端应用程序可能导致服务器上的Aborted_clients ,而MySQL在客户端上已消失。报告“ MySQL已经消失”的客户端应用程序很可能是这里的罪魁祸首。
例如,如果监视应用程序每N秒检查一次服务器,则确保超时(此处为30和60秒)明显大于N,否则服务器将终止监视会话。