文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Squid中文权威指南(第13-16章)

Squid中文权威指南(第13-16章)

时间:2009-04-06  来源:viking550229962

第13章 日志文件

13.1 cache.log

cache.log包含多种消息,例如Squid的配置信息、性能警告、以及严重错误。如下是cache.log的输出样本:

2003/09/29 12:09:45| Starting Squid Cache version 2.5.STABLE4 for i386-
   
unknown-freebsd4.8...
  
2003/09/29 12:09:45| Process ID 18990
  
2003/09/29 12:09:45| With 1064 file descriptors available
  
2003/09/29 12:09:45| Performing DNS Tests...
  
2003/09/29 12:09:45| Successful DNS name lookup tests...
  
2003/09/29 12:09:45| DNS Socket created at 0.0.0.0, port 1154, FD 5
  
2003/09/29 12:09:45| Adding nameserver 24.221.192.5 from /etc/resolv.conf
  
2003/09/29 12:09:45| Adding nameserver 24.221.208.5 from /etc/resolv.conf
  
2003/09/29 12:09:45| helperOpenServers: Starting 5 'redirector.pl' processes
  
2003/09/29 12:09:45| Unlinkd pipe opened on FD 15
  
2003/09/29 12:09:45| Swap maxSize 10240 KB, estimated 787 objects
  
2003/09/29 12:09:45| Target number of buckets: 39
  
2003/09/29 12:09:45| Using 8192 Store buckets
  
2003/09/29 12:09:45| Max Mem  size: 8192 KB
  
2003/09/29 12:09:45| Max Swap size: 10240 KB
  
2003/09/29 12:09:45| Rebuilding storage in /usr/local/squid/var/cache (CLEAN)
  
2003/09/29 12:09:45| Using Least Load store dir selection
  
2003/09/29 12:09:45| Set Current Directory to /usr/local/squid/var/cache
  
2003/09/29 12:09:45| Loaded Icons.
  
2003/09/29 12:09:45| Accepting HTTP connections at 0.0.0.0, port 3128, FD 16.
  
2003/09/29 12:09:45| Accepting ICP messages at 0.0.0.0, port 3130, FD 17.
  
2003/09/29 12:09:45| WCCP Disabled.
  
2003/09/29 12:09:45| Ready to serve requests.

每个cache.log条目以时间戳开始,指示消息何时产生。本示例里的日志报告了squid的版本(2.5.STABLE4),以及squid所运行的操作系统标识符(i386-unknown-freebsd4.8)。接下来是进程ID(18990)。许多cache.log条目看起来含义不明(例如 Target number of buckets: 39)。大多数正常情形下,可以忽略这些不易理解的条目。另一方面,你也许该仔细看一下本质的配置细节,例如名字服务器的地址,或HTTP服务器地址。本示例日志最后陈述了Squid准备接受请求。此时Squid可以接受来自客户端的HTTP连接。

通常,cache.log增长缓慢。然而,不正常的HTTP事务或类似的事件可以导致squid发布一个debug消息。假如这样的事件经常发生(例如DOS攻击、新的病毒、磁盘意外等),日志文件会增长很快。定期轮转日志减少了用光磁盘的风险。

主要的错误和异常条件最可能报告在cache.log里。我推荐存档这些日志,以便以后回查事件的源头。当在Squid的邮件列表或类似论坛描述这些故障时,相应的cache.log非常有用。某些情形下,你也许应该调大日志的debug级别,以便其他人能更好的理解和修正你的问题。

13.1.1 debug级别

debug_options指令控制cache.log的日志级别。默认值(ALL,1)通常是最佳选择。在更高级别上,不重要的消息会混淆视线。请参考16.2节关于debug_options指令的完整描述。

请注意最高级别的debug(9或10)会对每个请求产生数千行日志,快速消耗磁盘空间和显著影响squid的性能。

可以使用squid的-X命令行选项来对所有情形激活完整的debug。假如squid拒绝启动,并且squid.conf里的debug级别不足以诊断问题时,该模式特别有用。这也是在配置文件解析器解析到debug_options指令之前,激活它的完整debug的好方法。在squid运行正常时,请勿使用-X。

对运行的squid进程,可使用squid的-k debug命令行选项来立刻激活完整debug。这个命令是循环使用的:第一次调用打开完整debug,第二次调用则关闭它。请见第5章关于-k选项的通用讨论。

如前所述,完整debug会产生难以控制的日志增长。这会使squid和操作系统运行缓慢。在极端情形下,你会发现终端session在运行第一个 squid -k debug命令后,变得没有响应。在squid狂写日志的同时让操作无法进行,这情形并不好。如下技巧也许有用,它获取5秒钟的debug数据快照:

% squid -k debug; sleep 5; squid -k debug

13.1.2 转发cache.log消息到系统日志

为了让squid发送cache.log消息的拷贝到系统日志,请使用-s命令行选项。仅仅在debug级别0和1的消息会被转发。级别0的消息以 syslog级别LOG_WARNING记录,级别1的消息以syslog级别LOG_NOTICE记录。所有消息使用LOCAL4的syslog设备。如下是配置syslogd的一个方法,以便这些消息能保存下来:

local4.warning                           /var/log/squid.log

在维护多个squid主机时,使用syslog来记录cache.log特别方便。可以配置每个本地syslog进程,转发这些消息到中央日志主机,这样就可在一个地方统一浏览所有cache日志。例如,可在/etc/syslogd.conf里使用如下接口:

local4.notice                            @192.168.45.1

13.1.3 dump cache.log消息到终端

-d level命令行选项指示squid去dump cache.log消息到终端(例如stderr)。level参数指明dump出的消息的最大级别。注意你只会见到出现在cache.log里的消息,它遵循于debug_options设置。例如,假如设置了debug_options ALL,1,然后运行squid -d2,你不会见到级别2的debug消息。

-d level和-N选项在debug squid问题或快速测试配置文件的改变时,特别有用。它们允许你容易启动squid和观察cache.log消息。在squid从crontab或类似的设备启动时,该选项也有用,crontab会捕获squid的标准错误并将其报告回用户。例如,可能有如下crontab,它自动重配运行中的 squid进程:

15 */4 * * * /usr/local/squid/sbin/squid -d1 -k reconfigure

13.2 access.log

Squid把关于HTTP事务的关键信息存放在access.log里。该文件是基于行的,也就是说每行对应一个客户端请求。squid记录客户端IP(或主机名)、请求URL、响应size、和其他信息。

Squid 在access.log里记录所有HTTP访问,除了那些在还没有发送数据前就断开的连接。Squid也记录所有的ICP(非HTCP)事务,除非你使用 log_icp_queries指令关闭了这个功能。第13.2.4节描述了其他影响access日志的squid.conf指令。

默认的access.log格式包含了10个域。如下是日志样本,长行分割并且缩进排版:

1066037222.011  126389 9.121.105.207 TCP_MISS/503 1055

        GET http://home.gigigaga.com/n8342133/Miho.DAT.019 -

        DIRECT/203.187.1.180 -

1066037222.011   19120 12.83.179.11 TCP_MISS/200 359

        GET http://ads.x10.com/720x300/Z2FtZ3JlZXRpbmcxLmRhd/7/AMG -

        DIRECT/63.211.210.20 text/html

1066037222.011   34173 166.181.33.71 TCP_MISS/200 559

        GET http://coursesites.blackboard.com:8081/service/collab/./1010706448190/ -

        DIRECT/216.200.107.101 application/octet-stream

1066037222.011   19287 41.51.105.27 TCP_REFRESH_MISS/200 500

        GET http://fn.yam.com/include/tsemark/show.js -

        DIRECT/210.59.224.59 application/x-javascript

1066037222.011   19395 41.51.105.27 TCP_MISS/304 274

        GET http://fnasp.yam.com/image/coin3.gif -

        DIRECT/211.72.254.133 -

1066037222.011   19074 30.208.85.76 TCP_CLIENT_REFRESH_MISS/304 197

        GET http://ads.icq.com/content/B0/0/..bC6GygEYNeHGjBUin5Azfe68m5hD1jLk$/aol -

        DIRECT/64.12.184.121 -

1066037222.011   19048 12.83.179.11 TCP_MISS/200 261

        GET http://ads.adsag.com/js.ng/...ne&cat=friendship&subcat=girltalk -

        DIRECT/209.225.54.119 application/x-javascript

1066037222.118     106 41.51.105.27 TCP_HIT/200 536

        GET http://rcm-images.amazon.com/./images/G/01/rcm/privacy.gif -

        NONE/- image/gif

1066037222.352   19475 27.34.49.248 TCP_MISS/200 12387

        GET http://espanol.geocities.com/lebastias/divulgacion/budismo-tarot.html -

        DIRECT/209.1.225.139 text/html

1066037222.352     132 144.157.100.17 TCP_MISS/504 1293

        GET http://ar.atwola.com/image/93101912/aol -

        NONE/- -

如下是对每个域的详细解释:

1.时间戳

请求完成时间,以Unix纪元(UTC 1970-01-01 00:00:00)以来的秒数表示,它是毫秒级的。squid使用这种格式而不是人工可读的时间格式,是为了简化某些日志处理程序的工作。

可以使用一个简单的perl命令来转化Unix时间戳到本地时间,例如:

perl -pe 's/^\d+\.\d+/localtime($&)/e;' access.log

2.响应时间

对HTTP事务来说,该域表明squid花了多少时间来处理请求。在squid接受到HTTP请求时开始计时,在响应完全送出后计时终止。响应时间是毫秒级的。

对ICP查询来说,响应时间通常是0。这是因为squid回答ICP查询非常迅速。甚至,squid在接受到ICP查询和发送完响应之间,不会更新进程时钟。

尽管时间值是毫秒级的,但是精度可能是10毫秒。在squid负载繁重时,计时变得没那么精确。

3.客户端地址

该域包含客户端的IP地址,或者是主机名--假如激活了log_fqdn。出于安全或隐私的理由,你可能需要使用client_netmask指令来掩盖客户端地址的一部分。然而,这样让来自同一客户端的组请求变得不可能。

4.结果/状态码

该域包含2个token,以斜杠分隔。第一个token叫结果码,它把协议和事务结果(例如TCP_HIT或UDP_DENIED)进行归类。这些是 squid专有的编码,在13.2.1节里有定义。以TCP_开头的编码指HTTP请求,以UDP_开头的编码指ICP查询。

第2个token是HTTP响应状态码(例如200,304,404等)。状态码通常来自原始服务器。在某些情形下,squid可能有义务自己选择状态码。这些编码在HTTP的RFC里定义,在随后的Table 13-1里有概述。

5.传输size

该域指明传给客户端的字节数。严格的讲,它是squid告诉TCP/IP协议栈去发送给客户端的字节数。这就是说,它不包括TCP/IP头部的 overhead。也请注意,传输size正常来说大于响应的Content-Length。传输size包括了HTTP响应头部,然而Content- Length不包括。

传输size可用于近似的带宽使用分析,但并非精确的HTTP实体size计算。假如需要了解响应的Content-Length,可在store.log里找到它。

6.请求方式

该域包含请求方式。因为squid客户端可能使用ICP或HTTP,请求方式就可能是HTTP-或ICP-这2种。最普通的HTTP请求方式是GET。ICP查询总以ICP_QUERY的形式被记载。请见6.1.2.8节关于squid了解的HTTP方式列表。

7.URI

该域包含来自客户端请求的URI。大多数记录下来的URI实际是URL(例如,它们有主机名)。

Squid对某些失败使用特殊的记录格式。例如Squid不能解析HTTP请求,或者不能决定URI,这时你可能见到类似于"error:invalid-request." 的字串出现在URI的位置。例如:

1066036250.603 310 192.0.34.70 NONE/400 1203 GET error:invalid-request - NONE/- -

另外在该域里,也请留心URI里的空格字符。取决于uri_whitespace设置,squid可能在日志文件里打印URI时带空格字符。若发生这种情况,则阅读access.log文件的日志分析工具可能会遇到麻烦。

在记日志时,squid删掉了在第一个问号(?)之后的所有URI字符,除非禁用了strip_query_terms指令。

8.客户端身份

Squid有2种不同的办法来决定用户的身份。一种是RFC 1413身份协议,另一种来自HTTP验证头部。

Squid 试图基于ident_lookup_access规则进行身份查询,假如有的话。另外,假如使用代理验证(或在代理人模式下的规范服务验证),squid 会在该域放置给定的用户名。假如2者都提供给squid一个用户名,并且你使用了原始access.log格式,那么HTTP验证名字会记录下来,RFC 1413名字会忽略掉。普通日志文件格式会把两者都独立的记录。

9.对端编码/对端主机

对端信息包含了2个token,以斜杠分隔。它仅仅与cache丢失的请求有关。第一个token指示如何选择下一跳,第二个token是下一跳的地址。对端编码列在13.2.3节里。

当 squid发送一个请求到邻居cache时,对端主机地址是邻居的主机名。假如请求是直接送到原始服务器的,则squid会写成原始服务器的IP地址或主机名--假如禁用了log_ip_on_direct。NONE/-这个值指明squid不转发该请求到任何其他服务器。

10.内容类型

原始access.log的默认的最后一个域,是HTTP响应的内容类型。squid从响应的Content-Type头部获取内容类型值。假如该头部丢失了,squid使用一个横杠(-)代替。

假如激活了log_mime_headers指令,squid在每行追加2个附加的域:

11.HTTP请求头部

Squid 编码HTTP请求头部,并且在一对方括号之间打印它们。方括号是必须的,因为squid不编码空格字符。编码方案稍许奇怪。回车(ASCII 13)和换行(ASCII 10)分别打印成\r和\n。其他不可打印的字符以RFC 1738风格来编码,例如Tab(ASCII 9)变成了%09。

12.HTTP响应头部

Squid编码HTTP响应头部,并且在一对方括号之间打印它们。注意这些是发往客户端的头部,可能不同于从原始服务器接受到的头部。

Squid 只有在整个响应发送到客户端完成以后,才写access.log日志。这点允许squid在日志文件里包含请求和响应两者信息。然而,需要花费数分钟甚至数小时才能完成的事务,请求期间的日志在access.log里不可见。当这类型的事务呈现出性能或策略问题时,access.log可能对你没有帮助。代替的,可使用cache管理器来浏览挂起事务的列表(见14章)。

13.2.1 access.log结果编码

相应于HTTP请求,下列标签可能出现在access.log文件的第四个域。

TCP_HIT

Squid发现请求资源的貌似新鲜的拷贝,并将其立即发送到客户端。

TCP_MISS

Squid没有请求资源的cache拷贝。

TCP_REFERSH_HIT

Squid发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。原始服务器返回304(未修改)响应,指示squid的拷贝仍旧是新鲜的。

TCP_REF_FAIL_HIT

Squid发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。然而,原始服务器响应失败,或者返回的响应Squid不能理解。在此情形下,squid发送现有cache拷贝(很可能是陈旧的)到客户端。

TCP_REFRESH_MISS

Squid发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。原始服务器响应新的内容,指示这个cache拷贝确实是陈旧的。

TCP_CLIENT_REFRESH_MISS

Squid发现了请求资源的拷贝,但客户端的请求包含了Cache-Control: no-cache指令。Squid转发客户端的请求到原始服务器,强迫cache确认。

TCP_IMS_HIT

客户端发送确认请求,Squid发现更近来的、貌似新鲜的请求资源的拷贝。Squid发送更新的内容到客户端,而不联系原始服务器。

TCP_SWAPFAIL_MISS

Squid发现请求资源的有效拷贝,但从磁盘装载它失败。这时squid发送请求到原始服务器,就如同这是个cache丢失一样。

TCP_NEGATIVE_HIT

在对原始服务器的请求导致HTTP错误时,Squid也会cache这个响应。在短时间内对这些资源的重复请求,导致了否命中。 negative_ttl指令控制这些错误被cache的时间数量。请注意这些错误只在内存cache,不会写往磁盘。下列HTTP状态码可能导致否定 cache(也遵循于其他约束): 204, 305, 400, 403, 404, 405, 414, 500, 501, 502, 503, 504。

TCP_MEM_HIT

Squid在内存cache里发现请求资源的有效拷贝,并将其立即发送到客户端。注意这点并非精确的呈现了所有从内存服务的响应。例如,某些cache在内存里,但要求确认的响应,会以TCP_REFRESH_HIT, TCP_REFRESH_MISS等形式记录。

TCP_DENIED

因为http_access或http_reply_access规则,客户端的请求被拒绝了。注意被http_access拒绝的请求在第9域的值是NONE/-,然而被http_reply_access拒绝的请求,在相应地方有一个有效值。

TCP_OFFLINE_HIT

当offline_mode激活时,Squid对任何cache响应返回cache命中,而不用考虑它的新鲜程度。

TCP_REDIRECT

重定向程序告诉Squid产生一个HTTP重定向到新的URI(见11.1节)。正常的,Squid不会记录这些重定向。假如要这样做,必须在编译squid前,手工定义LOG_TCP_REDIRECTS预处理指令。

NONE

无分类的结果用于特定错误,例如无效主机名。

相应于ICP查询,下列标签可能出现在access.log文件的第四域。

UDP_HIT

Squid在cache里发现请求资源的貌似新鲜的拷贝。

UDP_MISS

Squid没有在cache里发现请求资源的貌似新鲜的拷贝。假如同一目标通过HTTP请求,就可能是个cache丢失。请对比UDP_MISS_NOFETCH。

UDP_MISS_NOFETCH

跟UDP_MISS类似,不同的是这里也指示了Squid不愿去处理相应的HTTP请求。假如使用了-Y命令行选项,Squid在启动并编译其内存索引时,会返回这个标签而不是UDP_MISS。

UDP_DENIED

因为icp_access规则,ICP查询被拒绝。假如超过95%的到某客户端的ICP响应是UDP_DENIED,并且客户端数据库激活了(见附录A),Squid在1小时内,停止发送任何ICP响应到该客户端。若这点发生,你也可在cache.log里见到一个警告。

UDP_INVALID

Squid接受到无效查询(例如截断的消息、无效协议版本、URI里的空格等)。Squid发送UDP_INVALID响应到客户端。

13.2.2 HTTP响应状态码

Table 13-1列出了数字HTTP响应CODE和理由短句。注意Squid和其他HTTP客户端仅仅关注这些数字值。理由短句是纯解释性的,不会影响响应的意义。对每个状态码,也提供了一个到RFC 2616的具体节的索引。注意状态码0和600是squid使用的非标准的值,不会在RFC里提到。

Table 13-1. HTTP response status codes
Code     Reason phrase     RFC 2616 section
0     No Response Received (Squid-specific)     N/A
1xx     Informational     10.1
100     Continue     10.1.1
101     Switching Protocols     10.1.2
2xx     Successful     10.2
200     OK     10.2.1
201     Created     10.2.2
202     Accepted     10.2.3
203     Non-Authoritative Information     10.2.4
204     No Content     10.2.5
205     Reset Content     10.2.6
206     Partial Content     10.2.7
3xx     Redirection     10.3
300     Multiple Choices     10.3.1
301     Moved Permanently     10.3.2
302     Found     10.3.3
303     See Other     10.3.4
304     Not Modified     10.3.5
305     Use Proxy     10.3.6
306     (Unused)     10.3.7
307     Temporary Redirect     10.3.8
4xx     Client Error     10.4
400     Bad Request     10.4.1
401     Unauthorized     10.4.2
402     Payment Required     10.4.3
403     Forbidden     10.4.4
404     Not Found     10.4.5
405     Method Not Allowed     10.4.6
406     Not Acceptable     10.4.7
407     Proxy Authentication Required     10.4.8
408     Request Timeout     10.4.9
409     Conflict     10.4.10
410     Gone     10.4.11
411     Length Required     10.4.12
412     Precondition Failed     10.4.13
413     Request Entity Too Large     10.4.14
414     Request-URI Too Long     10.4.15
415     Unsupported Media Type     10.4.16
416     Requested Range Not Satisfiable     10.4.17
417     Expectation Failed     10.4.18
5xx     Server Error     10.5
500     Internal Server Error     10.5.1
501     Not Implemented     10.5.2
502     Bad Gateway     10.5.3
503     Service Unavailable     10.5.4
504     Gateway Timeout     10.5.5
505     HTTP Version Not Supported     10.5.6
6xx     Proxy Error     N/A
600     Unparseable Response Headers (Squid-specific)     N/A

假如Squid从原始服务器没有接受到任何响应,你可在access.log里看到状态码0。假如Squid接受到的响应没有包含HTTP头部,就会出现状态码600。在少数情况下,某些原始服务器仅发送响应body,而忽略了任何头部。

13.2.3 access.log对端编码

下列编码可能出现在access.log的第9域。请参考10.10节关于Squid如何对cache丢失情况,选择有效的下一跳。

NONE

这指明Squid对本次请求,不会与任何其他服务器(邻居或原始服务器)通信。它通常与cache命中、拒绝请求、cache管理请求、错误、和所有的ICP查询这些类型联合出现。

DIRECT

Squid直接转发请求到原始服务器。该域的第2半部分显示原始服务器的IP地址,或主机名--假如禁止了log_ip_on_direct。

SIBLING_HIT

在姐妹cache返回ICP或HTCP命中后,Squid发送请求到姐妹cache。

PARENT_HIT

在父cache返回ICP或HTCP命中后,Squid发送请求到父cache。

DEFAULT_PARENT

Squid选择该父cache,因为其在squid.conf的cache_peer行里被标志为default。

FIRST_UP_PARENT

Squid转发请求到该父cache,因为它是位于已知活跃列表里的第一个父cache。

FIRST_PARENT_MISS

Squid转发请求到该父cache,它第一个响应ICP/HTCP丢失消息。换句话说,对这个特殊的ICP/HTCP查询,在这个特殊时刻,被选中的父 cache有最佳的往返时间(RTT)。注意标准RTT可能被人工矫正过,取决于cache_peer指令的weight选项。

CLOSEST_PARENT_MISS

Squid选择该父cache,因为它报告到原始服务器的RTT最低。这点仅在2个cache都激活了netdb,并且原始服务器(或在同一子网内的其他server)返回ICMP ping消息。

CLOSEST_PARENT

这点类似CLOSEST_PARENT_MISS,除了RTT计算不是来自ICP/HTCP响应消息外。代替的,它们来自Squid保留的更老的计算方式,例如netdb交换功能。

CLOSEST_DIRECT

Squid基于netdb算法,转发请求到原始服务器。这点在满足下述任何条件时发生:

    * 1)在Squid和原始服务器之间的RTT小于配置的minimum_direct_rtt值。

    * 2)在Squid和原始服务器之间的标准路由跳数少于配置的minimum_direct_hops值。

    * 3)在ICP/HTCP响应里返回的RTT值,指示Squid离原始服务器近于任何其他邻居。

ROUNDROBIN_PARENT

Squid转发请求到该父cache,因为设置了round-robin选项,并且它有最低的使用计数器。

CD_PARENT_HIT

Squid基于cache摘要算法(见10.7节)转发请求到该父cache。

CD_SIBLING_HIT

Squid基于cache摘要算法转发请求到该姐妹cache。

CARP

Squid选择该父cache,基于cache数组路由协议算法(见10.9节)。

ANY_PARENT

作为最后的手段,Squid选择该父cache,因为没有其他方法能选择可行的下一跳。

注意大部分上述编码可能以TIMEOUT_开头,这表明在等待ICP/HTCP响应时发生超时。例如:

1066038165.382    345 193.233.46.21 TCP_MISS/200 2836

        GET http://www.caida.org/home/./images/home.jpg

        TIMEOUT_CLOSEST_DIRECT/213.219.122.19 image/jpeg

可使用icp_query_timeout指令来调整超时。

13.2.4 影响access.log的配置指令

下列配置文件指令会影响到access.log。
13.2.4.1 log_icp_queries

该指令默认激活,导致squid记录所有的ICP查询。假如运行了一个繁忙的父cache,这点可能让access.log文件变得巨大。为了节省磁盘空间,可禁止该指令:

log_icp_queries off

假如禁止了ICP查询的日志,我建议你监视查询数量--通过cache管理器或SNMP。
13.2.4.2 emulate_httpd_log

access.log文件有2种格式:普通格式和原始格式。普通格式就如同大部分HTTP服务器(如Apache)的日志格式一样。它包含的信息少于 Squid的原始格式。然而,假如运行Squid在代理人模式下(见15章),你可能想要普通日志文件格式。普通格式或许也对你现有的日志文件分析工具有用。使用该指令来激活普通格式:

emulate_httpd_log on

请见http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format 关于该格式的描述。
13.2.4.3 log_mime_hdrs

使用log_mime_hdrs让squid记录HTTP请求和响应的头部:

log_mime_headers on

在激活时,squid追加请求和响应头部到access.log。这会在每行增加2个域。每个域都以方括号引用起来,便于分析。某些字符会被编码来保证日志文件可读。Table 13-2显示了这些编码方案。

Table 13-2. Character encoding rules for HTTP headers in access.log
Character     Encoding
Newline     \n
Carriage return     \r
Backslash     \\
[     %5b
]     %5d
%     %25
ASCII 0-31     %xx (hexadecimal value)
ASCII 127-255     %xx (hexadecimal value)
13.2.4.4 log_fqdn

Squid默认把客户端IP地址放在access.log里。也可以记录可用的主机名,激活如下指令:

log_fqdn on

这点让Squid在接受到请求时,对客户端的地址发起反向DNS查询。假如在请求完成时查到了主机名,Squid就将它放在第3域。
13.2.4.5 ident_lookup_access

该访问规则列表决定Squid是否对客户端的TCP连接发起RFC 1413身份查询。默认情况下,Squid不会发布身份查询。为了激活这点,简单的增加一个或多个规则:

acl All src 0/0

ident_lookup_access allow All

假如在请求完成时查到了答案,Squid将其放在第8域。假如同时使用了HTTP验证,从验证得到的用户名会取代身份查询答案。
13.2.4.6 log_ip_on_direct

当Squid转发cache丢失到原始服务器时,它在第9域记录原始服务器的IP地址。可以禁止这个指令,以便squid记录主机名:

log_ip_on_direct off

在此情形下,主机名来自于URI。假如URI包含了IP地址,Squid不会将其转换为主机名。
13.2.4.7 client_netmask

该指令存在主要是为了保护用户的隐私。不同于记录完整的IP地址,你也可以掩盖一些位。例如:

client_netmask 255.255.255.0

在此设置下,access.log里的所有客户端IP地址的最后一个八位组是0:

1066036246.918     35 163.11.255.0 TCP_IMS_HIT/304 266 GET http://...

1066036246.932     16 163.11.255.0 TCP_IMS_HIT/304 266 GET http://...

1066036247.616    313 140.132.252.0 TCP_MISS/200 1079 GET http://...

1066036248.598  44459 140.132.252.0 TCP_MISS/500 1531 GET http://...

1066036249.230     17 170.210.173.0 TCP_IMS_HIT/304 265 GET http://...

1066036249.752   2135 140.132.252.0 TCP_MISS/200 50230 GET http://...

1066036250.467      4 170.210.173.0 TCP_IMS_HIT/304 265 GET http://...

1066036250.762    102 163.11.255.0 TCP_IMS_HIT/304 265 GET http://...

1066036250.832     20 163.11.255.0 TCP_IMS_HIT/304 266 GET http://...

1066036251.026     74 203.91.150.0 TCP_CLIENT_REFRESH_MISS/304 267 GET http://...

13.2.4.8 strip_query_terms

该指令是另一个隐私保护功能。在记录请求前,Squid删除了查询条件。假如日志文件不幸落入坏人之手,他们不会找到任何用户名和密码。当该指令激活时,在问号(?)之后的所有字节被删除。例如,某个URI如下:

http://auto.search.msn.com/response.asp?MT=www.kimo.com.yw&srch=3&prov=&utf8

会被记录为:

http://auto.search.msn.com/response.asp?

13.2.4.9 uri_whitespace

早前我提到过出现在某些URI里的空格字符的问题。RFC申明 URI必须不包括空格字符,但在实际中情况并非如此。uri_whitespace指令指明Squid如何处理这种情况。允许的设置是:strip (default), deny, allow, encode, 和chop。在这些设置里,strip,encode和chop保证URI域不包含任何空格字符(空格字符会给access.log增加多余的域)。

allow设置允许请求不加修改的通过Squid。它很可能会给重定向器和日志文件解析器带来麻烦。与之相反的是deny设置,它导致Squid拒绝这种请求。用户会接受到错误消息,但请求仍带着空格字符被记录到access.log。

假如设置为encode,Squid将空格字符按RFC 1738规范来编码。这点其实用户代理应该先做到。chop设置导致Squid把第一个空格字符后的URI都截断。

默认设置是strip,它让Squid从URI里移除空格字符。这确保日志文件解析器和重定向器工作正常,但可能会破坏某些事情,例如不正确编码的搜索引擎查询。
13.2.4.10 buffered_logs

默认情况下,Squid禁止写cache.log文件的buffer,这允许你运行tail -f 命令实时的观察日志文件变化。假如你认为这点导致不必要的性能开销,就可以禁用buffer:

buffered_logs off

然而,除非以完整debug模式运行Squid,这点可能无关紧要。注意该选项仅仅影响cache.log。其他的日志文件总使用非缓冲的写方式。

13.2.5 access.log分析工具

access.log包含很多信息,远不止你简单的浏览该文件所见。为了完整的浏览,必须使用第三方的日志文件分析包。你可在Squid的web页面的链接里,找到它们的列表。或者直接访问:http://www.squid-cache.org/Scripts/.

最流行的工具之一是Calamaris -- 一个Perl脚本,解析日志文件并产生基于文本的或HTML的报告。它提供关于会话的详细分类包括请求方式、客户端IP地址、原始服务器域名、内容类型、文件名扩展、响应size、以及更多。Calamaris也报告ICP查询会话,甚至其他cache产品的日志分析。其站点是:http://calamaris.cord.de.

Squeezer 以及它的派生Squeezer2,是Squid专有的分析工具。它们提供许多统计,能帮助你了解Squid的性能,特别是在有邻居cache时。两者都产生HTML文件作为输出。squid-cache.org站点的Logfile Analysis页有这些程序的链接。

Webalyzer 是另一个有用工具。它运行快速,并且产生带表格和柱形统计表的HTML页面。它原始是设计成分析原始服务器的访问日志的。尽管它能解析Squid的日志,但不会报告诸如命中率和响应时间的事件。它使用的某些条款不同于我的做法。例如,Webalyzer把任何请求叫做一个"命中",这不同于cache命中。它也把"页面"和"文件"加以区别。更多信息请访问Webalyzer的主页:http://www.mrunix.net/webalyzer/.

13.3 store.log

store.log记录Squid关于存储或删除cache目标的决定。对每个存在cache里的目标、每个不可cache的目标、以及每个被轮换策略删除的目标,Squid都会创建相应的日志条目。该日志文件内容既包含了内存cache又包含了磁盘cache。

store.log提供了下述不能从access.log获取的内容:

    * 1)某个特定的响应是否被cache。
    * 2)cache目标的文件号。对UFS基础的存储机制,你可转换该文件号到路径名,并且检查cache文件的内容。
    * 3)响应的内容长度:包括Content-Length值和实际的body大小。
    * 4)Date, Last-Modified, 和Expires头部的值。
    * 5)响应的cache关键字(例如MD5哈希值)。

如你所见,这些都是相对低级的信息,在日常管理中可能用不上。除非你要做专业的分析,或打算debug某程序,否则store.log可有可无。可以如下来禁止它:

cache_store_log none

跟其他日志文件一样,Squid将最新的日志条目写到该文件的末尾。某个给定的URI可能出现在日志文件里多次。例如,它先被cache,然后删除,接着又cache住。仅仅最近来的日志条目才反映目标的当前值。

store.log是文本基础的,看起来如下:

1067299212.411 RELEASE -1 FFFFFFFF A5964B32245AC98592D83F9B6EA10B8D 206

    1067299212 1064287906 -1 application/octet-stream 6840/6840

    GET http://download.windowsupdate.com/msdownload/update/v3-19990518/cab...

1067299212.422 SWAPOUT 02 0005FD5F 6F34570785CACABC8DD01ABA5D73B392 200

    1067299210 1057899600 -1 image/gif 1125/1125

    GET http://forum.topsportsnet.com/shf./images/nav_members1.gif

1067299212.641 RELEASE -1 FFFFFFFF B0616CB4B7280F67672A40647DD08474 200

    1067299212 -1 -1 text/html -1/67191

    GET http://www.tlava.com/

1067299212.671 RELEASE -1 FFFFFFFF 5ECD93934257594825659B596D9444BC 200

    1067299023 1034873897 1067299023 image/jpeg 3386/3386

    GET http://ebiz0.ipixmedia.com/abc/ebiz/_EBIZ_3922eabf57d44e2a4c3e7cd234a...

1067299212.786 RELEASE -1 FFFFFFFF B388F7B766B307ADEC044A4099946A21 200

    1067297755 -1 -1 text/html -1/566

    GET http://www.evenflowrocks.com/pages/100303pic15.cfm

1067299212.837 RELEASE -1 FFFFFFFF ABC862C7107F3B7E9FC2D7CA01C8E6A1 304

    1067299212 -1 1067299212 unknown -1/0

    GET http://ebiz0.ipixmedia.com/abc/ebiz/_EBIZ_3922eabf57d44e2a4c3e7cd234a...

1067299212.859 RELEASE -1 FFFFFFFF 5ED2726D4A3AD83CACC8A01CFDD6082B 304

    1066940882 1065063803 -1 application/x-javascript -1/0

    GET http://www.bellsouth.com/scripts/header_footer.js

每个日志条目包含如下13个域:

    * 1. 时间戳

      事件何时发生,表现为Unix纪元以来的秒数,它是毫秒级的。

    * 2. 动作

    * cache目标发生的动作。该域有3个可能值:SWAPOUT,RELEASE,和SO_FAIL。

          o 1)SWAPOUT在Squid成功的存储目标到磁盘时发生。某些目标例如那些消极cache的,仅保存在内存而不是磁盘,Squid不会在store.log里记录它们。

          o 2)SO_FAIL表明Squid不能完整的存储目标到磁盘。多半意味着存储机制拒绝以写方式打开新的磁盘文件。

          o 3)RELEASE在Squid从cache里删除目标,或首先就决定响应不可存储时发生。

    * 3. 目录号

    * 目录号是十进制小数形式,它是个到cache目录的7位索引。对没有存储到磁盘的目标,该域包含-1值。

    * 4. 文件号

    * 文件号是25位的标识符,内在的被squid使用。它被写成8字符的十六进制号。对UFS基础的存储机制,有算法可以转换文件号到路径名(见13.3.1 节)。没有存储到磁盘的目标,没有有效的文件号。对这些目标,该域的值是FFFFFFFF。仅仅在RELEASE和SO_FAIL情况下才会出现这个值。

    * 5. cache关键字

      Squid使用MD5哈希值作为主要的索引来定位目标。该关键字基于请求方式、URI、和其他可能的信息计算得来。可以从cache关键字来查找 store.log条目。然而请注意,目标的cache关键字可能改变。当Squid在access.log里记录TCP_REFRESH_MISS请求时,这点会发生。情况类似如下:

      1065837334.045 SWAPOUT ... 554BACBD2CB2A0C38FF9BF4B2239A9E5 ... http://blah

      1066031047.925 RELEASE ... 92AE17121926106EB12FA8054064CABA ... http://blah

      1066031048.074 SWAPOUT ... 554BACBD2CB2A0C38FF9BF4B2239A9E5 ... http://blah

      发生了什么呢?该目标原本cache在某个关键字下(554B...)。一段时间后,Squid接受到对该目标的另一请求,并转发确认请求到原始服务器。当响应以新内容返回时,Squid改变旧目标的cache关键字(92AE...),以便它能授予新目标正确的关键字(554B...)。然后旧目标删除,新目标存储到磁盘。

    * 6. 状态码

    * 该域显示响应的HTTP状态码,跟access.log一样。表13.1是状态码列表。

    * 7. 日期

    * HTTP响应的Date头部值,表现为Unix纪元以来的秒数。值-1表示Date头部不可解析,-2意味着头部完缺。

    * 8. 最后修改时间

    * HTTP响应的Last-Modified头部值,表现为Unix纪元以来的秒数。值-1表示Last-Modified头部不可解析,-2意味着头部完缺。

    * 9. 过期时间

    * HTTP响应的Expires头部值,表现为Unix纪元以来的秒数。值-1表示Expires头部不可解析,-2意味着头部完缺。

    * 10. 内容类型

    * HTTP响应的Content-Type头部值,排除了任何media-type参数。假如Content-Type丢失了,Squid插入值unknown。

    * 11. 内容长度/大小

    * 该域包含2个数字,以斜杠分开。第一个是Content-Length头部值。-1表明Content-Length头部不存在。第二个是HTTP消息 body的实际大小。你可使用这2个数字来部分的验证接受到的响应,并验证原始服务器是否不正确的计算了内容长度。大多数情形下,这2个数字相等。

    * 12. 方式

    * 请求目标的HTTP方式,跟access.log里的一样。

    * 13. URI

    * 最后一个域是请求URI,跟access.log里的一样。该域也有前述章节提到的空格问题。然而,这里不必为此担忧,因为你可安全的忽略任何多余的域。

    * 对许多RELEASE的条目,在最后8个域出现的是疑问号(?)。这是因为这些域的大部分值来自squid称为MemObject的结构。该结构仅在目标已被接受时,或目标被完整存储在内存时,才会出现。Squid cache里的大部分目标没有MemObject结构,因为它们仅存在于磁盘。对这些情况,Squid在相应域放置一个疑问号。

13.3.1 转换文件号到路径名

假如想要检查某个特定的cache文件,你可稍费工夫将文件号转换到路径名。另外目录号和L1和L2值也是必需的。在squid的源代码里,storeUfsDirFullPath( )函数做这个事情。可在src/fs/ufs/store_dir_ufs.c文件里找到它。如下短小的perl脚本模拟了当前算法:

#!/usr/bin/perl

$L1 = 16;

$L2 = 256;

while (<>) {

    $filn = hex($_);

    printf("%02X/%02X/%08X\n",

        (($filn / $L2) / $L2) % $L1,

        ($filn / $L2) % $L2,

        $filn);

}

这样使用它:

% echo 000DCD06 | ./fileno-to-pathname.pl

0D/CD/000DCD06

要在第N个cache_dir里找到该文件,简单的进入到相应的目录,并列出或查看该文件:

% cd /cache2

% ls -l 0D/CD/000DCD06

-rw-------  1 squid  squid  391 Jun  3 12:40 0D/CD/000DCD06

    % less 0D/CD/000DCD06

13.4 referer.log

可选的referer.log包含了来自客户端请求的Referer头部。为了使用该功能,必须在./configure时打开--enable-referer-log选项。还必须用referer_log指令来指定一个路径。例如:

referer_log /usr/local/squid/var/logs/referer.log

假如想禁止referer.log,则可设置文件名为none。

Referer 头部正常情况下包含一个URI,从这个URI获取到了请求(见RFC2616的14.36节)。例如,当web浏览器发布请求到某个内嵌图片时,Referer头部被设置成包含该图片的HTML网页的URI。当你点击HTML超链接时,它也被设置。某些web站点管理员使用Referer值来查找死链接。在使用Squid作为代理人模式时,你也许发现referer.log特别有用。

referer.log格式简单,仅有4个域。如下是一些示例:

1068047502.377 3.0.168.206

    http://www.amazon.com/exec/obidos/search-handle-form/002-7230223-8205634

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

1068047503.109 3.0.168.206

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

    http://g-images.amazon.com/./images/G/01/gourmet/gourmet-segway.gif

1068047503.196 3.0.168.206

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

    http://g-images.amazon.com/./images/G/01/marketing/cross-shop/arnold/appar...

1068047503.198 3.0.168.206

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

    http://g-images.amazon.com/./images/G/01/marketing/cross-shop/arnold/appar...

1068047503.825 3.0.168.206

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

    http://images.amazon.com/./images/P/B00005R8BC.01.TZZZZZZZ.jpg

1068047503.842 3.0.168.206

    http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/...

    http://images.amazon.com/./images/P/0596001622.01._PE_PI_SCMZZZZZZZ_.jpg

注意缺少Referer头部的请求不会被记录。这4个域描述如下:

    * 1. 时间戳

    * 请求时间,表现为Unix纪元以来的秒数,是毫秒级的。

注意的是,不像access.log,referer.log在Squid接受到完整请求时,会立刻记录。这样,referer.log条目在access.log之前发生,后者等待响应完成才记录。

    * 2. 客户端地址

    * 客户端地址跟access.log里的一样。log_fqdn和client_netmask指令也影响该日志文件。

    * 3. referer

    * 来自客户端请求的Referer头部值。注意referer值可能有空格字符或其他字符,在写referer.log前Squid不会对其进行编码。

    * 4. URI

    * 客户端正请求的URI。它匹配access.log里的URI。

13.5 useragent.log

可选的useragent.log包含来自客户端请求的User-Agent头部值。为了使用该功能,必须在运行./configure时打开--enable-useragent-log选项。还必须使用useragent_log指令来提供一个路径名。例如:

useragent_log /usr/local/squid/var/logs/useragent.log

User- Agent头部正常情况下包含了发起请求的user-agent的描述。大多数情形下,该描述只是简单的产品名列表和版本信息。你应该清楚应用程序可以轻易的提供伪造的user-agent信息。现代user-agent提供途径可定制该描述。甚至Squid在转发请求里能改变这个User-Agent头部。

useragent.log格式相对简单,看起来如下:

3.0.168.206 [05/Nov/2003:08:51:43 -0700]

    "Mozilla/5.0 (compatible; Konqueror/3; FreeBSD)"

3.0.168.207 [05/Nov/2003:08:52:18 -0700]

    "Opera/7.21 (X11; FreeBSD i386; U)  [en]"

4.241.144.204 [05/Nov/2003:08:55:11 -0700]

    "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/103u (KHTM..."

3.0.168.206 [05/Nov/2003:08:51:43 -0700]

    "Java1.3.1_01"

64.68.82.28 [05/Nov/2003:08:52:50 -0700]

    "Googlebot/2.1 (http://www.googlebot.com/bot.html)"

3.0.168.205 [05/Nov/2003:08:52:50 -0700]

    "WebZIP/4.1 (http://www.spidersoft.com)"

4.241.144.201 [05/Nov/2003:08:52:50 -0700]

    "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 3.0)"

3.0.168.206 [05/Nov/2003:08:54:40 -0700]

    "Bookmark Renewal Check Agent [http://www.bookmark.ne.jp/] (Version 2.0..."

不像其他日志文件,它仅有3个域:

    * 1. 客户端地址

    * 跟access.log里的一样。log_fqdn和client_netmask指令也影响该日志文件。

    * 2. 时间戳

    * 不像其他日志文件那样,用Unix纪元以来的秒数来描述时间,这里使用人工可读的格式。它是HTTP通用日志文件格式的时间戳,看起来如下:

      [10/Jun/2003:22:38:36 -0600]

      注意方括号界定时间戳,它包含一个空格。也请注意,跟referer.log一样,这些条目在Squid接受到完整请求时,立刻被记录。

    * 3. user-agent

    * User-Agent头部的值。这些字串几乎总包含空格。在将其写入日志文件时,Squid不会编码User-Agent值。

13.6 swap.state

swap.state 文件是目标写入cache目录、或从cache目录删除的日志写照。每个cache_dir有它自己的swap.state文件。当Squid启动时,它读取swap.state文件来重建cache目标的内存索引。这些文件对Squid管理来说,至关重要。

默认情况下,每个cache.state文件位于它相应的cache目录。这样,每个state文件自动驻留在每个cache_dir下。这点很有用--假如你想重新排序cache_dir行,或想从cache_dir列表里删除条目的话。

如果想将它们放在其他位置,可使用cache_swap_log指令来做:

cache_swap_log /usr/local/squid/var/logs/swap.state

在此情况下,Squid对每个cache目录创建一个swap.state文件,并增加数字后缀。例如,假如有4个cache目录,Squid创建如下日志:

/usr/local/squid/var/logs/swap.state.00

/usr/local/squid/var/logs/swap.state.01

/usr/local/squid/var/logs/swap.state.02

/usr/local/squid/var/logs/swap.state.03

在这个情形下,如果你要增加、删除、或重排序cache_dir行,就必须手工重命名swap.state文件,以保持事情一致。

技术上,swap.state格式是独立于存储机制的。然而,在当前版本的Squid里,所有的存储机制使用同一种格式。swap.state文件使用修正大小(48位)的二进制格式。各个域值以主机字节顺序记录,这样在不同的操作系统之间不便迁移。表13-3描述了swap.state日志条目的各个域的说明。

Table 13-3. swap.state entry fields
Name     Size, in bytes     Description
op     1     Operation on the entry: added (1) or deleted (2).
file number     4     Same as the fourth field of store.log, except it is stored in binary.
timestamp     4     A timestamp corresponding to the time when the response was generated or last validated. Taken from the Date header for responses that have one. Stored as the number of seconds since the Unix epoch.
lastref     4     A timestamp corresponding to the most recent access to the object.
expires     4     The object's expiration time, taken from an Expires header or Cache-Control max-age directive.
last-modified     4     The object's Last-Modified value.
swap file size     4     The amount of space the object occupies on disk. This includes HTTP headers and other Squid-specific meta-information.
refcount     2     The number of times this object has been requested.
flags     2     Various internal flags used by Squid.
key     16     The MD5 hash of the corresponding URI. Same as the key in store.log, except this one is stored in binary.

13.7 轮转日志

Squid不断的写日志,假如cache非常忙,那么在一段时间后,这些日志文件可能变得很大。某些操作系统甚至限制了文件的最大size(例如2G),假如写文件超过了这个size就会报错。为了保持日志文件容易管理,以及让Squid正常工作,必须定期轮转日志。

Squid有内建的功能用于轮转日志。可通过squid -k rotate命令来调用它,然后告诉Squid对每个日志文件保持多少份旧拷贝。例如,假如设置它为7,对每个日志文件会有8个版本:1个当前的,和7个旧的。

旧日志文件以数字扩展来重命名。例如,当执行一次轮转时,Squid重命名log.6到log.7,然后是log.5到log.6,依此类推。当前log变成log.0,并且Squid创建一个新的空文件,命名为log。

每次执行squid -k rotate时,Squid轮转下述文件:cache.log, access.log, store.log, useragent.log (假如激活), 以及referer.log (假如激活)。Squid也会创建最新版本的swap.state文件。然而请注意,swap.state不会以数字扩展形式来轮转。

Squid不会自己轮转日志,最好的办法是在crontab里自动执行。例如:

0 0 * * * /usr/local/squid/sbin/squid -k rotate

假如你想编写自己的脚本来管理日志文件,Squid提供了一个有用的模式,简单的设置logfile_rotate指令为0。这样,当你运行 squid -k rotate命令时,Squid简单的关闭当前日志文件,并且打开新的。如果操作系统允许重命名被其他进程打开的文件,则这点非常有用。下述shell脚本描述了一个思路:

#!/bin/sh

set -e

yesterday_secs=`perl -e 'print time -43200'`

yesterday_date=`date -r $yesterday_secs +%Y%m%d`

cd /usr/local/squid/var/logs

# rename the current log file without interrupting the logging process

mv access.log access.log.$yesterday_date

# tell Squid to close the current logs and open new ones

/usr/local/squid/sbin/squid -k rotate

# give Squid some time to finish writing swap.state files

sleep 60

mv access.log.$yesterday_date /archive/location/

    gzip -9 /archive/location/access.log.$yesterday_date

13.8 隐私和安全

Squid 的日志文件特别是access.log,包含了用户的活跃记录,因此它受隐私问题支配。作为Squid管理员,你必须采取额外的小心来保证日志文件安全。最好的办法是限制访问Squid主机的人员的数量。假如这点行不通,那么就要谨慎的检查文件和目录许可,确保日志文件不会被非信任的、或未授权的用户访问。

也可利用client_netmask和strip_query_terms指令来保护用户隐私。前者让识别access.log里的用户困难;后者移除了URI查询条件以避免泄露用户私人信息。更多信息见13.2.4节。

如果想要保持历史数据相当长的时间,你也许可裁减日志来保证日志文件匿名。假如你仅对哪个URI被访问感兴趣,而不是谁访问了它们,就可从 access.log里抽取出该域。这样也让文件更小,并且减少了隐私违背的风险。另一个技术是随机处理客户端IP地址。换句话说,就是创建一个过滤器,把真正的IP地址映射到假的地址,前提是同一个真IP地址总是映射到同一个假IP。假如你在使用RFC 1413身份验证协议或HTTP认证,也可考虑保持这些域匿名。

第14章 监视Squid

14.1 cache.log告警

在碰到Squid有问题时,应该首先查看cache.log里的警告信息。在正常运行时,你可发现不同的警告或信息,它们会或不会表明问题存在。我在13.1节里讲到了cache.log的结构。这里我重提一些可能在日志文件里见到的警告信息。

在中值响应时间超过限制时,high_response_time_warning指令让Squid打印一条警告。该值是毫秒级的,默认禁止。假如增加如下行到squid.conf:

high_response_time_warning 1500

如果大于1分钟的时间范围内的中值响应时间超过1.5秒,Squid会发布如下警告:

2003/09/29 03:17:31| WARNING: Median response time is 2309 milliseconds

在设置该指令前,你应该对Squid的正常响应时间级别有较好理解。假如设置过低,会导致很多假报警。在上述示例里,意味着一半用户的请求需要花费2.3 秒去完成。高响应时间可能由本地程序产生,例如运行超出文件描述符;也可能是远程问题,例如拥挤的Internet连接。

high_page_fault_warning 作用类似。假如每分钟的页面错误次数超过给定限制,它会导致Squid发布一条警告。高页面错误率通常意味着Squid进程不能完全放在内存,必须被交换到磁盘。这种交换严重影响了Squid的性能,所以你必须尽快解决问题,见16.1.8节的描述。

Squid使用Unix的getrusage()函数来获取页面错误计数。在某些操作系统上(例如Solaris),页面错误计数器表现异常。这样,high_page_fault_warning在这些系统上会导致假报警。

high_memory_warning指令也类似于前面提到的报警。在此情况下,它检查Squid进程的size,假如size超过了限制,就会在cache.log里告警。在某些操作系统上,进程size只增不降。这样,除非Squid关闭,你会经常得到这个警告。

进程size来自于如下3个函数之一:mallinfo( ), mstats( ), 或sbrk( ) 。假如这些函数在你的操作系统上不可用,则high_memory_warning不能工作。

Squid有其他一些硬编码的告警,可在cache.log里见到:

DNS lookup for 'neighbor.host.name' failed!

在Squid查询邻居cache的IP地址失败时,这点会发生。Squid大约每小时刷新一次邻居的地址。只要邻居的地址不可知,Squid不会发送会话到那边。

Detected DEAD Sibling: neighbor.host.name/3128/3130

在Squid不能与某个邻居cache通信时,它记录这个消息。例如,太多连续的ICP查询没有得到响应,这点就会发生。见10.3.2节的更多信息。

95% of replies from 'neighbor.host.name' are UDP_DENIED

该消息表明邻居cache拒绝回答Squid的查询。可能意味着Squid发送未经许可的查询到邻居cache。假如邻居cache使用地址基础的访问控制,并且你近来更改了地址,那它们就不会知道这个更改。在检测到该条件后,Squid拒绝发送更多查询到邻居cache。

Probable misconfigured neighbor at 192.168.121.5

若有未经授权的cache客户端向你发送ICP或HTCP查询,这点就会发生。最好的处理方法就是找到负责这个cache的组织或个人,询问他们为什么要查询你的cache。

Forwarding loop detected for:

回想一下,当单个请求遍历Squid 2次时,就发生了转发循环。请求的Via头部包含了遍历过的所有代理的列表。假如Squid在Via列表里检测到了自己的名字,它发布转发循环警告,并将请求直接发送到原始服务器。见10.2节关于转发循环的解释。

Closing client 192.168.121.5 connection due to lifetime timeout

client_lifetime指令对单个HTTP请求的存活期设置一个上限。当这样的请求终止时,Squid发布警告,它可能意味着某人正发起长时间连接来滥用cache,例如,无穷的download目标。

如你所见,caceh.log仅提供了异常事件的通知。对周期性的监控,还需要其他工具。cache管理器可能是最好的选择,尽管它的接口还不完美。

14.2 Cache管理器

译者注:由于本节的内容本人从未涉及,为避免误导,请读者自行阅读原书的该章节。 也有可能以后会更新本节内容,请关注本书中文版release的web目录:
http://home.arcor.de/jeffpang/squid

14.3 使用SNMP

译者注:由于本节的内容本人从未涉及,为避免误导,请读者自行阅读原书的该章节。 也有可能以后会更新本节内容,请关注本书中文版release的web目录:
http://home.arcor.de/jeffpang/squid

第15章 服务加速模式

15.1 概述

假如你已在某台机器上运行了原始服务器,就必须将它移到不同的IP地址或TCP端口。例如,可以这样做:(1)在独立的主机上安装squid;(2)给原始服务器分配一个新的IP地址;(3)将旧的IP地址分配给squid。为了安全起见,在squid和后台服务器通信的链路上,可使用私网地址。见图 15-1。

Figure 15-1. How to replace your origin server with Squid

另一个方法是配置squid成HTTP拦截,见第9章的描述。例如,可以配置离原始服务器最近的路由器或交换机,拦截HTTP请求,将其驱向squid。

假如你资源有限,不能将squid运行在独立的系统上,就可以让它随着HTTP服务一起运行。然而,这2个应用不能共享相同的IP地址和端口号。必须将后台服务绑定在不同的地址(例如127.0.0.1)或将它移到另一个端口。看起来改变端口最容易,但我推荐改变IP地址。

改变端口可能会带来问题。例如,当后台服务产生错误消息时,它可能会泄露错误的端口。更糟的是,假如服务产生一个HTTP重定向,它典型的将非标准端口号追加到Location URI后面。

HTTP/1.1 301 Moved Permanently
  
Date: Mon, 29 Sep 2003 03:36:13 GMT

Server: Apache/1.3.26 (Unix)

Location: http://www.squid-cache.org:81/Doc/

假如客户端接受到这样的响应,它会发起连接到非标准断口(81),这样就绕过了服务加速器。假如你必须让squid和后台服务运行在同一主机上,那最好让后台服务侦听在本地回路地址上(127.0.0.1)。在apache上,可以这样做:

BindAddress 127.0.0.1

ServerName www.squid-cache.org

一旦你决定如何重新部署原始服务器,下一步就是配置squid。

15.2 配置Squid

技术上,一个单一的配置文件指令,足以让squid从cache代理状态转换到加速状态。不幸的是,生活总非如此简单。因为许多组织的web服务器以不同方法实现,所以squid也有很多指令要考虑。

15.2.1 http_port

一般squid仅对80端口的HTTP服务加速。使用http_port指令让squid侦听在该端口:

http_port 80

假如想让squid既作cache代理,又作加速器,那么列出这2个端口:

http_port 80

http_port 3128

你也可以配置客户端发送代理请求到80端口,但我强烈不鼓励那样做。使用独立的端口,假如以后必要,你可以更容易将2个服务迁移到不同的主机上。

15.2.2 https_port

可以配置squid来处理加密的HTTP(SSL和TLS)连接。该功能要求在运行./configure时,激活--enable-ssl选项。在该模式下,squid解密来自客户端的SSL/TLS连接,并将未加密的请求转发到后台服务器。https_port指令有如下格式:

https_port [host:]port cert=certificate.pem [key=key.pem] [version=1-4]
         
           [cipher=list] [options=list]

cert和key参数是OpenSSL兼容的证书和私钥文件的路径。假如忽略了key参数,OpenSSL库会在证书文件里寻找私钥。

可选的version参数指定支持何种SSL/TLS协议:1为自动选择,2为支持SSLv2,3为支持SSLv3,4为支持TLSv1。

可选的cipher参数是冒号分隔的密码列表。squid简单的将它传递给SSL_CTX_set_cipher_list( )函数。更多信息,请阅读系统中的ciphers(1) manpage,或试着运行:openssl ciphers.

可选的options参数是冒号分隔的OpenSSL选项列表。squid简单的将它传递给SSL_CTX_set_options( )函数。更多信息,请阅读系统中的SSL_CTX_set_options(3) manpage。

如下是一些https_port行的示例:

https_port 443 cert=/usr/local/etc/certs/squid.cert

https_port 443 cert=/usr/local/etc/certs/squid.cert version=2

https_port 443 cert=/usr/local/etc/certs/squid.cert cipher=SHA1

https_port 443 cert=/usr/local/etc/certs/squid.cert options=MICROSOFT_SESS_ID_BUG

15.2.3 httpd_accel_host

在这里告诉squid后台服务器的IP地址或主机名。假如后台服务器使用前面描述的本地环路地址,那么这样写:

httpd_accel_host 127.0.0.1

Squid会预先将这个值作为要加速的URI。它也会改变Host头部的值。例如,假如客户端发起这样的请求:

GET /index.html HTTP/1.1

Host: squidbook.org

Squid会将它改变成这个形式:

GET http://127.0.0.1/index.html HTTP/1.1

Host: 127.0.0.1

你可以看到,请求不再包含对squidbook.org的任何信息。只要后台服务没有配置成多域虚拟主机,这样做就不会有问题。

假如想让squid使用原始服务器的主机名,那么可将它放在httpd_accel_host指令里:

httpd_accel_host squidbook.org

这样请求如下:

GET http://squidbook.org/index.html HTTP/1.1

Host: squidbook.org

另一个选项是激活httpd_accel_uses_host_header指令。这时squid对大部分请求,会将Host头部插入URI里;仅对那些缺少Host头部的请求,squid才使用httpd_accel_host值。

当使用主机名时,squid通过正常途径来查询其IP地址。因为期望该主机名被解析到2个不同的地址(一个是客户端连接到squid的地址,另一个是squid连接到后台服务器的地址),你应该增加静态的DNS接口到系统的/etc/hosts文件里。例如:

127.0.0.1       squidbook.org

也可以使用重定向器代替。例如,可以编写一个简单的perl程序,将http://squidbook.org/...改变为http://127.0.0.1/... 见11章关于重定向客户请求的具体细节。

httpd_accel_host指令有1个特殊值。假如将它设为virtual,在Host头部丢失时,squid将原始服务器的IP地址插入URI里。然而,该功能仅在使用HTTP拦截时有用。

15.2.4 httpd_accel_port

该指令告诉squid后台服务器的端口号。默认是80。不必改变该值,除非后台服务器运行在不同端口。如下是示例:

httpd_accel_port 8080

假如在多个端口上加速原始服务器,可以将该值设为0。在该情形下,squid从Host头部里获取端口号。

15.2.5 httpd_accel_uses_host_header

该指令控制squid如何决定它插入加速URI里的主机名。假如激活了,请求里的Host头部值,会优先于httpd_accel_host值。

httpd_accel_uses_host_header指令与后台服务器上运行的虚拟域配合工作。假如后台服务器仅处理1个域,那么可禁用它。然而,假如你在加速多个域名,就请打开它:

httpd_accel_uses_host_header on

假如激活了httpd_accel_uses_host_header指令,记得要配置一些本章后面描述的访问控制。为什么要这样做?请考虑如下配置:

httpd_accel_host does.not.exist

httpd_accel_uses_host_header on

因为大多数请求有Host头部,squid会忽略掉httpd_accel_host设置,很少将does.not.exist名字插入到URI里。那些非常聪明的假冒HTTP请求的人,会让squid从加速模式进入cache代理模式。假如我知道你正在使用squid作为加速器,并且没有正确的访问控制,那我能发送这样的请求:

GET /index.html HTTP/1.1

Host: www.mrcranky.com

假如你已经激活了httpd_accel_uses_host_header,并且没有任何基于目的地址的访问控制,squid会转发这个请求到www.mrcranky.com 。阅读15.4章,配置访问控制,以确保squid不会与外部原始服务器会话。

15.2.6 httpd_accel_single_host

前面的httpd_accel_uses_host_header指令决定squid插入URI里的主机名,这里的指令决定squid转发它的cache 丢失到哪里。默认的(httpd_accel_single_host 禁止),squid转发cache丢失到URI里的主机。假如URI里包含主机名,squid执行DNS查询来获取后台服务器的IP地址。

当激活了httpd_accel_single_host时,squid总是转发cache丢失到httpd_accel_host里定义的主机。换句话说,URI里的内容和Host头部不会影响到转发决定。也许激活该指令的最好的理由是避免DNS查询。简单的将httpd_accel_host设置为后台服务器的IP地址。激活它的另一个理由是假如你有其他设备(负载均衡器,病毒扫描器等)在squid和后台服务器之间。你可以让squid转发请求到这样的设备,不用对HTTP请求作任何改变。

注意同时激活httpd_accel_single_host和httpd_accel_uses_host_header是危险的,可能让攻击者破坏cache。考虑如下配置:

httpd_accel_single_host on

httpd_accel_host 172.16.1.1

httpd_accel_uses_host_header on

和这样的HTTP请求:

GET /index.html HTTP/1.0

Host: www.othersite.com

Squid 将请求转发到172.16.1.1的后台服务器,但存储响应在URI http://www.othersite.com/index.html下。既然172.16.1.1实际上并非 www.othersite.com,squid现在包含了对该URI的伪响应。假如激活了httpd_accel_with_proxy(下一节的),或者cache参与了某个层叠,它可能对信任用户发布坏的响应。为了阻止这样的滥用,记得阅读15.4章。

假如使用了 httpd_accel_single_host指令,服务端持久连接可能不能工作。这是因为squid存储空闲连接在原始服务器主机名下面,但连接建立代码会查找由httpd_accel_host值命名的空闲连接。假如2个值不同,squid查找相应的空闲连接会失败。在超时后,空闲连接关闭,不会被重用。可以用server_persistent_connections指令(见附录A)来禁止服务端持久连接,就避免了这个小问题。

15.2.7 httpd_accel_with_proxy

默认的,无论何时你激活了httpd_accel_host指令,squid进入加速模式。那就是说,它拒绝代理http请求,仅仅接受加速请求,就好像它真正是原始服务器一样。squid也禁用了ICP端口(但不是HTCP,如果你激活它的话)。假如想让squid既接受加速请求又接受代理请求,请激活这个指令:

httpd_accel_with_proxy on

15.3 令人疑惑之处

诚然,杂乱的配置让我也疑惑。让我们换种方法来看它。实际使用的配置,依赖于有多少后台服务器,以及需要加速多少原始服务器主机名。让我们考虑如下4个独立的案例。

15.3.1 一个主机,一个主机名

这是最简单的配置。因为你只有一个主机和一个主机名,Host头部就无关紧要。可以这样做:

httpd_accel_host www.example.com

httpd_accel_single_host on

httpd_accel_uses_host_header off

假如愿意,可以在httpd_accel_host后使用IP地址,尽管它将出现在access.log的URI里。

15.3.2 一个主机,多个主机名

因为有多个虚拟主机的主机名,Host头部就变得重要。我们想让squid将它插入转发URI里。这样配置:

httpd_accel_host www.example.com

httpd_accel_single_host on

httpd_accel_uses_host_header on

在该情形下,squid基于Host头部产生URI。假如缺少Host头部,squid会插入www.example.com。假如愿意,你可以禁止 httpd_accel_single_host。跟前面一样,可在httpd_accel_host后使用IP地址,以避免DNS查询。

15.3.3 多个主机,一个主机名

这点听起来象负载均衡配置。实现它的方法之一是,对多个IP地址的后台服务器创建一个DNS名字。对每个cache丢失,squid会轮循请求所有后台地址。在该情形下,squid配置与单主机/单主机名的情况一样:

httpd_accel_host roundrobin.example.com

httpd_accel_single_host on

httpd_accel_uses_host_header off

唯一不同之处是httpd_accel_host名被解析到多个IP地址。在BIND zone文件里,DNS配置可能看起来如下:

$ORIGIN example.com.
  
roundrobin      IN      A      192.168.1.2
                  
                IN      A      192.168.1.3
                  
                IN      A      192.168.1.4

在这样的DNS配置里,squid每次打开到roundrobin.example.com的新连接时,都使用列表里的下一个地址。当抵达列表末尾时,又会从头开始。注意squid内在的根据TTLs来缓存DNS响应。对每次DNS查询,不能依赖于名字服务器以不同顺序返回地址列表。

另一个选择是使用重定向器(见11章)来选择后台服务器。可以编写一个简单的脚本,将URI主机名(例如roundrobin.example.com)替换成不同的主机名或IP地址。如果重定向器足够智能,它甚至可以基于后台服务器的当前状态来进行选择。使用下列配置:

httpd_accel_host roundrobin.example.com

httpd_accel_single_host off

httpd_accel_uses_host_header off

15.3.4 多个主机,多个主机名

在该情形下,要使用Host头部。也要让squid基于原始服务器名字(例如,一个DNS查询)来选择后台服务器。配置如下:

httpd_accel_host www.example.com

httpd_accel_single_host off

httpd_accel_uses_host_header on

也许你凭错觉将httpd_accel_host设为virtual。然而,除非使用HTTP拦截,否则那将是一个错误。

15.4 访问控制

典型配置的加速器接受来自整个Internet的HTTP请求。然而这不意味着,可以忘记访问控制。你不应该让squid接受指向外部原始服务器的请求。唯一的例外是当你激活了httpd_accel_with_proxy时。

对仅作为加速器的配置,请使用目的基础的访问控制。例如,dst类型可执行这个任务:

acl All src 0/0

acl TheOriginServer dst 192.168.3.2
  
http_access allow TheOriginServer

http_access deny All

另外,假如愿意,可使用dstdomain ACL:

acl All src 0/0

acl TheOriginServer dstdomain www.squidbook.org
  
http_access allow TheOriginServer

http_access deny All

注意激活了httpd_accel_single_host某种程度上绕过了访问控制规则。这是因为在squid执行了访问控制检测后,原始服务器域(例如httpd_accel_host值)才被设置。

若在单个squid实例里,既使用加速模式又使用代理模式,访问控制会变得很麻烦。你不能简单的拒绝到外部原始服务器的所有请求。然而你能确保外部用户不允许对任意原始主机发起代理请求。例如:

acl All src 0/0

acl ProxyUsers src 10.2.0.0/16

acl TheOriginServer dst 192.168.3.2
  
http_access allow ProxyUsers

http_access allow TheOriginServer

http_access deny All

可以在访问控制规则里使用本地端口号。它实际上不会真正保护squid不被滥用,但确实能保证,例如,用户代理发送其代理请求到正确的端口。这点也让你以后可以方便的将加速服务和代理服务分拆到独立的主机上。假设配置squid侦听在80和3128端口,可以使用:

acl All src 0/0

acl ProxyPort myport 3128

acl ProxyUsers src 10.2.0.0/16

acl SurrogatePort myport 80

acl TheOriginServer dst 192.168.3.2
  
http_access allow ProxyUsers ProxyPort

http_access allow TheOriginServer SurrogatePort

http_access deny All

不幸的是,若同时激活了httpd_accel_single_host, httpd_accel_uses_host_header, 和httpd_accel_with_proxy,则这些访问控制规则不能阻止用户破坏cache的企图。这是因为有效的代理请求:

GET http://www.bad.site/ HTTP/1.1
 
Host: www.bad.site

和假的加速请求:

GET / HTTP/1.1

Host: www.bad.site

有同样的访问控制结果,但被转发到不同的服务器。它们有相同的访问控制结果是因为,在squid重写了加速请求后,它有和代理请求相同的URI。然而,它们不会被送到同一地方。加速请求到达由httpd_accel_host定义的服务器,因为激活了httpd_accel_single_host。

可以采取步骤来解决这个问题。确保后台服务器对未知的服务名(例如,Host头部指向非本地服务)产生一个错误。然而,最好不要同时运行squid作为加速和代理服务。

15.5 内容协商

近来的squid版本支持HTTP/1.1 Vary头部。假如后台服务器使用内容协商,这就是个好消息。例如,它能依赖于哪种web浏览器发起请求(User-Agent头部),或基于用户语言参数(Accept-Language头部),来发送不同的响应。

当对某URI的响应基于请求行为而变化时,原始(后台)服务器包含了一个Vary头部。该头部包含用于选择变量的请求头部列表。这些是selecting 头部。当squid接受到带有Vary头部的响应时,在它产生内部cache key过程中,会包含这个selecting头部值。这样,随后而来的带有同样selecting头部值的请求会产生cache命中。

假如在运行./configure时,使用了 —enable-x-accelerator-vary选项,squid会查找一个名为X-Accelerator-Vary的响应头部。squid严格的把这个头部和Vary头部一样对待。然而,因为这是个扩展头部,它被下游用户代理忽略。它本质上提供一个方法,用于squid和后台服务器之间的私有内容协商。为了使用它,你也必须修改服务应用,以使其在响应里发送这个头部。我不知道该头部在何种情形下有用。假如你服务于协商响应,你也许该使用标准的 Vary头部,以便所有的用户代理知道什么在进行。

15.6 补充

使用squid作为加速器可能改进原始服务器的安全和性能。然而,也有一些潜在的消极影响。请记住如下事情。

15.6.1 日志

当使用加速器时,原始服务器的访问日志仅包含了来自squid的cache丢失。并且,这些日志文件只记录了squid的IP地址,而不是客户端的。换句话说,squid的access.log才是所有有用信息的存放之处。

回想一下,squid默认不使用通用日志文件格式。可以使用emulate_httpd_log指令,来让squid的access.log看起来象Apache的默认日志文件格式。

15.6.2 忽略Reload

大部分浏览器的reload按钮产生带Cache-Control: no-cache指令的HTTP请求。虽然这点对客户端缓存代理来说很有用,但它可能破坏squid加速器的性能。假如后台服务器负载很高,这点尤其明显。reload请求强迫squid刷新当前cache响应,并从原始服务器重新获取新的响应。假如原始服务器的响应抵达很慢,squid会耗费超出正常数量的文件描述符和网络资源。

为了解决这个问题,可使用refresh_pattern的一个选项。当设置了ignore-reload选项时,squid假装请求没有包含no-cache指令。ignore-reload选项对加速器来说通常是安全的,尽管它在技术上确实违背了HTTP协议。

为了让squid忽略所有请求里的reload,在squid.conf里这样写:

refresh_pattern . 0 20% 4320 ignore-reload

其他的一种更安全的选择,你可以使用reload-into-ims选项。当请求包含no-cache时,它导致squid去验证其cache响应。然而请注意,这点仅在响应有cache验证选项(例如Last-Modified时间戳)时才能工作。

15.6.3 不可cache的内容

作为加速器,squid对来自后台服务器的cache响应,遵从标准HTTP头部规范。这意味着,例如,某些动态响应可能不被cache。你也许想使用refresh_pattern指令来强迫cache这些目标。例如:

refresh_pattern \.dhtml$ 60 80% 180

这样的欺骗仅对某些类型的响应有效,也就是说,那些没有Last-Modified或Expires头部的响应。squid默认不cache这样的响应。然而,在refresh_pattern规则里使用非零的最小时间,会让squid去cache这些响应,并在该数量的时间范围内,将响应作为cache 命中处理。请见7.7章的细节。

假如后台服务器产生其他类型的不可cache响应,你也许不能欺骗squid来缓存它们。

15.6.4 错误

把 squid作为原始服务器前面的加速器,你应该知道站点访问者有可能见到squid产生的错误消息,而不是原始服务器产生的。换句话说,你的squid的用法通过某些错误消息可能会暴露出来。例如,当squid解析客户HTTP请求失败时,它会返回自己的错误消息,假如请求不完整或畸形构造,就可能发生这种情况。若squid因为某些理由不能连接到后台服务器,它也会返回错误消息。

如果站点调整得好,可能不必担心squid的错误消息。虽然如此,你也应该经常仔细观察access.log,看看有何错误;任何错误,都有可能被你的用户看到。

15.6.5 刷新目标

在操作加速器时,你也许发现PURGE方式特别有用。如果你对服务的内容有良好理解,就该知道何时cache目标必须被刷新。刷新目标的技术跟我以前提过的一样。请见7.6章的细节。

15.6.6 邻居

尽管我不推荐,你仍可以配置squid作为加速器,并且作为cache层叠的一部分。假如选择了如此部署,请注意,squid默认转发cache丢失到父 cache(而不是后台服务器)。假如这不是你想要的,请确保使用cache_peer_access指令,以便对后台服务器的请求不会抵达邻居 cache。

第16章 调试和故障处理

16.1 一些通用问题

在讨论通用debug前,我先提起一些经常发生的问题。

16.1.1 "Failed to make swap directory"

Failed to make swap directory /var/spool/cache: (13) Permission denied

这点发生在你运行squid -z,并且squid的用户ID没有对/var/spool目录的写权限的时候。记住假如以root来启动squid,并且没有增加 cache_effective_user行,那么squid默认以nobody用户运行。解决方法很简单:

# chown nobody:nobody /var/spool

16.1.2 "Address already in use"

commBind: Cannot bind socket FD 10 to *:3128: Address already in use

这个消息出现在bind()系统调用失败时,因为请求端口已经被其他应用程序所打开。通常,若已有一个squid在运行,而又试图启动第2个squid实例,就会发生这种情况。假如你见到这个错误消息,请使用ps来观察是否squid已经在运行。

Squid使用SO_REUSEADDR socket选项,以便bind()调用总能成功,即使仍有一些残余的socket位于TIME_WAIT状态。若该消息出现,尽管squid没有在运行,但你的操作系统可能在处理这个问题上有bug。重启操作系统是解决问题的一个方法。

另一个可能性是端口(例如3128)当前已被其他应用程序使用。假如你怀疑这点,就可使用lsof程序来发现哪个应用正在该端口上侦听。FreeBSD用户能使用sockstat代替。

16.1.3 "Could not determine fully qualified hostname"

FATAL: Could not determine fully qualified hostname.  Please set 'visible_hostname'

假如squid不能识别它自己的完整可验证域名,就会报这个错。如下是squid使用的算法:

    * 1) 假如你将squid的HTTP端口绑定在指定的接口地址上,squid试图对该地址执行反向DNS查询。假如成功,查询答案就被用上。

    * 2) Squid调用gethostname( )函数,然后使用 gethostbyname( )函数,试着解析其IP地址。假如成功,squid使用后者函数返回的官方主机名串。

假如以上2项技术都不能工作,squid以前面提到的致命错误消息退出。在该情形下,必须使用visible_hostname指令来告诉squid它的主机名。例如:

visible_hostname my.host.name

16.1.4 "DNS name lookup tests failed"

默认情况下,squid在启动前执行一些DNS查询。这点确保你的DNS服务器可到达,并且运行正确。假如测试失败,可在cache.log或syslog里见到如下消息:

FATAL: ipcache_init: DNS name lookup tests failed

假如你在内网里使用squid,squid可能不能查询到它的标准主机名列表。可使用dns_testnames指令来指定你自己的主机名。只要接受到响应,squid就会认为DNS测试成功。

假如你想完全跳过DNS测试,简单的在启动squid时,使用-D命令行选项:

% squid -D ...

16.1.5 "Illegal character in hostname"

urlParse: Illegal character in hostname 'super_bikes.tripod.com'

默认情况下,squid检查URL的主机名部分的字符,假如它发现了非标准的字符,squid会抱怨。参考RFC 1034和1035,名字必须由字母A-Z,数字0-9,以及短横线(-)组成。下划线(_)是最有问题的字符之一。

Squid验证主机名是因为,在某些情形下,DNS对畸形字符的解析会很困难。例如:

% host super_bikes.tripod.com

super_bikes.tripod.com has address 209.202.196.70
 
 
% ping super_bikes.tripod.com

ping: cannot resolve super_bikes.tripod.com: Unknown server error

Squid事先检查主机名,这好过于以后返回Unknown server error消息。然后它会告诉用户主机名包含畸形字符。

某些DNS解析器确实能处理下划线和其他非标准字符。假如你想让squid不检查主机名,请在运行./configure时,使用—disable- hostname-checks选项。假如你允许下划线作为唯一的例外,那么使用—enable-underscores选项。

16.1.6 "Running out of filedescriptors"

WARNING! Your cache is running out of filedescriptors

上述消息出现在squid用完了所有可用文件描述符时。假如这点发生在正常条件下,就有必要增加内核的文件描述符限制,并且重新编译squid。请见3.3.1章。

假如squid成为了拒绝服务攻击的目标,那也会见到这条消息。某些人可能有意或无意的,同时对squid发送成百上千条请求。在这种情形下,可以增加一条包过滤规则,阻止来自恶意地址的TCP进入连接。假如攻击是分布式的,或使用假冒源地址,就很难阻止它们。

转发循环(见10.2章)也可能耗尽squid的所有文件描述符,但仅仅发生在squid不能检测到死循环时。Via头部包含了某个请求遍历过的所有代理的主机名。squid在头部里查找它自己的主机名,假如发现了,就报告这个循环。假如因为某些理由,Via头部从外出或进入HTTP请求里过滤掉了,squid就不能检测到循环。在该情形下,所有文件描述符被循环遍历squid的同一请求迅速耗完。

16.1.7 "icmpRecv: Connection refused"

假如pinger程序没有正确的安装,可见到下列消息:

icmpRecv: recv: (61) Connection refused

不过看起来更象是因为没有打开ICMP socket的权限,pinger立刻退出了。因为该进程未在运行,当squid试图与它会话时,会接受到I/O错误。为了解决该问题,请到源代码目录以root运行:

# make install-pinger

假如成功,你可见到pinger程序有下列文件属主和许可设置:

# ls -l /usr/local/squid/libexec/pinger
  
-rws--x--x  1 root  squid  140728 Sep 16 19:58 /usr/local/squid/libexec/pinger

16.1.8 在运行一段时间后,Squid变慢了

看起来更象squid与其他进程,或与它自己,在竞争系统中的内存。当squid进程的内存不再充足时,操作系统被迫从交换空间进行内存读写。这对squid的性能有强烈影响。

为了证实这个想法,请使用top和ps等工具检查squid的进程大小。也检查squid自己的页面错误计数器,见14.2.1.24章的描述。一旦你已确认内存耗费是问题所在,请执行下列步骤来减少squid的内存使用:

    * 1. 减少cache_mem值,见附录B。

    * 2. 关掉内存池,用该选项:

      memory_pools off

    * 3. 通过降低一个或多个cache目录的size,减少磁盘cache大小。

16.1.9 调试访问控制

假如访问控制不能正确工作,如下是一些有用帮助。编辑squid.conf文件,设置debug_options行如下:

debug_options ALL,1 33,2

然后,重配置squid:

% squid -k reconfigure

现在,对每个客户端请求以及每个响应,squid都写一条消息到cache.log。该消息包含了请求方式,URI,是否请求/响应被允许或拒绝,以及与之匹配的最后ACL的名字。例如:

2003/09/29 20:22:05| The request

    GET http://images.slashdot.org:80/topics/topicprivacy.gif is ALLOWED,

    because it matched 'localhost'

2003/09/29 20:22:05| The reply for

    GET http://images.slashdot.org/topics/topicprivacy.gif is ALLOWED,

    because it matched 'all'

知道ACL的名字,并非总能知道相应的http_access行,但也相当接近了。假如必要,可以复制acl行,并给予它们唯一的名字,以便给定的ACL名字仅仅出现在一个http_access规则里。

16.2 通过cache.log进行调试

从 13.1章已了解到,cache.log包含了不同的操作消息,squid认为这些消息足够重要,从而告诉了你。我们也将这些作为debug消息考虑。可以使用debug_options指令来控制出现在cache.log里的消息的冗长度。通过增加debug等级,可以见到更详细的消息,有助于理解 squid正在做什么。例如:

debug_options ALL,1 11,3 20,3

在 squid源代码里的每个debug消息有2个数字特征:1个节和1个等级。节范围从0到100,等级范围从0到10。通常来说,节号对应着源代码的组成成分。换句话说,在单一源文件里的所有消息,有相同的节号。在某些情形下,多个文件使用同一debug节,这意味着某个源文件变得太大,从而被拆分成多个小块。

每个源文件的顶部有一行,用于指示debug节。它看起来如此:

* DEBUG: section 9     File Transfer Protocol (FTP)

我不指望你通过查看源文件来查找节号,所有相关信息定义在表16-1里。

Table 16-1. Debugging section numbers for the debug_options directive
Number     Description     Source file(s)
0     Client Database     client_db.c
1     Startup and Main Loop     main.c
2     Unlink Daemon     unlinkd.c
3     Configuration File Parsing     cache_cf.c
4     Error Generation     errorpage.c
5     Socket Functions     comm.c
5     Socket Functions     comm_select.c
6     Disk I/O Routines     disk.c
7     Multicast     multicast.c
8     Swap File Bitmap     filemap.c
9     File Transfer Protocol (FTP)     ftp.c
10     Gopher     gopher.c
11     Hypertext Transfer Protocol (HTTP)     http.c
12     Internet Cache Protocol     icp_v2.c
12     Internet Cache Protocol     icp_v3.c
13     High Level Memory Pool Management     mem.c
14     IP Cache     ipcache.c
15     Neighbor Routines     neighbors.c
16     Cache Manager Objects     cache_manager.c
17     Request Forwarding     forward.c
18     Cache Manager Statistics     stat.c
19     Store Memory Primitives     stmem.c
20     Storage Manager     store.c
20     Storage Manager Client-Side Interface     store_client.c
20     Storage Manager Heap-Based Replacement     repl/heap/store_heap_replacement.c
20     Storage Manager Logging Functions     store_log.c
20     Storage Manager MD5 Cache Keys     store_key_md5.c
20     Storage Manager Swapfile Metadata     store_swapmeta.c
20     Storage Manager Swapin Functions     store_swapin.c
20     Storage Manager Swapout Functions     store_swapout.c
20     Store Rebuild Routines     store_rebuild.c
21     Misc Functions     tools.c
22     Refresh Calculation     refresh.c
23     URL Parsing     url.c
24     WAIS Relay     wais.c
25     MIME Parsing     mime.c
26     Secure Sockets Layer Proxy     ssl.c
27     Cache Announcer     send-announce.c
28     Access Control     acl.c
29     Authenticator     auth/basic/auth_basic.c
29     Authenticator     auth/digest/auth_digest.c
29     Authenticator     authenticate.c
29     NTLM Authenticator     auth/ntlm/auth_ntlm.c
30     Ident (RFC 1413)     ident.c
31     Hypertext Caching Protocol     htcp.c
32     Asynchronous Disk I/O     fs/aufs/async_io.c
33     Client-Side Routines     client_side.c
34     Dnsserver Interface     dns.c
35     FQDN Cache     fqdncache.c
37     ICMP Routines     icmp.c
38     Network Measurement Database     net_db.c
39     Cache Array Routing Protocol     carp.c
40     Referer Logging     referer.c
40     User-Agent Logging     useragent.c
41     Event Processing     event.c
42     ICMP Pinger Program     pinger.c
43     AIOPS     fs/aufs/aiops.c
44     Peer Selection Algorithm     peer_select.c
45     Callback Data Registry     cbdata.c
45     Callback Data Registry     leakfinder.c
46     Access Log     access_log.c
47     Store COSS Directory Routines     fs/coss/store_dir_coss.c
47     Store Directory Routines     fs/aufs/store_dir_aufs.c
47     Store Directory Routines     fs/diskd/store_dir_diskd.c
47     Store Directory Routines     fs/null/store_null.c
47     Store Directory Routines     fs/ufs/store_dir_ufs.c
47     Store Directory Routines     store_dir.c
48     Persistent Connections     pconn.c
49     SNMP Interface     snmp_agent.c
49     SNMP Support     snmp_core.c
50     Log File Handling     logfile.c
51     File Descriptor Functions     fd.c
52     URN Parsing     urn.c
53     AS Number Handling     asn.c
54     Interprocess Communication     ipc.c
55     HTTP Header     HttpHeader.c
56     HTTP Message Body     HttpBody.c
57     HTTP Status-Line     HttpStatusLine.c
58     HTTP Reply (Response)     HttpReply.c
59     Auto-Growing Memory Buffer with printf     MemBuf.c
60     Packer: A Uniform Interface to Store Like Modules     Packer.c
61     Redirector     redirect.c
62     Generic Histogram     StatHist.c
63     Low Level Memory Pool Management     MemPool.c
64     HTTP Range Header     HttpHdrRange.c
65     HTTP Cache Control Header     HttpHdrCc.c
66     HTTP Header Tools     HttpHeaderTools.c
67     String     String.c
68     HTTP Content-Range Header     HttpHdrContRange.c
69     HTTP Header: Extension Field     HttpHdrExtField.c
70     Cache Digest     CacheDigest.c
71     Store Digest Manager     store_digest.c
72     Peer Digest Routines     peer_digest.c
73     HTTP Request     HttpRequest.c
74     HTTP Message     HttpMsg.c
75     WHOIS Protocol     whois.c
76     Internal Squid Object handling     internal.c
77     Delay Pools     delay_pools.c
78     DNS Lookups; interacts with lib/rfc1035.c     dns_internal.c
79     Squid-Side DISKD I/O Functions     fs/diskd/store_io_diskd.c
79     Storage Manager COSS Interface     fs/coss/store_io_coss.c
79     Storage Manager UFS Interface     fs/ufs/store_io_ufs.c
80     WCCP Support     wccp.c
82     External ACL     external_acl.c
83     SSL Accelerator Support     ssl_support.c
84     Helper Process Maintenance     helper.c

debug等级这样分配:重要消息有较低值,非重要消息有较高值。0等级是非常重要的消息,10等级是相对不紧要的消息。另外,关于等级其实并没有严格的向导或要求。开发者通常自由选择适应的debug等级。

debug_options指令决定哪个消息出现在cache.log,它的语法是:

debug_options section,level section,level ...

默认设置是ALL,1,这意味着squid会将所有等级是0或1的debug消息打印出来。假如希望cache.log里出现更少的debug消息,可设置debug_options为ALL,0。

假如想观察某个组件的其他debug信息,简单的将相应的节号和等级增加到debug_options列表的末端。例如,如下行对FTP服务端代码增加了等级5的debug:

debug_options ALL,1 9,5

如同其他配置指令一样,可以改变debug_options,然后给squid发送重置信号:

% squid -k reconfigure

注意debug_options参数是按顺序处理的,后来的值会覆盖先前的值。假如使用ALL关键字,这点尤其要注意。考虑如下示例:

debug_options 9,5 20,9 4,2 ALL,1

在该情形下,最后的值覆盖了所有先前的设置,因为ALL,1对所有节设置了debug等级为1。

选择合适的debug节号和等级有时非常困难,尤其是对squid新手而言。许多更详细的debug消息仅对squid开发者和熟悉源代码的用户有意义。无经验的squid用户会发现许多debug消息无意义和不可理解。进一步的说,假如squid相对忙的话,你可能对某个特殊请求或事件进行独立 debug 有困难。假如你能一次用一个请求来测试squid,那么高的debug等级通常更有用。

若以高debug等级来运行squid较长时间,需要特别谨慎。假如squid繁忙,cache.log增长非常快,并可能最终耗尽它的分区的剩余空间。假如这点发生,squid以致命消息退出。另一个关注点是性能可能下降明显。因为有大量的debug消息,squid要耗费许多CPU资源来格式化和打印字符串。将所有debug消息写往 cache.log,也浪费了大量的磁盘带宽。

16.3 Coredump,断点,和堆栈跟踪

假如不幸,squid可能在运行时遭遇致命错误。这类型的错误来自3个风格:断点,总线错误,和异常分片。

断点是源代码里的正常检测。它是一个工具,被开发者用来确认在处理某事情前,相应的条件总为真。假如条件为假,程序退出并创建一个core文件,以便开发者能分析形势。如下是个典型的示例:

int some_array[100];
  

void

some_func(int idx)

{
        ...
      
        assert(idx < 100);
      
      
        some_array[idx]++;
     
        ...
}

这里,断点确保数组索引的值位于数组范围内。假如去访问大于或等于100的数组元素,就会遇到错误。假如不知何故,idx的值不小于100,程序运行时会打印如下消息:

assertion failed: filename.c:123: "idx < 100"

假如这点发生在squid上,就可在cache.log里见到"assertion failed"消息。另外,操作系统会创建一个core文件,这对事后分析有用。在本节结尾,我会解释如何去处理core文件。

总线错误是:由于处理器检测到其总线上的异常条件,会引发机器语言指令执行时致命失败。当处理器试图操作非连续的内存地址时,通常会发生这种错误。在64位处理器系统上可能更容易见到总线错误,例如Alpha和某些SPARC CPU。幸运的是,它们容易修复。

异常分片错误不幸的更常见,且有时难以修复。SEGV通常发生在进程试图访问无效内存区域时(可能是个NULL指针,或超出进程空间之外的内存地址)。当bug原因和SEGV影响在不同时间呈现时,它们特别难于捕获到。

Squid默认捕获总线错误和异常分片,当它们发生时,squid试图执行一个clean shutdown(清理关闭)。可在cache.log里见到类似的语句:

FATAL: Received Bus Error...dying.

2003/09/29 23:18:01| storeDirWriteCleanLogs: Starting...

大多数情形下,squid能够写swap.state文件的clean版本。在退出前,squid调用abort()函数来创建core文件。core文件可以帮助你或其他开发者来捕获和修复bug。

在错误发生时马上创建core文件,而不是先调用clean shutdown过程,这样更利于调试。使用-C命令行选项,可以告诉squid不去捕获总线错误和异常分片:

% squid -C ...

注意某些操作系统使用文件名core,而另外一些优先考虑进程名(例如squid.core)。一旦找到core文件,请使用调试器来进行堆栈跟踪。 gdb是GNU调试器--GNU C编译器的配套工具。假如没有gdb,可试着运行dbx或adb代替。如下显示如何使用gdb来进行堆栈跟踪:

% gdb /usr/local/squid/sbin/squid /path/to/squid.core
  
 
...
  
Core was generated by 'squid'.
  
Program terminated with signal 6, Abort trap.
...

然后,敲入where来打印堆栈轨迹:

(gdb) where
  
#0  0x28168b54 in kill ( ) from /usr/lib/libc.so.4
  
#1  0x281aa0ce in abort ( ) from /usr/lib/libc.so.4
  
#2  0x80a2316 in death (sig=10) at tools.c:301
  
#3  0xbfbfffac in ?? ( )
  
#4  0x80abe0a in storeDiskdSend (mtype=4, sd=0x82101e0, id=1214000,
  
    sio=0x9e90a10, size=4096, offset=-1, shm_offset=0)
  
    at diskd/store_io_diskd.c:485
  
#5  0x80ab726 in storeDiskdWrite (SD=0x82101e0, sio=0x9e90a10,
  
    buf=0x13e94000 "...", size=4096, offset=-1, free_func=0)
  
    at diskd/store_io_diskd.c:251
  
#6  0x809d2fb in storeWrite (sio=0x9e90a10, buf=0x13e94000 "...",
  
    size=4096, offset=-1, free_func=0) at store_io.c:89
  
#7  0x80a1c2d in storeSwapOut (e=0xc5a7800) at store_swapout.c:259
  
#8  0x809b667 in storeAppend (e=0xc5a7800, buf=0x810f9a0 "...", len=57344)
  
    at store.c:533
  
#9  0x807873b in httpReadReply (fd=134, data=0xc343590) at http.c:642
  
#10 0x806492f in comm_poll (msec=10) at comm_select.c:445
  
#11 0x8084404 in main (argc=2, argv=0xbfbffa8c) at main.c:742
  
#12 0x804a465 in _start ( )

你可见到,堆栈轨迹打印了每个函数的名字,它的参数,以及源代码文件名和行数。当捕获bug时,这些信息特别有用。然而在某些情形下,这些还不够。可能要求你在调试器里执行其他命令,例如打印来自某个函数的变量的值:

(gdb) frame 4
  

#4  0x80abe0a in storeDiskdSend (mtype=4, sd=0x82101e0, id=1214000,
      
    sio=0x9e90a10, size=4096, offset=-1, shm_offset=0)
      
    at diskd/store_io_diskd.c:485
  
485         x = msgsnd(diskdinfo->smsgid, &M,
   
 msg_snd_rcv_sz, IPC_NOWAIT);
  
(gdb) set print pretty
  
(gdb) print M
  
$2 = {
    
  mtype = 4,
    
  id = 1214000,
    
  seq_no = 7203103,
    
  callback_data = 0x9e90a10,
    
  size = 4096,
    
  offset = -1,
    
  status = -1,
    
  shm_offset = 0
  
}

在报告了某个bug后,请保留core文件一些天,可能还需要从它获取其他信息。

16.3.1 不能找到core文件?

core 文件写在进程的当前目录。squid在启动时默认不改变其当前目录。这样你的core文件(如果有的话),会写在启动squid的目录。假如文件系统没有足够的自由空间,或进程属主没有对该目录的写权限,就无法产生core文件。可以使用coredump_dir指令来让squid使用指定的 coredump目录--位于其他地方的有充足自由空间和完全权限的目录。

进程资源限制也会阻止产生core文件。进程限制参数之一是 coredump文件的大小。大部分操作系统默认设置这个值为"无限"。在当前shell里使用limits或ulimit命令,可以检查当前限制。然而请注意,你的shell的限制可能不同于squid的进程限制,特别是当squid随系统启动而自动启动时。假如怀疑进程限制阻止了core文件的产生,试试这样:

csh% limit coredumpsize unlimited

csh% squid -NCd1

在FreeBSD上,某个sysctl参数控制了操作系统对调用了setuid()或setgid()函数的进程,是否产生core文件。假如以root启动,squid会用到这些函数。这样为了得到coredump,必须告诉内核创建core文件,用这个命令:

# sysctl kern.sugid_coredump=1

请见sysctl.conf的manpage,关于在系统启动时如何自动设置变量的信息。

16.4 重现问题

有时候可能遇到这样的问题:某个请求,或原始服务器看起来不能与squid协调工作。可以使用下面的技术来确定问题在于squid,客户端,或原始服务器。技巧就是捕获HTTP请求,然后用不同的方法响应它,直到你验证了问题。

捕获HTTP请求意味着获取除了URL外的更多信息,包括请求方式,HTTP版本号,和所有请求头部。捕获请求的一个方法是,短期激活squid的完整debug模式。在squid主机上,敲入:

% squid -kdebug

然后,到web浏览器上发布请求。squid几乎会立刻接受到请求。在若干秒后,回到squid主机,并发布同样的命令:

% squid -kdebug

现在cache.log文件包含了上述客户端的请求。假如squid繁忙,cache.log会包含大量的请求,所以你必须查找它。它看起来如下:

2003/09/29 10:37:40| parseHttpRequest: Method is 'GET'

2003/09/29 10:37:40| parseHttpRequest: URI is 'http://squidbook.org/'

2003/09/29 10:37:40| parseHttpRequest: Client HTTP version 1.1.

2003/09/29 10:37:40| parseHttpRequest: req_hdr = {

User-Agent: Mozilla/5.0 (compatible; Konqueror/3)

Pragma: no-cache

Cache-control: no-cache

Accept: text/*, image/jpeg, image/png, image/*, */*

Accept-Encoding: x-gzip, gzip, identity

Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5

Accept-Language: en

Host: squidbook.org

注意squid把首行元素分开打印,必须手工组合它们如下:

GET http://squidbook.org/ HTTP/1.1

捕获完整请求的另一个方法是使用工具例如netcat或socket (http://www.jnickelsen.de/socket/ )。启动socket程序侦听在某个端口,然后配置浏览器使用该端口作为代理地址。当再次发起请求时,socket打印出HTTP请求:

% socket -s 8080
  
GET http://squidbook.org/ HTTP/1.1

User-Agent: Mozilla/5.0 (compatible; Konqueror/3)

Pragma: no-cache

Cache-control: no-cache

Accept: text/*, image/jpeg, image/png, image/*, */*

Accept-Encoding: x-gzip, gzip, identity

Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5

Accept-Language: en

Host: squidbook.org

最后,还可以使用网络包分析工具例如tcpdump或ethereal。使用tcpdump捕获到一些包后,可以使用tcpshow来查看它们:

# tcpdump -w tcpdump.log -c 10 -s 1500 port 80
  
# tcpshow -noHostNames -noPortNames < tcpdump.log | less
  
...

Packet 4
  
TIME:   08:39:29.593051 (0.000627)
  
LINK:   00:90:27:16:AA:75 -> 00:00:24:C0:0D:25 type=IP
  
  IP:   10.0.0.21 -> 206.168.0.6 hlen=20 TOS=00 dgramlen=304 id=4B29
          
        MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=15DC
  
 TCP:   port 2074 -> 80 seq=0481728885 ack=4107144217
      
        hlen=32 (data=252) UAPRSF=011000 wnd=57920 cksum=EB38 urg=0
  
 DATA:  GET / HTTP/1.0.
         
        Host: www.ircache.net.
          
        Accept: text/html, text/plain, application/pdf, application/
      
        postscript, text/sgml, */*;q=0.01.
      
        Accept-Encoding: gzip, compress.
      
        Accept-Language: en.
      
        Negotiate: trans.
      
        User-Agent: Lynx/2.8.1rel.2 libwww-FM/2.14.

.

注意tcpshow按数据里的新行字符为周期来进行打印。

一旦捕获到了某个请求,就将它存到文件。然后可以使用netcat或socket来让它重新通过squid:

% socket squidhost 3128 < request | less

假如响应看起来正常,问题可能在于用户代理。否则,可以改变不同事情来孤立问题。例如,假如你看到一些古怪的HTTP头部,那就从请求里删除它们,然后再试一次。让请求直接到达原始服务器,而不是经过squid,这样做也可调试。方法就是从请求里删除http://host.name/,并将请求发送到原始服务器:

% cat request
  
GET / HTTP/1.1

User-Agent: Mozilla/5.0 (compatible; Konqueror/3)

Pragma: no-cache

Cache-control: no-cache

Accept: text/*, image/jpeg, image/png, image/*, */*

Accept-Encoding: x-gzip, gzip, identity

Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5

Accept-Language: en

Host: squidbook.org
  
% socket squidbook.org 80 < request | less

以这种方式使用HTTP时,请参考RFC 2616和Oreilly的HTTP:The Definitive Guide这本书。

16.5 报告Bug

假如你的squid版本已经有几个月未更新了,在报告bug前你应该更新它。因为其他人可能也注意了同样的bug,并且它已被修复。

假如你发现了squid的合理bug,请将它填入到squid的bug跟踪数据库:http://www.squid-cache.org/bugs/ 。 它当前是个"bugzilla"数据库,需要你创建一个帐号。当bug被squid开发者处理了时,你会接到更新通知。

假如你对报告bug很陌生,请先花时间阅读Simon Tatham写的"How to Report Bugs Effectively" (http://www.chiark.greenend.org.uk/~sgtatham/bugs.html )。

当报告bug时,确认包含下列信息:

    * 1) Squid版本号。假如bug发生在不止一个版本上,就也要写上其他版本号。

    * 2) 操作系统名字和版本。

    * 3) bug每次都发生,还是偶尔发生。

    * 4) 所发生事情的精确描述。类似于"它不能工作","请求失败"之类的语句,本质上对bug修复者无用。记得要非常详细。

    * 5) 对断点,总线错误,或异常分片的堆栈跟踪。

记住squid开发者通常是无报酬的义务劳动,所以要有耐心。严重bug比小问题享有更高的解决优先级。

译后序

当译完本书最后一章时,心头袭来深深的寂寞。

在计算机领域,国内外技术水平差之甚远,部分原因归咎于语言的差异。

某种技术在国外流行若干年后,才有相应的中文文档出现。

没有文档,技术人员无法起步;而不规范的发行文档,更是误导了一批又一批的初学者。

本书的作者Duane Wessels是位大师级的人物,除了精湛的技术外,他写的本书文笔通畅,脉络清晰,丝毫不晦涩。

若对研究Squid抱着严肃的态度,那么请认真的拜读原著。

而我所能做的,只是按照我自己的理解,把原著译成中文。

好的软件只是解决了某一方面的问题,而真正可贵的,是开源的精神。

在开源的世界里,可以体会到现实中所没有的无私与奉献。

想起陈玉莲演的小龙女,和金轮法王有过这么一段对话:

金轮法王:你能接住十招,我就放过你们。

小龙女:试试看咯。

金轮法王:若接不住呢?

小龙女:接不住就接不住咯。

多年来让我记住的,是陈玉莲这种不食人间烟火,与世无争的神韵。

彭勇华

[email protected]

2005年10月于广州
 
相关阅读 更多 +
排行榜 更多 +
暗黑封魔录手游

暗黑封魔录手游

角色扮演 下载
战国美人游戏

战国美人游戏

角色扮演 下载
仙境苍穹手游

仙境苍穹手游

角色扮演 下载