网络连接拒绝与日志排查全解析
在网络服务的运行过程中,我们常常会遇到连接被拒绝的情况,而且往往没有明显的原因。下面我们就来详细探讨如何解决这类问题,以及如何通过日志来排查故障。
连接拒绝场景分析
有时候,服务会拒绝连接,却不给出明确原因。例如,内部 API 报告高错误率,使用该 API 的其他服务也出现大量错误。应用日志中的错误信息可能如下:
Failed to connect to api.smith.lab port 8080: Connection refused
这表明用户在尝试连接 API 服务器时收到了“连接被拒绝”的错误。已知 Docker 容器正在运行,否则会收到容器停止的警报。为了解决这个问题,我们可以使用以下几个命令来识别网络或配置相关的问题。
常用命令排查
-
curl 命令
:当需要检查 Web 服务器是否响应请求,或者只想获取一些数据或文件时,可以使用
curl命令。为了验证端点是否对所有用户都不可用,而不仅仅是其他主机的路由问题,可以使用以下命令:
$ curl http://api.smith.lab:8080
如果输出显示“连接被拒绝”的错误,通常意味着主机未在该端口监听,或者防火墙正在拒绝数据包。
curl: (7) Failed to connect to api.smith.lab port 8080: Connection refused
-
ss 命令
:
ss(套接字统计)命令用于转储主机上的套接字信息。为了查看主机上是否有应用程序在端口 8080 上监听请求,可以使用以下命令:
$ sudo ss -l -n -p | grep 8080
输出示例:
... 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=1448197,fd=4))
其中,
-l
标志显示主机上所有监听的套接字,
-n
标志指示
ss
不解析服务名称,
-p
标志显示使用该套接字的进程。需要注意的是,使用
ss
确定套接字所属进程时,需要
sudo
或提升权限。此输出表明
docker-proxy
进程正在所有接口上监听端口 8080。
在
ss
之前,有一个名为
netstat
的工具,两者功能基本相同,但按照现代标准,
netstat
已被视为过时工具。尽管仍能在一些教程和博客文章中看到使用
netstat
的情况,但建议今后使用
ss
。
-
tcpdump 命令
:
tcpdump命令可以验证主机上的网络流量,它有许多选项,可以捕获一个或所有接口上的流量,甚至可以将网络捕获结果写入文件以便后续分析。它不仅适用于排查网络问题,还可用于安全审计。为了捕获发往api.smith.lab主机端口 8080 的网络流量,可以使用以下命令:
$ sudo tcpdump -ni any tcp port 8080
输出示例:
IP 192.168.50.26.50563 > 192.168.50.4.8080: Flags [S], seq 3446688967, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 157893401 ecr 0,sackOK,eol], length 0
IP 192.168.50.4.8080 > 192.168.50.26.50563: Flags [R.], seq 0, ack 3446688968, win 0, length 0
IP 192.168.50.26.50563 > 192.168.50.4.8080: Flags [S], seq 3446688967, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 157893501 ecr 0,sackOK,eol], length 0
IP 192.168.50.4.8080 > 192.168.50.26.50563: Flags [R.], seq 0, ack 1, win 0, length 0
其中,
-n
标志确保不尝试解析任何主机或端口名称,
-i
标志指定要监听的网络接口,
any
表示监听所有接口。最后一个参数
tcp port 8080
表示只捕获包含端口 8080 的 TCP 数据包。
从输出可以看出,客户端发送同步(S)数据包尝试建立连接,而服务器返回重置(R)数据包,这表明连接不正常。正常的 TCP 连接是通过三次握手建立的,即客户端发送 SYN 数据包,服务器返回 SYN - ACK 数据包,客户端再发送 ACK 数据包。
graph LR
A[客户端 192.168.50.26] -->|SYN| B[服务器 192.168.50.4]
B -->|SYN - ACK| A
A -->|ACK| B
虽然通过
tcpdump
验证了连接已到达服务器,但仍不清楚被拒绝的原因。
下一步排查方向
目前已知服务正在端口 8080 上监听(通过
ss
命令验证),并且流量已到达服务器(通过
tcpdump
捕获验证)。接下来需要检查 Docker 容器和应用程序配置。可能是
docker - proxy
存在问题,未能将流量转发到运行 API 的容器;也可能是容器启动时内部端口映射配置错误。可以通过查看 Docker 的系统日志以查找代理错误,或者运行以下命令检查端口映射:
-
docker ps <container id>
-
docker inspect <container_id>
日志搜索与分析
在几乎所有的故障排查场景中,都需要检查日志。系统和应用程序日志包含了大量可以从命令行查看的信息。现代 Linux 发行版使用
systemd
,它有一个名为
journal
的日志收集机制,可以从多个源(如
syslog
、
auth.log
和
kern.log
)收集日志事件,这使得可以在单个流中查看和搜索日志。
常见日志文件
大多数 Linux 主机上的系统和应用程序日志存储在
/var/log
目录中。以下是一些常见的日志文件及其用途:
| 日志文件 | 用途 | 示例 |
| ---- | ---- | ---- |
|
/var/log/syslog
| 包含 Linux 操作系统的一般全局系统消息 |
Jun 11 00:00:03 box systemd[1]: Finished Rotate log files.
|
|
/var/log/auth.log
| 包含授权和认证事件的信息,可用于调查用户登录、暴力攻击或跟踪用户的
sudo
命令 |
Jan 15 20:57:35 box sshd[27162]: Invalid user aiden from 192.168.1.133 port 59876
|
|
/var/log/kern.log
| 可用于查找 Linux 内核消息,如硬件问题或与 Linux 内核相关的一般信息 |
Jan 16 19:18:47 box kernel: [2397.472979] Out of memory: Killed process 20371 (nginx) total-vm:571408kB, anon-rss:524540kB, file-rss:456kB, shmem-rss:8kB, UID:0 pgtables:1100kB oom_score_adj:1000
|
|
/var/log/dmesg
| 包含自上次启动以来主机的启动消息,可用于多种故障排查场景,如端口耗尽、硬件故障和内存不足 |
[1.036655] kernel: e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21 - k8 - NAPI
|
journalctl
常用命令
在使用
systemd
的主机上,所有这些常见日志都存储在一个名为
journal
的单个二进制流中,可以使用
journalctl
命令行应用程序访问。以下是一些常见的
journalctl
命令:
-
按最新行优先查看所有日志
:
$ sudo journalctl -r
- 查看特定时间段内的日志 :
$ sudo journalctl -r --since "2 hours ago"
- 按系统服务名称过滤日志 :
$ sudo journalctl -r -u ssh
- 按日志级别显示日志 :
$ sudo journalctl -r -u ssh -p err
- 使用正则表达式匹配特定消息 :
$ sudo journalctl -r -u ssh -g "session opened"
如果使用的是较旧版本的
journald
,可能不包含
grep
模式匹配功能,此时可以使用以下命令将搜索结果通过管道传递给
grep
命令:
sudo journalctl -r -u ssh | grep "session opened"
通过合理使用这些日志和命令,可以更高效地排查网络连接和服务故障。后续我们还会介绍如何使用
grep
和
awk
命令进一步解析日志。
网络连接拒绝与日志排查全解析
日志解析工具
在故障排查过程中,解析日志是一项关键技能。除了
journalctl
之外,
grep
和
awk
也是非常实用的日志解析工具。
grep 命令
grep
命令用于在文本或文件中快速搜索特定模式。以下是一些常见的使用场景及操作步骤:
-
搜索特定 IP 地址
:要在
/var/log/syslog中查找所有包含10.0.2.33的日志行,可以使用以下命令:
$ grep "10.0.2.33" /var/log/syslog
示例输出:
... box postfix/smtpd[6520]: connect from unknown[10.0.2.33]
... box postfix/smtpd[6520]: disconnect from unknown[10.0.2.33] ehlo=1 auth=0/1 quit=1 commands=2/3
-
查找无权限执行 sudo 命令的用户
:在
/var/log/auth.log中搜索尝试执行sudo命令但没有权限的用户,可以使用以下命令:
$ grep "user NOT in sudoers" /var/log/auth.log
示例输出:
Jan 31 17:37:40 box sudo: akira : user NOT in sudoers ; TTY=pts/0 ; PWD=/home/akira ; USER=root ; COMMAND=/usr/bin/cat /etc/passwd
-
获取匹配行前后的额外日志行
:使用
-A标志可以获取匹配行之后的指定数量的日志行,-B标志可以获取匹配行之前的指定数量的日志行,-C标志可以同时获取匹配行前后的指定数量的日志行。例如,要获取用户akira无权限执行sudo命令的日志行之前的 5 行日志,可以使用以下命令:
$ grep -B 5 "user NOT in sudoers" /var/log/auth.log
示例输出:
Jan 31 17:37:35 box sshd[64646]: pam_unix(sshd:session): session opened for user akira by (uid=0)
Jan 31 17:37:35 box systemd-logind[632]: New session 169 of user akira.
Jan 31 17:37:35 box systemd: pam_unix(systemd-user:session): session opened for user akira by (uid=0)
Jan 31 17:37:38 box sudo: pam_unix(sudo:auth): Couldn't open /etc/securetty: No such file or directory
Jan 31 17:37:40 box sudo: pam_unix(sudo:auth): Couldn't open /etc/securetty: No such file or directory
Jan 31 17:37:40 box sudo: akira : user NOT in sudoers ; TTY=pts/0 ; PWD=/home/akira ; USER=root ; COMMAND=/usr/bin/cat /etc/passwd
awk 命令
awk
命令不仅可以像
grep
一样搜索特定模式,还可以从任何列中过滤信息。以下是一些常见的使用场景及操作步骤:
-
提取特定列信息
:要从
/var/log/nginx/access.log中提取所有请求的源 IP 地址(通常是日志行的第一列),可以使用以下命令:
$ sudo awk '{print $1}' /var/log/nginx/access.log
示例输出:
127.0.0.1
192.168.1.44
如果要提取日志中的日期时间戳(通常是第四列),可以使用以下命令:
$ sudo awk '{print $4}' /var/log/nginx/access.log
如果要同时提取多个列的信息,可以使用逗号分隔列号,例如:
$ sudo awk '{print $1,$4}' /var/log/nginx/access.log
-
根据特定列的内容过滤日志
:要在
/var/log/nginx/access.log中搜索所有返回 HTTP 500 响应代码的请求(通常在第九列),可以使用以下命令:
$ sudo awk '($9 ~ /500/)' /var/log/nginx/access.log
示例输出:
10.0.2.15 - - [15/Feb/2022:19:41:46 +0000] "GET / HTTP/1.1" 500 396 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"
总结
在网络服务故障排查过程中,我们可以按照以下流程进行操作:
graph LR
A[发现连接拒绝错误] --> B[使用 curl 验证服务响应]
B --> C{连接是否被拒绝}
C -- 是 --> D[使用 ss 检查端口监听情况]
C -- 否 --> E[排查其他问题]
D --> F[使用 tcpdump 捕获网络流量]
F --> G{流量是否到达服务器}
G -- 是 --> H[检查 Docker 容器和应用配置]
G -- 否 --> I[排查网络路由问题]
H --> J[查看 Docker 系统日志和端口映射]
J --> K[使用日志搜索和解析工具排查问题]
K --> L[使用 journalctl 搜索日志]
K --> M[使用 grep 解析日志]
K --> N[使用 awk 解析日志]
通过使用
curl
、
ss
、
tcpdump
等命令可以初步定位网络连接问题,而查看 Docker 容器和应用程序配置可以进一步排查可能的故障点。同时,合理利用
journalctl
、
grep
和
awk
等日志搜索和解析工具,可以更高效地从系统和应用程序日志中获取有用信息,从而快速解决网络连接和服务故障。
总之,掌握这些工具和方法可以帮助我们在面对复杂的网络和服务故障时,有条不紊地进行排查和解决,确保系统的稳定运行。
超级会员免费看
559

被折叠的 条评论
为什么被折叠?



