Squid Web Cache Wiki

Squid Web Cache 文档

🔗 向 Squid 团队发送 Bug 报告

Squid 的 Bug 报告应在我们的Bug 数据库中注册。

任何 Bug 报告必须包括

请注意

🔗 崩溃和核心转储

在两种情况下,Squid 会异常退出并生成核心转储。首先,SIGSEGV 或 SIGBUS 信号会导致 Squid 退出并转储核心。其次,许多函数包含一致性检查。如果其中一个检查失败,Squid 会调用 abort() 生成核心转储。

如果您有核心转储文件,请使用 gdb 通过 `backtrace full` 命令(如果支持)或 `backtrace` 命令(始终支持,但信息较少)从核心中提取堆栈跟踪。

% gdb /usr/local/squid/sbin/squid core
gdb> backtrace full

许多人报告 Squid 没有留下核心转储。这可能是由于以下原因之一:

🔗 资源限制

这些限制通常可以在 shell 脚本中更改。更改资源限制的命令通常是 `ulimit` 或 `limits`。有时它是一个 shell 内置函数,有时它是一个常规程序。另请注意,您可以在 FreeBSD 和其他系统上的 `/etc/login.conf` 文件中设置资源限制。

要更改 coredumpsize 限制,您可以使用类似以下的命令:

limits coredump unlimited

如果 Squid 二进制文件由 RHEL6/CentOS6 init 脚本启动,您可能需要在 init 脚本或脚本的配置文件(通常是 /etc/sysconfig/squid)中设置变量 `DAEMON_COREFILE_LIMIT="unlimited"`。

对于 systemd units,等效选项是 `LimitCORE=infinity`。

🔗 调试符号

要查看您的 Squid 二进制文件是否具有调试符号,请使用此命令:

% nm /usr/local/squid/bin/squid | head

如果看到类似这样的乱码,则二进制文件具有调试符号:

0812abec B AS_tree_head
080a7540 D AclMatchedName
080a73fc D ActionTable
080908a4 r B_BYTES_STR
080908bc r B_GBYTES_STR
080908ac r B_KBYTES_STR
080908b4 r B_MBYTES_STR
080a7550 D Biggest_FD
08097c0c R CacheDigestHashFuncCount
08098f00 r CcAttrs

如果看到这个,则没有调试符号:

/usr/local/squid/bin/squid: no symbols

调试符号可能已被您的安装程序移除。如果您查看源目录中的 squid 二进制文件,它可能具有调试符号。

🔗 核心转储位置

核心转储文件将在以下位置之一生成:

  1. 如果您设置了 `coredump_dir` 选项,则在 `coredump_dir` 目录中。
  2. 如果您使用了 `cache_effective_user` 选项,则在第一个 `cache_dir` 目录中。
  3. Squid 启动时的当前目录。

较新版本的 Squid 会在 `cache.log` 中报告启动时的当前目录。

2000/03/14 00:12:36| Set Current Directory to /usr/local/squid/cache

如果找不到核心文件,则可能是 Squid 没有权限在其当前目录中写入,或者您的 shell 限制阻止了核心文件的写入。

通常,如果您像这样从命令行运行 Squid(csh shell 及其克隆),您会得到一个核心转储:

% limit core un
% /usr/local/squid/bin/squid -NCd1

找到核心转储文件后,使用 `dbx` 或 `gdb` 等调试器生成堆栈跟踪。

% gdb /usr/local/squid/sbin/squid core
gdb> backtrace full

如果可能,请将核心转储文件保留一两天。如果我们要求您发送额外的调试器输出(例如某些变量的内容),那通常很有帮助。但请注意,核心文件只有与生成该核心文件的确切二进制文件配对时才有用。如果您重新编译 Squid,那么以前版本的任何核心转储都将无用,除非您已保存相应的 Squid 二进制文件,并且任何分析此类核心转储的尝试很可能提供关于崩溃原因的误导性信息。

在某些环境中,核心转储由专门的实用程序处理以进行管理。例如,在 RHEL6/CentOS6 环境中,可能是 `abrtd` 和 `abrt-addon-ccpp`(man abrtd,man abrt-install-ccpp-hook)。在 systemd 环境中,它是 `systemd-coredump`(man systemd-coredump)。您可以通过读取 `/proc/sys/kernel/core_pattern`(man core)来检查。

# cat /proc/sys/kernel/core_pattern
|/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e

systemd-coredump 的 core_pattern:

# cat /proc/sys/kernel/core_pattern
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %e

因此,您应该熟悉用于控制核心转储生成和位置的处理程序。或者,如果服务器专用于 Squid,您可以禁用该处理程序并使用常规方法处理核心转储。例如,您可以使用以下方法禁用上述处理程序:

# chkconfig abrt-ccpp off
# service abrt-ccpp stop
# cat /proc/sys/kernel/core_pattern
core

禁用 systemd-coredump:

# echo kernel.core_pattern=core > /etc/sysctl.d/50-coredump.conf
# /usr/lib/systemd/systemd-sysctl --prefix kernel.core_pattern
# cat /proc/sys/kernel/core_pattern
core

🔗 在 Squid 上使用 gdb 调试器

如果您无法让 Squid 为您留下核心文件,则可以使用以下方法之一:

第一个替代方案是在 GDB 的控制下启动 Squid。

% gdb /path/to/squid
handle SIGPIPE pass nostop noprint
handle SIGTERM pass nostop noprint
handle SIGUSR1 pass nostop noprint
handle SIGHUP  pass
handle SIGKILL pass
handle SIGSEGV stop
handle SIGABRT stop
run -NYCX
[wait for crash]
backtrace full
quit

🔗 在实时代理上使用 gdb 调试器(停机时间最少)

上述方法的缺点是它不适用于生产系统,因为如果 Squid 崩溃,它将不会自动重新启动。好消息是,完全有可能自动化上述过程以自动获取堆栈跟踪然后重新启动 Squid。这是一个应该有效的简短自动化脚本:

trap "rm -f $$.gdb" 0
cat <<EOF >$$.gdb
handle SIGPIPE pass nostop noprint
handle SIGTERM pass nostop noprint
handle SIGUSR1 pass nostop noprint
handle SIGHUP  pass
handle SIGKILL pass
handle SIGSEGV stop
handle SIGABRT stop
run -NYCd3
backtrace full
quit
EOF
while sleep 2; do
    gdb -x $$.gdb /path/to/squid 2>&1 | tee -a squid.out
done

如果上述方法不可行,则有其他选项:

  1. 使用 --enable-stacktraces 选项构建 Squid,如果您的操作系统支持(Linux glibc on Intel 和 Solaris 存在一些额外的库,这些库似乎如今很难找到……)
  2. 使用 “catchsegv” 工具运行 Squid。(Linux glibc Intel)

:information_source: 这些方法提供的详细信息远不如使用 gdb。

🔗 将 gdb 调试器附加到已运行的 Squid

首先找到您要调试的特定 Squid 工作进程的 PID。

% gdb /path/to/squid
handle SIGPIPE pass nostop noprint
handle SIGTERM pass nostop noprint
handle SIGUSR1 pass nostop noprint
handle SIGHUP  pass
handle SIGKILL pass
handle SIGSEGV stop
handle SIGABRT stop

attach [worker PID]
[wait for crash]
backtrace full
detach
quit

🔗 在不停机的情况下获取实时代理的当前堆栈

如果您怀疑 Squid 卡在繁忙循环中,或者您想知道 Squid “现在”正在做什么,但又不想干扰 Squid 进程,以下技巧可能会有所帮助。

  1. 使用 gdb 转储当前堆栈:
         sudo gdb -n -batch -ex 'backtrace full' -pid <PID>
    

    您可能不需要/不想使用 `-n`(即,不加载 gdb 初始化文件)选项。

  2. 使用 pstack(1) 转储当前堆栈:
         sudo pstack <PID>
    
  3. 快速检查 Squid 是否正在等待系统调用:
         sudo cat /proc/<PID>/stack
    

    此方法不显示导致系统调用的 Squid 函数。

在上述命令中,`` 代表您要调试的 Squid 进程的进程 ID。它通常是一个工作进程,但也可以是另一个子进程,甚至是主进程。

🔗 调试 Squid

如果您认为您发现了非致命 Bug(例如不正确的 HTTP 处理),请向我们发送一段具有调试信息的 cache.log,以演示问题。cache.log 文件会变得非常大,因此,您也可以将其复制到 FTP 或 HTTP 服务器上供我们下载。

一旦您将调试信息捕获到 `cache.log` 中,请自行查看,看看您是否能理解您看到的行为。如果不能,请随时将您的调试输出发送到 `squid-users` 或 `squid-bugs` 邮件列表。

🔗 调试单个事务

不幸的是,目前还无法调试单个事务,但以下过程可以最大限度地减少日志噪音,并可能帮助开发人员查明问题:

  1. 找到您的 Squid 日志文件或等效文件。在此示例中,我们称之为 `cache.log`。
  2. 启用详细(级别 7)或完整(级别 9)调试。有关详细信息,请参见下面的部分。
  3. 如果需要,请启动 Squid。
  4. 运行 “tail -f cache.log > partial-cache.log”。这将开始将新的调试信息追加到 `partial-cache.log` 文件中。
  5. 重现失败的事务,如果可能,使用单个请求。请注意,重新加载浏览器中的页面通常会向 Squid 发送数十甚至数百个请求。理想情况下,请尽可能使用 squidclient、wget、curl 或其他“单请求”工具。
  6. 停止上述 “tail” 命令。
  7. 共享生成的 partial-cache.log,如果需要,请进行压缩。请注意,其中可能包含敏感信息,如密码。

🔗 详细调试输出

很容易为正在运行的 Squid 进程获取 7 级调试信息:

squid -k debug

上述命令向正在运行的 Squid 版本发送一个信号,该信号导致源代码中的许多(但不是所有)debug() 语句写入 `cache.log` 文件或等效文件。重复相同的命令可将调试级别恢复到以前的状态。

要调试在 “squid -k debug” 开始工作之前发生的情况,请参阅下面讨论的 **-X** 命令行选项。

🔗 完全调试输出

要启用完全或 9 级调试(即,强制 Squid 中的每个调试语句在到达时都发出一些输出),您有两个选择:

  1. 将 squid.conf 中的 `debug_options` 设置为 ALL,9。这样做将调试配置文件解析之后发生的情况。这足以对大多数运行时问题进行分类。
  2. 使用 **-X** 命令行选项启动 Squid。这样做将调试配置文件中 `debug_options` 解析之前和之后发生的情况。

当使用 -X(或 -d)命令行选项启动时,在 Squid 打开 cache.log 或开始将调试发送到日志守护进程之前,Squid 会将调试行写入标准错误流(stderr)。当不使用这些命令行选项启动时,直到 Squid 解析配置文件并开始遵守其中配置的设置之前,很少或根本不会产生调试信息。

不幸的是,无法为正在运行的 Squid 进程启用完全调试,但上面讨论的 “squid -k debug” 将启用 7 级调试。

🔗 调试部分

要启用选择性调试(例如,仅针对一个源文件),您需要编辑 **squid.conf** 并将其添加到 **debug_options** 行。每个 Squid 源文件都被分配了一个调试 **section**。调试 section 的分配可以通过查看单个源文件的顶部、阅读 `debug-sections.txt` 文件或查看 KnowledgeBase/DebugSections 来找到。

🔗 调试级别

您还可以指定调试 *级别* 来控制调试量。级别越高,产生的调试消息越多。例如,要启用访问控制功能的完全调试,您将使用:

debug_options 28,9

然后您必须重新启动或重新配置 Squid。

🔗 捕获数据包

有时,在检查了核心转储跟踪和调试输出后,开发人员可能会要求您在 Squid 的两侧(Squid 到源站和 Squid 到客户端)收集数据包。您可以使用强大的工具 **tcpdump** 来完成此操作。下面介绍了一些常见的示例和方法。

🔗 在拦截代理上收集数据包

在标准/常见配置中,拦截代理有两个网络接口。一个面向 Internet,另一个面向本地网络。因此,要捕获 Squid 到源站的事务,您必须将 tcpdump 连接到 WAN 接口,相应地将 tcpdump 连接到 LAN 接口以捕获 Squid 到客户端的事务。您必须属于 tcpdump 组或作为 root 用户才能在网络接口上捕获流量。

语法

tcpdump -s 0 -i $nic -w /path/to/dump.pcap port $port and host $origin_ip [and host $client_ip]

其中 **$nic** 是 WAN 或 LAN 网络接口,**$port** 是拦截的端口,**$origin_ip** 是源服务器 IP,**$client_ip** 是本地网络中的客户端 IP。'and host $client_ip' 部分仅适用于 NAT 代理上的 Squid 到客户端的事务。TProxy 拦截代理可以将此部分用于两种事务类型。参数 **-s 0** 要求 tcpdump 保存完整的数据包,**-w** 指定转储位置。

例如,在 NAT 代理上捕获 Squid 到源站的事务:

tcpdump -s 0 -i eth1 -w /tmp/squid-to-example.com.pcap port 80 and host 10.11.12.13

在 TProxy 代理上捕获 Squid 到源站的事务:

tcpdump -s 0 -i eth1 -w /tmp/squid-to-example.com.pcap port 80 and host 10.11.12.13 and host 172.16.1.100

捕获 Squid 到客户端的事务:

tcpdump -s 0 -i eth0 -w /tmp/squid-to-client100.pcap port 80 and host 10.11.12.13 and host 192.168.1.100

要限制收集的数据量,在启动两个 tcpdump 实例后,立即发起有问题 HTTP 请求。获得所需结果后,立即停止两个 tcpdump 实例。

🔗 在显式代理上收集数据包

方法的主要区别在于,Squid 到客户端的通信是 Squid 的 IP/代理端口与客户端 IP 之间的显式通信。因此,语法是:

tcpdump -s 0 -i $nic -w /path/to/dump.pcap port $proxy_port and host $proxy_ip and host $client_ip

其中 **$proxy_port** 和 **$proxy_ip** 是用户代理(例如浏览器)访问 Squid 时使用的值。例如:

tcpdump -s 0 -i eth0 -w /tmp/squid-to-client100.pcap port 3128 and host 192.168.1.1 and host 192.168.1.100

请注意,捕获将包括来自客户端到代理服务器的所有流量。因此,在捕获流量时,请尝试限制客户端上活动的 HTTP 会话数量。

🔗 收集导致 Squid 崩溃的数据包

有时 Squid 可能由于处理来自已知目标的数据包而崩溃,因此我们需要捕获问题流量进行分析。为此,您可以选择长时间捕获流量,直到遇到崩溃。由于数据包转储在此操作中可能很容易变得非常大,因此最好启用转储文件轮换。例如:

tcpdump -s 0 -i eth0 -G 300 -w /tmp/squid-to-client100-%Y-%m-%d_%H:%M:%S.pcap port 3128 and host 192.168.1.1 and host 192.168.1.100

其中 **-G** 指定轮换间隔(秒),以及像 `%Y-%m-%d_%H:%M:%S` 这样的灵活字符串,用于在文件名中显示轮换发生的时间(man strftime)。

在上面的示例中,tcpdump 将每 5 分钟轮换一次转储文件。一旦您发现 Squid 崩溃并获得了故障的确切时间,您就可以轻松找到数据包转储中感兴趣的 5 分钟部分。转储的目标目录应该足够大,以适应连续捕获。如果 tcpdump 将其权限降级为普通用户(通常是 tcpdump),该用户应具有目标目录的写入访问权限。

如果您有大小限制的捕获存储,您可以使用 tcpdump 的轮换缓冲区选项。它允许保留固定的存储空间用于捕获。例如:

tcpdump -s 0 -i eth1 -w /tmp/squid-to-example.com.pcap -W 10 -C 100 port 80 and host 10.11.12.13

其中 **-W** 指定最大转储文件数,**-C** 指定每个转储文件的最大大小(MB)。

在上面的示例中,tcpdump 将在达到 100MB 时轮换转储文件并附加后缀到文件名。当达到配置的最大文件数时,它将覆盖最旧的转储文件。在此配置中,最大捕获存储大小将为 1GB。此方法的缺点是,您必须定期监控 Squid 的活动,并在检测到断言时尽快停止捕获。否则,感兴趣的文件转储将被覆盖。

回到 FAQ 索引

导航: 网站搜索网站页面分类🔼 向上