过去 6 年来,我的服务器一直在运行,没有任何问题,但最近遇到了一些麻烦。我收到了很多 SYN_RECV 连接,这使得连接设备的积压工作推后了很多,而且没有任何东西像应该的那样更新。现在我的服务器是 Intel(R) Xeon(R) CPU E31230 @ 3.20GHz,7 核,32GB 内存,运行 CentOS 6.7 Red Hat。我在这台机器上运行了大约 +- 800 个活动连接。我有 12 个端口在运行,所有 +-800 个设备分布在这 12 个端口上,每个端口最多 100 个设备。我通过 PHP 创建/运行套接字。我将不胜感激任何建议。
-将所有东西都放在 1 个端口上有帮助吗? -将它们扩展到更多端口有帮助吗(每个端口最多 50 个设备) -调整 Linux 设置有帮助吗(会是哪些设置) -用另一种语言编写有帮助吗(如果有的话最好) -还有什么可能导致这个问题?
我启用了 SYN Cookies 来帮助应对 SYN 攻击:
sysctl -n net.ipv4.tcp_syncookies
这是我的 sysctl.conf:
/# Red Hat Linux 的内核 sysctl 配置文件 /# /# 对于二进制值,0 表示禁用,1 表示启用。有关更多详细信息,请参阅 sysctl(8) 和 /# sysctl.conf(5)。
/# 控制 IP 数据包转发 net.ipv4.ip_forward = 0
/# 控制源路由验证 net.ipv4.conf.default.rp_filter = 1
/# 不接受源路由 net.ipv4.conf.default.accept_source_route = 0
/# 控制内核的系统请求调试功能 kernel.sysrq = 0
/# 控制核心转储是否将 PID 附加到核心文件名。 /# 适用于调试多线程应用程序。 kernel.core_uses_pid = 1
/# 控制 TCP syncookies 的使用 net.ipv4.tcp_syncookies = 1
/# 在网桥上禁用 netfilter。net.bridge.bridge-nf-call-ip6tables = 0 net.bridge.bridge-nf-call-iptables = 0 net.bridge.bridge-nf-call-arptables = 0
/# 控制消息队列的默认最大大小 kernel.msgmnb = 65536
/# 控制消息的最大大小,以字节为单位 kernel.msgmax = 65536
/# 控制最大共享段大小,以字节为单位 kernel.shmmax = 68719476736
/# 控制共享内存段的最大数量,以页为单位 kernel.shmall = 4294967296
/# 重试 SYN/ACK 仅三次,而不是五次 net.ipv4.tcp_synack_retries = 5
/# 尝试关闭两次 net.ipv4.tcp_orphan_retries = 5
/# FIN-WAIT-2 仅持续 5 秒 net.ipv4.tcp_fin_timeout = 30
/# 增加 syn 套接字队列大小 (默认值:512) net.ipv4.tcp_max_syn_backlog = 1024 net.core.netdev_max_backlog = 1000
/# 使用较少探测次数进行一小时保持活动 (默认值:7200 & 9) net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_keepalive_probes = 5
/# 输入可以排队的最大数据包 net.core.netdev_max_backlog = 65536
/# 保留片段 15 秒(默认值:30)net.ipv4.ipfrag_time = 30
/# 使用 H-TCP 拥塞控制 net.ipv4.tcp_congestion_control = htcp
net.core.rmem_default = 256960 net.core.rmem_max = 256960 net.core.wmem_default = 256960 net.core.wmem_max = 256960
net.ipv4.tcp_sack = 1 net.ipv4.tcp_window_scaling = 1 net.ipv4.tcp_timestamps = 0 net.ipv4.ip_local_port_range = 15000 61000 net.core.somaxconn = 1024
减去“#”前的“/”
以下是运行端口的 PHP 代码:
#!/usr/bin/php -q
<?php
error_reporting(0);
set_time_limit(0);
ob_implicit_flush();
$address = '123.123.123.123';
$port = 8000;
//Check for the connections
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
logs("socket_create() failed, reason: " . socket_strerror($master) . "\n", $enable_logging);
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
logs("socket_bind() failed, reason: " . socket_strerror($ret) . "\n", $enable_logging);
}
if (($ret = socket_listen($master, SOMAXCONN)) < 0)
{
logs("socket_listen() failed, reason: " . socket_strerror($ret) . "\n", $enable_logging);
}
$read_sockets = array($master);
//Read all data from buffer
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
foreach($changed_sockets as $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
logs("socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n", $enable_logging);
continue;
}
else
{
array_push($read_sockets, $client);
logs("[".date('Y-m-d H:i:s')."] ".$client." CONNECTED "."(".count($read_sockets)."/".SOMAXCONN.")\r\n", $enable_logging);
}
}
else
{
$buffer = socket_read($socket, 8192);
if ($buffer === "")
{
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
socket_close($socket);
}
else
{
//Do DB connections etc here
}
}
}
}
?>
我使用 bash 脚本打开和关闭端口。
任何帮助,我都愿意接受。
答案1
我设法解决了我的服务器和跟踪单元一直遇到的问题。发生了什么事,我们正在使用来自本地服务提供商的自定义 APN 网络,并且我们遇到了他们那边的问题。连接会丢失,当与我的服务器建立连接时,APN 会断开连接。这就是为什么我收到很多 SYN_RECV 连接,这些连接只有在超时后才会退出。