BBS水木清华站∶精华区

发信人: ruster (尘埃*星辰*领悟), 信区: Linux        
标  题: 第九章 管理、维护和排错(下) 
发信站: BBS 水木清华站 (Thu Dec 21 13:53:14 2000) 
 
 
9.6 网络管理和排错 
   
  网络是容易出现问题的。尽管技术上说诸如网线折断或者远程路由错误这样的问题似 
乎不应该由服务器管理员负责,但是用拒绝负责的态度对待你的客户绝对无益于你在他 
们心目中的形象。不过,在这本书里面我们不想讨论如何处理网络硬件问题。我们将会 
讨论如何对网络的运行状态进行监视,并且找出一些常见的问题。 
   
  9.6.1  确定网络故障 
   
  网络出现问题的最常见情况是网络连接错误。网线断连,路由失效或者拥塞,甚至服 
务器主机已经掉电。我们这一节主要介绍如何判定这种比较简单的网络故障。 
   
  在你的网络出现问题的时候,第一步总是对目标地址的ping命令。这个命令调用基本 
的ICMP回应服务来探测对方的机器是否处于活动中。一些其它版本(特别是Solaris)U 
NIX的ping命令必须用特殊的参数才能激活输出信息,但是Linux根本不需要。 
   
  ping命令的格式非常简单:ping [目标地址]。例如,我感到到www.163.com的网络访 
问出奇地缓慢(当然,如果你是个学生或者教师,你不需要我解释也能知道是为什么) 
。所以我要看一看问题出在哪里: 
   
  $ping www.163.com 
   
  PING www.163.com (202.106.185.85) from 202.199.248.11 : 56(84) bytes of da 
ta. 
   
  64 bytes from 202.106.185.85: icmp_seq=0 ttl=242 time=750.6 ms 
   
  64 bytes from 202.106.185.85: icmp_seq=2 ttl=242 time=797.6 ms 
   
  ^C 
   
  --- www.163.com ping statistics --- 
   
  4 packets transmitted, 2 packets received, 50% packet loss 
   
  round-trip min/avg/max = 750.6/774.1/797.6 ms 
   
  Linux版本的ping命令会不断地重复发送ping命令直到你按下^C组合键。实际上,这个 
简单的ping命令已经显示了很多东西。首先,第一行中在www.163.com的旁边显示了它的 
IP地址(202.106.185.85)。这意味着你的DNS服务器处于正常的工作中。 
   
  接下来的行是信息行,我们可以注意到,网络的回应时间平均来说是774ms,这个数值 
显示了网络的速度。另外一个重要的信息是丢包率,现在的丢包率是50%,表明相当一部 
分数据包由于失败而被丢弃了。 
   
  由于有50%的数据包得到了返回,说明目标主机在正常工作中。但是丢包率很高,说明 
在数据传递的过程中已经出现了拥塞。 
   
  如果ping命令始终得不到回应(丢包率100%),那么说明目标主机已经瘫痪或者到目 
标主机的路由路径存在问题。这时候就需要使用traceroute命令来跟踪路由路径来解决 
问题: 
   
  $traceroute www.163.com 
   
  traceroute: Warning: www.163.com has multiple addresses; using 202.106.185 
.85 
   
  traceroute to www.163.com (202.106.185.85), 30 hops max, 38 byte packets 
   
   1  router (202.199.248.1)  0.989 ms  0.857 ms  0.781 ms 
   
   2  202.112.30.46 (202.112.30.46)  603.304 ms  646.450 ms  1124.455 ms 
   
  …………………… 
   
  每一行的信息来源于路由路径上的一个路由器。后面的数字是路由器响应请求的时间 
。如果某个路由器在缺省的时间内没有响应请求,它将显示为一个星号。如果某个路由 
器始终显示星号,那么它可能不工作了,或者路由表设置错误使得它无法知道如何对你 
的主机回应请求。后一种情况特别常见,尤其当路由器的管理是一些好奇或者恶作剧的 
学生完成的时候。 
   
  通过ping和traceroute可以找到网络中的拥塞点,确定路由层次是否有错误,甚至被 
用来测试网络的线路连接是否有错误。 
   
  关于Linux的ping命令我们要说一句题外的话。最常见的一种情况是,如果你在安装网 
卡的时候发生了任何错误,那么可能会出现ping自己的ip一切正常却就是无法和别人通 
信的情况。在这种情况下,你应该研究一下网卡模块是否正确地设置了。根据经验,这 
种情况几乎总是发生在ISA的NE2000兼容网卡被错误地配置在PNP模式的情况。 
   
  如果是你的主机出现了问题,你可以首先用ping命令来判断主机是否正常工作,如果 
ping的返回正常,就需要看一看服务进程是否在正确地监听端口了。 
   
  原则上,确定服务器进程是否在正确监听的正确方法是利用端口扫描程序。不过在大 
部分情况下,由于端口对话常常是纯粹文本的,所以可以用telnet程序连接上去察看服 
务是否正常,例如,我们用telnet命令来察看httpd程序是否在80端口等待请求: 
   
  $telnet 202.199.240.2 80 
   
  Trying 202.199.240.2... 
   
  Connected to 202.199.240.2. 
   
  Escape character is '^]'. 
   
  get // 
   
  <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 
   
  <HTML><HEAD> 
   
  <TITLE>501 Method Not Implemented</TITLE> 
   
  </HEAD><BODY> 
   
  <H1>Method Not Implemented</H1> 
   
  get to //index.html not supported.<P> 
   
  Invalid method in request get //<P> 
   
  <HR> 
   
  <ADDRESS>Apache/1.3.4 Server at asiist.edu.cn Port 80</ADDRESS> 
   
  </BODY></HTML> 
   
  Connection closed by foreign host. 
   
  connected to ...和Escape ...行说明在80端口确实有httpd服务程序在监听。为了确 
认程序,我们用get //(非法请求)得到了httpd服务程序的信息。 
   
  直接telnet到指定端口的方法是对许多服务进行测试的基本方法,如http,smtp,po 
p-3,nntp等等。 
   
  9.6.2  对网络进行监视 
   
  如果你发现系统性能异乎寻常地降低,那么接下来你需要干什么?系统性能降低或者 
干脆罢工可能由许多原因导致,无论如何,现在你必须启动某种监视程序来判断网络的 
问题所在。 
   
  即使你的系统运行正常,使用某种监视程序也是必要的,它可以让你了解你的系统有 
什么潜在的问题。另外,还可以对其它工作提供有益的参考。 
   
  最常用的工具是netstat程序,它有很多种功能,最基本的功能是显示当前系统运行的 
网络服务以及客户的请求情况: 
   
  $ netstat 
   
  Active Internet connections (w/o servers) 
   
  Proto Recv-Q Send-Q Local Address           Foreign Address         State 
   
  tcp        0      0 linux.asnc.edu.cn:pop-3 202.199.248.16:1066     TIME_W 
AIT 
   
  tcp        0      4 linux.asnc.edu.c:telnet 202.199.249.2:1146      ESTABL 
ISHED 
   
  tcp        0      0 linux.asnc.:netbios-ssn asnt_1.asnc.edu.cn:2092 ESTABL 
ISHED 
   
  tcp        0      0 linux.asnc.edu.cn:smtp  euler.math.hkbu.ed:1516 TIME_W 
AIT 
   
  tcp        0      0 mail.asnc.e:netbios-ssn 202.199.249.2:1029      ESTABL 
ISHED 
   
  Active UNIX domain sockets (w/o servers) 
   
  Proto RefCnt Flags       Type       State         I-Node Path 
   
  unix  7      [ ]         DGRAM                    296    /dev/log 
   
  unix  0      [ ]         STREAM     CONNECTED     120    @00000014 
   
  unix  0      [ ]         DGRAM                    2920 
   
  unix  0      [ ]         DGRAM                    611 
   
  unix  0      [ ]         DGRAM                    532 
   
  unix  0      [ ]         DGRAM                    461 
   
  unix  0      [ ]         DGRAM                    381 
   
  unix  0      [ ]         DGRAM                    324 
   
  unix  0      [ ]         DGRAM                    309 
   
  这里面最重要的是上半部分,容易看到,当前202.199.248.16正在使用pop-3协议从我 
们的系统上取信,在服务器上的连接端口是110(pop3),在对方机器上是1066。每个TCP 
连接都会产生出一个这样的行,在高峰时段,我们会看到服务器上出现200个以上的htt 
p连接和多个smtp连接,相应地,那时候会感到网络速度的明显退降。 
   
  netstat命令的第二个功能是显示网络接口的状态,这是通过netstat –i命令完成的 
: 
   
  $ netstat -i 
   
  Kernel Interface table 
   
  Iface   MTU Met    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OV 
R Flg 
   
  eth0   1500   0    18467      0      0     0    15691      1      0      0 
 BRU 
   
  eth1   1500   0    29712      0      0      0    16091      3      0       
0 BRU 
   
  lo     3924   0      979      0      0      0      979      0      0       
0 LRU 
   
  现在服务器上有三个网络接口,分别是两个以太网接口和一个本机loopback接口。在 
输出中,每个接口占据一行,各栏的含义是这样的: 
   
  Iface是网络的接口名字,MTU是网络的传输数据单元的大小。接下来,以RX和TX开头 
的栏是发送和接收的数据包的数目,OK代表正常的包,ERR,DRP,OVR分别代表包错误, 
包被丢弃和溢出。后两者一般发生在网络发生碰撞的时候。一般来说,碰撞包应该少于 
总包数的0.5%,如果你发现了更高的丢包率,可以肯定是网络的电气连接上出现了拥塞 
。 
   
  netstat命令还有一个-r选项,它等效于使用route命令: 
   
  $ netstat -r 
   
  Kernel IP routing table 
   
  Destination     Gateway     Genmask      Flags   MSS Window  irtt Iface 
   
  202.199.248.11  *         255.255.255.255 UH        0 0          0 eth0 
   
  255.255.255.255 *         255.255.255.255 UH        0 0          0 eth0 
   
  202.199.249.0   *         255.255.255.0   U         0 0          0 eth1 
   
  202.199.248.0   *         255.255.255.0   U         0 0          0 eth0 
   
  127.0.0.0       *         255.0.0.0       U         0 0          0 lo 
   
  default         router.asnc.edu 0.0.0.0   UG        0 0          0 eth0 
   
  如果发现了过多的碰撞,你需要一个以太网络分析软件,比如Netware的Net Analyse 
r程序。 
   
  另外一种情况,是发现系统中的数据流量过大。对于这种情况,你需要确定数据的流 
动方向,那些机器造成了过量的数据流。这个任务可以用专用的分析工具,也可以使用 
某种监听软件,例如安全性的章中讲的sniffit程序。不过,一般情况下,只要使用标准 
的tcpdump程序就可以完成这个任务了。 
   
  要使用tcpdump,你必须具有root权限,这个程序会显示出所有在网络上流动的数据包 
: 
   
  $tcpdump  
   
  Kernel filter, protocol ALL, datagram packet socket 
   
  tcpdump: listening on all devices 
   
  14:57:26.283567 eth1 < 202.199.249.2.1029 > linux.asnc.edu.cn.telnet: . 66 
7982:) 
   
  14:57:26.283648 eth1 > linux.asnc.edu.cn.telnet > 202.199.249.2.1029: P 1: 
89(88) 
   
  14:57:26.286378 eth0 > linux.asnc.edu.cn.1131 > www.asnc.edu.cn.domain: 37 
528+ ) 
   
  ……………………… 
   
  由于tcpdump程序会输出所有它看到的数据包,因此在网络繁忙的时候会看到它疯狂地 
输出数据包的统计信息。你可以用重定向把tcpdump程序的输出存储到文件然后用某种脚 
本工具来分析它们,也可以在使用tcpdump程序的时候加上过滤条件: 
   
  # tcpdump dst 255.255.255.255 
   
  Kernel filter, protocol ALL, datagram packet socket 
   
  tcpdump: listening on all devices 
   
  15:00:52.066876 eth0 B router.asnc.edu.cn.1997 > 255.255.255.255.1997: udp 
 12 
   
  15:00:52.066971 eth1 B router.asnc.edu.cn.1997 > 255.255.255.255.1997: udp 
 12 
   
  15:00:52.213242 eth0 B 202.199.248.99.1025 > 255.255.255.255.1689: udp 140 

   
  15:00:52.214023 eth1 B 202.199.248.99.1025 > 255.255.255.255.1689: udp 140 

   
  通过设定参数,我们在网络上查询所有的广播信息。同样,我们也可以用src来限定源 
包信息,用port设定端口。在各个限定之间可以用and和or设置关系: 
   
  # tcpdump port 23 and src 202.199.249.2 
   
  Kernel filter, protocol ALL, datagram packet socket 
   
  tcpdump: listening on all devices 
   
  15:04:57.489239 eth1 < 202.199.249.2.1029 > linux.asnc.edu.cn.telnet: . 66 
8346:) 
   
  15:04:57.689206 eth1 < 202.199.249.2.1029 > linux.asnc.edu.cn.telnet: . 0: 
0(0) ) 
   
  在网络出现由于软件问题引起的拥塞的时候,tcpdump是一个非常重要的分析工具。 
   
  9.7 账号管理 
   
  在第二章我们已经涉及到账号管理的概念,在那里我们涉及的是如何建立和删除一个 
账号,以及对账号进行控制。这里我们要介绍一些比较高级的内容,主要是如何对用户 
进行精确的控制。 
   
  一般来说,useradd和adduser程序已经足够好。(这两个程序是一个,adduser只是一 
个指向useradd程序的符号连接),然而你有时仍然需要直接编辑/etc/passwd程序来处 
理一些特殊的问题,比如说给出一个不需要口令的账户,禁止某个用户的登录等等。 
   
  在Linux中,你可以直接修改/etc/passwd程序,只要修改后用pwconv程序同步一下pa 
sswd和shadow文件的内容,对group程序也是一样。许多参考书上会建议你用vipw命令, 
不过它会用那个莫名其妙的vi程序进行编辑,反正我不太喜欢这个。不过vipw程序会自 
动备份/etc/passwd程序,如果你熟悉vi那就是另外一回事了。直接在命令行下输入vip 
w就可以起动这个程序。与其它任何需要编辑器的命令一样,可以用EDITOR环境变量来设 
置别的编辑器代替vi程序: 
   
  $EDITOR='/usr/bin/jed' 
   
  $export EDITOR 
   
  关于直接编辑系统的/etc/passwd和/etc/shadow文件的一个重要理由就是更改用户口 
令的有效期,超过这个有效期之后用户必须更改口令。这个动作可以通过更改/etc/sha 
dow文件完成,在/etc/shadow文件中,与这个资料相关的栏目不少,我们可以看一个范 
例的/etc/shadow文件中的一行来解释: 
   
  kzd:$1$YJ1L2VQB$2j8ReLRTmIVSK..edxYG..:11029:12:99999:7:-1:-1:134549420 
   
  在/etc/shadow文件中,第一个栏目是用户名字,然后是加密后的用户口令,下面几个 
栏目的意义是这样的: 
   
  第三栏:从1970年一月一日到用户的口令最近一次修改之间的天数。 
   
  第四栏:经过多少天之后,用户应该修改自己的口令。 
   
  第五栏:经过多少天之后,用户必须修改自己的口令。现在这个栏目是999999,说明 
用户可以永远不修改自己的口令,这个账号也不会被冻结。 
   
  第六栏:在口令修改期限到达之前多少天开始通知用户必须修改口令。 
   
  第七栏:在口令修改期限到达之后多少天冻结用户账号。 
   
  第八栏:从1970年一月一日到冻结账号的日期有多少天。 
   
  第九栏:保留。 
   
  如果你很关心用户的安全性,建议你使用这些栏目。 
 
   
  在建立用户账号的时候,需要设置用户的缺省shell。你可以用useradd –s [shell的 
名字]来设置这个,或者在建立用户账号之后用vipw程序修改他的登录shell。这个技术 
经常被用来封禁用户账号,只要把用户的shell栏目清空或改成一个其它的无法执行的s 
hell,这个用户就无法使用telnet登录。类似的技术被用来封禁ftp权限,只要用户的s 
hell不列入/etc/shells文件,用户就无法使用自己的账号进行ftp存取。我们的办法是 
写一个只有一行的shell文件: 
   
  #! /etc/noshell 
   
  exit 
   
  以后只要把用户的登录shell改成这个文件,用户就无法使用telnet和ftp进行登录。 
   
  尽管Linux的缺省设置(bash,path,………)已经比许多其它的UNIX要友好得多,但 
是许多情况下你仍然需要一些自定义的设置。在Linux中,如果/etc/skel目录存在,那 
么adduser程序执行的时候会自动把这个目录下面的所有文件和子目录复制到新用户的宿 
主目录下面。因此,你可以建立一组比较合适的配置文件和目录(.bashrc,.cshrc,. 
procmailrc,public_html,qmail的Maildir等等),放到/etc/skel目录下面,确定这 
些目录的属主是root,权限被正确地设置,然后当建立新用户的时候,adduser程序会把 
它们拷贝到用户的目录中并且自动把属主设置为新的用户,于是新的用户就得到了一个 
正确的系统配置。 
   
  也许你想要修改adduser程序的缺省设置。这可以用修改/etc/login.defs的办法来完 
成。下面是一个范例性质的/etc/login.defs: 
   
  MAIL_DIR        /var/spool/mail 
   
  PASS_MAX_DAYS   99999 
   
  PASS_MIN_DAYS   0 
   
  PASS_MIN_LEN    5 
   
  PASS_WARN_AGE   7 
   
  UID_MIN                   500 
   
  UID_MAX                 60000 
   
  GID_MIN                   500 
   
  GID_MAX                 60000 
   
  CREATE_HOME     yes 
   
  这里面的定义一目了然。其中,UID_MAX,UID_MIN以及GID_MIN,GID_MAX显示的是ad 
duser对新用户设置uid和gid值范围。如果你想要建立一个uid比较小的系统账号,你需 
要使用useradd的-r选项。 
   
  在许多情况下,你需要向所有用户发出一些公告信息,一个办法是使用email向所有人 
发信,另外一个办法是在用户登录的时候发出。后一项技术是通过在/etc目录下放一个 
名字叫motd的文本文件实现的,例如,我们这样建立自己的/etc/motd: 
   
  $cat /etc/motd 
   
  I am testing.Never Mind. 
   
  那么,当用户登录系统的时候会出现这样的信息: 
   
  Last login: Thu Mar 23 15:45:43 from 202.199.249.2 
   
  I am testing.Never Mind. 
   
  [wanghy@mail ~]$ 
   
  还有另外一种情况,你想要对登录到系统内的所有用户发送一条信息。这可以用wall 
命令实现: 
   
  $ wall I am Testing 
   
  那么用户的终端上会出现下面的信息: 
   
  Broadcast message from root (pts/0) Thu Mar 23 16:16:13 2000... 
 
   
  I am testing 
   
  作为系统管理员,你也许想要知道每个文件都在由哪个用户使用。在你需要强制拆卸 
文件系统的时候,这个功能特别有用,这可以通过lsof命令完成: 
   
  $lsof |more 
   
  COMMAND    PID   USER   FD   TYPE     DEVICE    SIZE      NODE NAME 
   
  init         1   root  cwd    DIR        3,1    4096         2 / 
   
  ……………… 
   
  csh       2338 wanghy  txt    REG        3,1  262152     80521 /bin/tcsh 
   
  csh       2338 wanghy  mem    REG        3,1  344890     64406 /lib/ld-2.1 
.2.so 
   
  ……………… 
   
  显然,wanghy用户正在使用/lib/ld-2.1.2.so文件。 
   
  9.8 系统升级和补丁程序 
   
  GNU模式下的所有事情都依赖于补丁程序。许多其它UNIX系统的用户嘲笑Linux的工作 
方式是“每周升级一个内核”,不过,说实话,不断地升级和修正已有的错误总要比把 
已知的错误放在那里等着服务器崩溃要好得多。许多其它UNIX系统没有这样多的补丁, 
原因很多,但是有一个很重要的问题是开发商总是希望用户对系统的缺陷报以“眼不见 
为净”的态度。相反,Linux系统是提供源代码的,因此不断有人发现它的缺陷并且加以 
改进。 
   
  在Linux下面,修正程序的主要方式是对源代码打补丁,或者用标准的说法叫做“pat 
ch”。patch命令会从标准输入读入补丁的内容,与目标文件进行比较,然后修改目标文 
件中对应的部分。这样说可能不容易理解,我们可以看一个范例性的patch文件: 
   
  $cat bash-2.03-profile.patch 
   
  --- bash-2.03/config-top.h.profile      Mon Feb 22 14:37:17 1999 
   
  +++ bash-2.03/config-top.h      Mon Feb 22 14:37:29 1999 
   
  @@ -3,6 +3,8 @@ 
   
   /* This contains various user-settable options not under the control of 
   
      autoconf. */ 
 
   
  +#define NON_INTERACTIVE_LOGIN_SHELLS 
   

   
   /* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to 
   
      continue processing arguments after one of them fails.  This is 
   
      what POSIX.2 specifies. */ 
   
  其实真正的应该注意的行只有里面用---和+++开始的行。这两行的含义是,以+++开头 
的行中指出的文件应该被修改,修改的方法就是按照下面的说明,说实话,你并不需要 
了解patch文件的详细语法,那是开发者的任务,你真正需要的是如何在已有的代码上使 
用patch。 
   
  要使用patch文件,可以使用patch命令,例如,我们进入到bash-2.03的源代码目录, 
然后: 
   
  $patch < ../bash-2.03-profile.patch 
   
  patching file `config-top.h' 
   
  这个信息的出现说明patch文件已经被正确地读入,修改了需要打补丁的文件。 
   
  在使用patch的过程中,最容易发生的问题是弄错了目录。patch文件的目录设定比较 
怪异。比如说,像上面的那个patch,文件路径名是bash-2.03/config-top.h,那么,我 
们应该在哪个目录下执行patch命令?bash-2.03的父目录吗?否!必须在bash-2.03目录 
下执行。如果执行时你的目录不正确,你就会得到这样的信息: 
   
  $patch < bash-2.03-profile.patch 
   
  can't find file to patch at input line 3 
   
  Perhaps you should have used the -p or --strip option? 
   
  The text leading up to this was: 
   
  -------------------------- 
   
  |--- bash-2.03/config-top.h.profile     Mon Feb 22 14:37:17 1999 
   
  |+++ bash-2.03/config-top.h     Mon Feb 22 14:37:29 1999 
   
  -------------------------- 
   
  File to patch: 
   
  这时你就需要读出patch文件中的目录,然后在正确的目录里面重新执行patch程序。 
   
  在patch完成之后,按照我们的一般方法,重新编译源代码,就可以使用新的程序了。 
   
  9.9 性能调整 
   
  让我们开始关于服务器管理的最后的主要内容。我们在一开始就说过,传统上,Linu 
x并不适合作为重负荷服务器。这是因为起源的原因。Linus本人最开始只是将Linux作为 
跑GNU GCC编译器的一个平台。为了具有较高的效能,一开始Linux的发展方向是让系统 
具有较高的进程效率而不是网络性能。但随着Linux的发展,越来越多的人用Linux作为 
他的网络服务器平台,而从2.x开始,Linux内核在处理网络负荷方面已经有了很大的提 
高。不久,2.4的系统内核将会推出(如果一切顺利,在你们看到这本书的时候,2.4内 
核已经可以使用了)。这个系统内核的最大改进是可以支持非常高的硬件配置和更好的 
重负荷性能。同时,在笔者写这本书的时候,用于Linux的集群服务器也已经面世,因此 
,讨论如何用Linux作为中高端的服务器仍然是有意义的。 
   
  解决Linux世界中的问题的最终手段往往是从源代码开始。如同我们看到的那样,在L 
inux中调整和重新编译内核实际是很简单的事情。而实际上,调整系统内核也确实能够 
解决部分的问题。 
   
  在使用下面介绍的内容之前,请记住我不会为这些东西负责。这些内容仅仅是相关文 
档中指出的,我也从没有面对过负担如此沉重以至于需要按照最大服务能力的情况调整 
系统内核的情况。不管怎么说,如果你真的需要试验这些东西,请你首先在一台空载的 
Linux上试验。 
   
  9.9.1 性能监视 
   
  也许你偶尔会感到系统速度难以想象地缓慢。无论在Linux还是Windows中,这种事情 
都十分正常,因为有太多的东西消耗系统资源。无论如何,检查系统的运行状态是对性 
能进行调整的第一步。 
   
  监测系统最主要的工作是检查当前消耗的内存和CPU利用率。检查当前内存的使用状况 
可以用free命令: 
   
  $free 
   
               total       used       free     shared    buffers     cached 
   
  Mem:        257528     253908       3620      21676     182064      47724 
   
  -/+ buffers/cache:      24120     233408 
   
  Swap:       698788       4156     694632 
   
  在这个例子中,系统一共具有256MB的物理内存和680MB的交换内存,可能让你感到吃 
惊的是可用的物理内存居然只剩下不到3MB。这是由于Linux把空余的内存都拿来当成磁 
盘缓冲造成的,注意到这一点之后,就会发现现在系统内存几乎是空着的。 
   
  一般情况下,可以把buffers看成当前空闲的内存量,这些内存并未真正使用,而仅仅 
是放在磁盘缓冲区中。当然,由于ext2文件系统的性能,你至少也需要以MB计算的buff 
ers存在,否则你就会看到系统速度犹如蜗牛一般。尤其是,如果你发现系统开始大量使 
用Swap内存,那么你应该考虑是否需要升级内存了。 
   
  同样,可以用uptime命令检查系统的负载: 
   
  $uptime 
   
    6:39pm  up 2 days, 22:40,  1 user,  load average: 0.00, 0.00, 0.00 
   
  它显示了系统当前已经运行的时间,连接入系统的用户个数,而最重要的是load ave 
rage。这个输出数值的含义很难用一两句话说清,而且不同的用户对此也说法不一。按 
照某些文档,这三个数分别是过去一分钟,五分钟和十分钟时间内平均有多少个进程由 
于CPU来不及处理而进入等待。在传统UNIX的管理员手册中,认为在1以下表示系统正常 
,2-3表示系统轻度负载,10以上表示系统已经严重过载。不过,显然对于不同的系统, 
过载的标准是不同的。一般来说,我们认为load average不应该大于你的系统的处理器 
数目*2。 
   
  top命令也是一个显示系统负载的重要命令,它和free+uptime命令一样会显示当前的 
内存分配和load average。然而,top命令会显示详细的多的信息: 
   
  $ top 
   
    6:50pm  up 2 days, 22:51,  1 user,  load average: 0.00, 0.00, 0.00 
   
  56 processes: 55 sleeping, 1 running, 0 zombie, 0 stopped 
   
  CPU states:  0.0% user,  0.5% system,  0.0% nice, 99.4% idle 
   
  Mem:  257528K av, 254196K used,   3332K free,  21896K shrd, 182124K buff 
   
  Swap: 698788K av,   4156K used, 694632K free                 47792K cached 
 
   
    PID USER     PRI  NI  SIZE  RSS SHARE STAT  LIB %CPU %MEM   TIME COMMAND 
   
   5458 root      13   0  1060 1060   856 R       0  0.9  0.4   0:01 top 
   
    448 root      10   0   104    0     0 SW      0  0.1  0.0 365:46 lpd 
   
      1 root       0   0   124   72    52 S       0  0.0  0.0   0:17 init 
   
      2 root       0   0     0    0     0 SW      0  0.0  0.0   0:03 kflushd 
   
      3 root       0   0     0    0     0 SW      0  0.0  0.0   0:07 kupdate 
   
  除了给出当前详细的CPU利用率信息之外,还给出了当前占用CPU时间最多的进程的列 
表,显然,在我们的情况下,系统几乎是空闲的。 
   
  top程序会持续地在前台运行,等待你输入命令,并且每隔5秒钟左右刷新一下服务器 
信息的显示。可以用h命令显示top的命令列表,其中,最重要的命令是杀死一个进程, 
例如,我们要杀死lpd守护进程,那么按下k键,将提示: 
   
  PID to kill: 
   
  要求你输入想要杀死的进程的进程号(pid),输入448,然后会要求你输入发送给进 
程的信号,缺省是15,你也可以使用自己选择的信号: 
   
  Kill PID 448 with signal [15]: 
   
  直接回车,就给lpd进程发送了一个终止信息,lpd进程将会被杀掉。 
   
  监视内存的使用还可以使用vmstat命令,它的语法是vmstat [时间间隔]。例如,下面 
的命令将每隔五秒钟对系统的内存使用做一次统计: 
   
  $vmstat 5 
   
     procs                      memory    swap          io     system        
  cpu 
   
   r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  s 
y  id 
   
   0  0  0   4156   3944 181928  47828   0   0     0     1   54    58   8  2 
1  70 
   
   0  0  0   4156   3944 181928  47828   0   0     0     0  103   109   0    
0 100 
   
  ………………………… 
   
  每一行代表一个采样结果,在procs的栏目里面,给出的是处于运行、睡眠和交换态的 
进程数,内存的项目意义一目了然,io栏目中给出了单位时间内块设备io的数目,syst 
em中给出了执行系统调用(in)和上下文切换(cs)的次数,最后的cpu栏目中,us是用户进 
程占用cpu时间的百分比,sy给出系统内核消耗的时间,id是空闲时间。 
   
  9.9.2   调整系统参数 
   
  Linux内核中,包含了一些对于系统运行态的可设置参数。下面简单地介绍一下可能需 
要设置的一些参数。必须记住,除非你有明确的理由,否则确实不需要自己调整它们。 
   
  缓冲区刷新频率: 
   
  VFS的缓冲刷新是Linux文件系统高效的重要原因之一,但同时,也增加了文件丢失的 
可能性。如果性能对你真的很重要,你应该考虑调整这个参数。 
   
  缓冲刷新的参数可以通过调整/proc/sys/vm/bdflush文件来完成,这个文件的格式是 
这样的: 
   
  $cat /proc/sys/vm/bdflush 
   
  40      500     64      256     500     3000    500     1884    2 
   
  每一栏是一个参数,其中最重要的是前面几个参数。第一个数字是在“dirty”缓冲区 
达到多少的时候强制唤醒bdflush进程刷新硬盘,第二个数字是每次让bdflush进程刷新 
多少个dirty块。所谓dirty块是必须写到磁盘中的缓存块。接下来的参数是每次允许bd 
flush将多少个内存块排入空闲的缓冲块列表。其他一些参数的含义可以参考/usr/src/ 
linux/Documentation/stsctl/vm.txt的有关部分。 
   
  如果你确实认为修改这些数字对你非常重要,那么考虑使用这样的数字来设置: 
   
  echo '100 1200 128 512 15 5000 500 1884 2 '> /proc/sys/vm/bdflush 
   
  必须记住,这样的设置加大了缓冲区大小,降低了bdflush被启动的频度,同时也增加 
了万一系统崩溃丢失数据的危险性。到底是不是应该这样做,你只有自己去判断。 
 
   
  文件句柄数和i-节点数 
   
  /proc/sys/fs下的文件设置一些文件系统的重要参数,特别是设置可以同时打开的文 
件数目。缺省的情况下,系统中允许同时打开的文件数目是4096。在一个大型的网站中 
,这个数字很容易被突破,因此你有可能需要改变这个值。于打开文件相关的主要文件 
是file-max和inode-max。 
   
  一般情况下,最大打开文件数设置不应该超过物理内存(以兆计算)乘以64,而最大 
的使用的i节点的数目应该是最大打开文件数目的3倍到4倍。例如,我们将最大打开文件 
数设置成为8192,而i节点的数目设置为31768,那么 
   
  echo '8192' > /proc/sys/fs/file-max 
   
  echo '32768' > /proc/sys/fs/inode-max 
 
   
  ulimit命令 
   
  除了核心的限制之外,还有一些系统自动对用户进程的限制,例如在第二章我们曾经 
设置的forks限制。这些限制可以用ulimit命令限制: 
   
  $ulimit -a 
   
  core file size (blocks)  0 
   
  data seg size (kbytes)   unlimited 
   
  file size (blocks)       unlimited 
   
  max memory size (kbytes) unlimited 
   
  stack size (kbytes)      8192 
   
  cpu time (seconds)       unlimited 
   
  max user processes       256 
   
  pipe size (512 bytes)    8 
   
  open files               1024 
   
  virtual memory (kbytes)  2105343 
   
  执行带-a参数的ulimit命令显示了当前各种用户进程限制。通常,对于服务器进程来 
说,第一个需要调整的是每个进程可以打开的文件数目限制。显然,在缺省配置中,这 
个限制是1024,我们可以手工将这个数字加大: 
   
  ulimit –n 4096 
   
  这个过程将每个进程可以打开的文件数目加大到4096。 
   
  下一个需要限制的东西是每个进程使用的内存量,一般我们可以限制httpd或者cgi进 
程使用的内存量,下面的命令将每个进程使用的内存限制在4MB: 
   
  ulimit –m 4096 
   
  当然,设置forks进程的数目也是熟知的: 
   
  ulimit –u 512 
   
  注意你只能最大将这个数字设置到512。如果512仍然不够,那么你需要修改内核的源 
代码。 
   
  9.9.3 服务器的特有问题 
   
  作为服务器的守护进程,各种守护程序会不断地forks出各种子进程,或是启动另外的 
服务程序。每一种服务程序都具有自身的问题,但是最常见的问题出在apache和inetd。 
   
  让我们首先考虑inetd。这个程序的行为我们已经很清楚,它在后台运作,每当应该由 
它负责的端口接收到请求时就去启动对应的服务程序。你可能会非常奇怪inetd有什么好 
处,为什么这样多的程序都由它启动,回答是inetd将正常的tcp/ip 数据流简化为标准 
流式文件I/O。如果一个程序是从inetd启动,那么它根本不需要考虑网络编程的问题, 
而只要简单地对stdin和stdout操作,好像网络数据流不存在一样。这种编程上的简单性 
使得许多人使用inetd作为自己的程序执行平台。 
   
  然而inetd的这种实现使得它本身是一个效率比较低的系统,如果单单是效率比较低的 
话我们还可以忍受,问题在于,出于安全性方面的考虑,inetd被设置为监测单位时间内 
的请求个数,一旦超过某个值(大约每秒40次)就关闭对应的服务,直到请求恢复正常 
。显然,对于负载量比较大的站点,使用inetd进行服务根本就是一个玩笑。 
   
  像apache这样的程序,可以设置为作为一个单独的守护进程启动,这样就不需要使用 
inetd了,因此只要守护进程设计比较合理,就可以接收足够多的请求。但是像in.ftpd 
和pop3d这样的程序显然是要一个相当于inetd的服务程序才能正确启动的。 
   
  解决的办法是使用某种代替产品,例如在qmail那一章中我们介绍的tcpserver程序, 
这个程序完成和inetd一样的工作,但是可以接受更多的请求。 
   
  现在我们来考虑apache服务器的问题。实际上,Internet上主要的数据流量都来源于 
WEB页面,而且在接入internet的情况下,一台服务器的大部分资源都是用来执行httpd 
服务。 
   
  apache服务器本身是一个守护进程,按照我们说的forks方式工作。由于连接到服务器 
的请求数可能非常大,因此一般来说apache服务器并不会在接收到一个请求的时候就fo 
rks出一个进程。按照Apache开发组自己的说法,同时连接数与forks数量的比值大约是 
5:1,也就是httpd进程的数目是最大同时连接数的20%。这个估计可能有些保守,实际的 
forks数目很可能会比这里估计的数量多一些。无论如何,即使按照这样的数字,缺省的 
256的forks极限也是容易被突破的,因为对于一个商业网站,每天几十万到上百万的访 
问量是很正常的,而且一般情况下每个http请求都会生存一段时间。实际上,一千左右 
的同时连接是重负荷服务器上的常见情形,这刚好达到了256的危险极限。 
   
  如同我们说的,用ulimit命令可以提升forks限制到512,但是再加大的话,意义已经 
不大,首先你必须修改系统内核源代码,其次是同时连接数在2000以上的时候,普通的 
x86服务器已经很难应付了。这时最合适的解决方法应该是使用服务器集群或者类似的技 
术(见后)。 
   
  不管怎样,如果你真的有一个非常高档的服务器,而你希望提升系统的forks进程数极 
限,你应该修改linux内核源码的include/linux/tasks.h,查找到这样一行: 
   
  #define NR_TASKS        512 
   
  把512改成较大的值。对于intel系列的CPU,建议你最大用到4090。进一步增加将导致 
系统无法引导。更改之后,重新编译内核,就可以使用大得多的forks极限了。 
   
  对于Apache的forks有一个特殊的问题,Apache服务器在启动的时候自动设置了自己能 
产生的子服务进程的数目限制,对于普通的版本,这个数目被设置为256,你应该自己加 
大这个数值,在apache源代码的src/include/httpd.h中你可以看到 
   
  #ifndef HARD_SERVER_LIMIT 
   
  #ifdef WIN32 
   
  #define HARD_SERVER_LIMIT 1024 
   
  #else 
   
  #define HARD_SERVER_LIMIT 256 
   
  #endif 
   
  #endif 
   
  将相关的HARD_SERVER_LIMIT从256改成512,然后重新编译apache,在apache的启动脚 
本中使用ulimit –u 512就可以了。 
   
  9.10 负载均衡和其他手段 
   
  作为一个服务器管理员,你当然希望永远不要改变服务器的架构。然而,你的服务器 
会接收越来越多的服务要求。尤其是电子邮件和www服务器,它们的性质也许不会有什么 
本质的变化,然而其数量却会以可怕的速度增长,上一节我们已经提到了由于请求数增 
加造成的可能问题,这一节我们考虑如果你的Linux系统已经无法应付巨大的服务请求时 
,你应该用什么办法处理问题。 
   
  9.10.1 反向代理和Apache本身的优化 
   
  我们已经熟悉了代理的概念。象squid这样的WWW代理程序,可以用来代理加速客户对 
外部世界的访问,也可以倒过来,用来缓冲来自外界的访问,提高WEB服务器对外界请求 
的相应能力。 
   
  在这种反向代理模式下面,squid运行在服务器的80端口接收外界世界的请求,然后把 
请求转交给Apache 的httpd程序。由于squid不需要forks,它对静止页面(一个网站中 
不包含cgi、SSI,PHP的部分,或者说不变的html文本以及图像)的处理效能要比apach 
e高得多。这样,Apache只需要处理那些cgi程序和服务器脚本就可以了。实际上,象No 
vell这样的公司也曾经使用过这种技术。 
   
  要把squid配置成为反向代理服务器,首先要配置它在80端口运行,这是通过配置/et 
c/squid.conf中的http_port行实现的: 
   
  http_port 80 
   
  一般情况下,squid只是耗费巨大的磁盘空间和内存,而对CPU的负担并不重,因此你 
可以把Apache服务器和squid放在同一台服务器上,这时,只需要用http_accel_host和 
http_accel_port告诉squid到哪里寻找真正的Web服务器。例如,我们把apache配置在同 
一台机器的82端口运行(利用Port,Bind和Listen语句),那么: 
   
  httpd_accel_host localhost 
   
  httpd_accel_port 82 
   
  当然,你也可以把Apache放到别的机器上: 
   
  httpd_accel_host  other_apache 
   
  httpd_accel_port 80 
   
  如果你想加速的是一个虚拟主机,那么还要加入这样的选项: 
   
  httpd_accel_host virtual 
   
  另外,我们原则上不赞成用squid同时做正向和反向的页面缓冲,如果你一定要这样做 
,那么,需要加入这样的配置行: 
   
  httpd_accel_with_proxy on 
   
  使用缓冲方式加速静态网页的服务是一种非常常用的技术,但是它只对静态页面有效 
,实际上,cgi常常是更严重的服务器超载的原因。实际上,对于cgi程序的加速目前并 
没有太好的办法,Apache开发者提供了两个能够起一定作用的模块,但是到底有多大的 
效果那只有试验以后才知道。 
   
  Fast-CGI是第一个附加功能。它使得每个CGI进程可以提供多次服务,大大降低了装入 
执行的次数。然而Fast-CGI不仅要重新编译Apache加入对应功能,更大的问题是你需要 
改写自己的CGI程序以便支持Fast-CGI标准,所以使用的不是很多。 
   
  许多CGI程序是Perl写成的,对于Perl程序,Apache必须启动Perl解释程序来执行Per 
l代码,这要消耗相当多的服务器资源。为了提高Perl程序的执行效率,Apache模块的开 
发者提供了一个模块,称为mod_perl,这个模块将Perl解释程序嵌入到了Apache内部, 
因此可以无需调用Perl解释程序。如果要使用mod_perl,你需要自己下载源代码并且编 
译。 
   
  9.10.2 DNS负载均衡 
   
  如果一台服务器的性能无法满足要求,有两种基本的解决方法。第一种是使用功能更 
强大的系统。这个方法非常简单,问题是,如同我们熟知的那样,计算机的性能和其价 
格并不成正比。目前我们能够以个人机的价格买到十亿次的处理系统,而百亿次的系统 
价格通常要比这高几十倍甚至上百倍。 
   
  第二个解决问题的方法是使用某种分布式处理机制。在服务器的场合,这种技术特别 
有效,你只要把应该由一台机器负责的服务分摊到若干个机器。这种技术称为负载平衡 
。 
   
  负载平衡的关键是如何自动分摊服务,最基本的方式是利用DNS的一个特性,我们现在 
来考虑这样的一种情况:在域名数据库文件中,一个名字指向多个IP地址: 
   
  www1          IN      A     202.199.248.100 
   
  www1          IN      A     202.199.248.101 
   
  在这种情况下会发生有趣的情况,当你向名字服务器查询www1的IP地址的时候,名字 
服务会返回这样的信息: 
   
  $ nslookup 
   
  > www1 
   
  Server:  linux.asnc.edu.cn 
   
  Address:  202.199.248.11 
   
  Name:    www1.asnc.edu.cn 
   
  Addresses:  202.199.248.101, 202.199.248.100 
   
  > www1 
   
  Server:  linux.asnc.edu.cn 
   
  Address:  202.199.248.11 
   
  Name:    www1.asnc.edu.cn 
   
  Addresses:  202.199.248.100, 202.199.248.101 
   
  返回的信息并不是按照域名数据库的次序排列,而是选择一个随机的顺序。这样,如 
果你访问www1这个地址,按照你查询域名服务器的时间,域名服务器会随机地返回一个 
IP地址。这样,只要保证两台服务器的文件相同,请求就会随机地分配到某个服务器上 
去。 
   
  为了使得这种随机返回IP地址的功能有效,必须让客户端机器不断查询对服务器负责 
的DNS。由于DNS缓冲的问题,我们应该把DNS中设置的缓冲刷新时间设的小一点,一般对 
于大型商业站点,可以把刷新时间设置在1-2小时左右。 
   
  另外一个重要的应用是电子邮件的负载平衡机制。我们讲过,在发送电子邮件的时候 
,各种smtp传输代理会查询目标机器的MX记录以便找出可以使用的MX交换器。如果一个 
地址有多个MX记录,那么smtp代理程序会自动选择优先数最高(数值最小)的MX机器发 
送信件。 
   
  如果对某个地址有多个MX记录具有相同的优先数,DNS将把它们全部返回,然而顺序是 
随机的,当你向这个地址发送信件的时候,smtp代理将选择排在前面的记录,这样,只 
要将几台MX交换器设置成同样的优先数并且正确地设置DNS刷新时间,就可以实现smtp交 
换的负载均衡。 
   
  在电子邮件传输的情况下有一些特殊问题。对于WWW服务,我们可以简单地将各个服务 
机器的内容设置成一样,但是对于smtp主机,信件随机地发送到各个机器上就改变了文 
件系统的内容。在传统上,建议你用qmail+NFS解决这个问题,例如,将所有用户的宿主 
目录都放在一台NFS服务机器上,然后在每一台接收邮件的服务器上都将这个机器的共享 
目录mount成/home。这样就可以解决困扰的文件同步问题。原则上,也可以设置sendma 
il共享/var/spool/mail和/var/spool/mqueue做类似的工作,不过由于sendmail的工作 
方式问题,这种做法比较容易丢失信件。 
   
  无论哪一种基于DNS的负载均衡方式,都有一个共同的问题,就是一旦服务器组中有一 
台出现了问题,那么所有被分配到这台机器的服务都会就此失败,结果表现为服务器的 
时好时坏。而其即使你修改了DNS从负载分配表里面除掉了相应的机器,这个操作也要等 
DNS刷新之后才能起作用。 
   
  尽管如此,现在几乎所有的大型站点都使用了这种负载均衡技术,例如yahoo,micro 
soft,novell,IBM等等。 
   
  9.10.3 NAT和集群服务器 
   
  另外的一种负载平衡的手段是通过反向的IP代理,或者说,基于NAT。NAT的概念我们 
比较熟悉,即利用一台机器对于内部的机器进行IP地址翻译,内部的整个私用网络被映 
射成一个地址,这个地址上的网关机器代替整个私用网络对外访问。 
   
  反向NAT的办法是把上述的过程颠倒过来,用网关提供负载均衡功能,当网关接收到外 
界请求的时候,自动把请求交给内部私用网络上的服务器,在私用网络上放置多台服务 
器,至于服务器之间的负载分配由网关机器完成。 
   
   
  集合上面说的各种技术(页面代理,反向代理,DNS等等),可以制作出更复杂也更强 
大的负载均衡系统,这种系统称为集群服务器。不过,我们一般建议你不要自己制作比 
DNS平衡更复杂的体系,因为目前市场上有商品化的集群服务器产品。 
   
  目前,在国内能够买到的适用于Linux的主要集群服务器产品是TurboLinux公司的Tur 
bo Cluster Server,它能较好地实现容错,负载的动态分配,系统扩展等功能。目前的 
报价是人民币28400元,作为服务器软件来说价格并不贵,我建议你如果要建立一个超级 
庞大的站点的话,你可以考虑这个产品。 
 
   
   
 
-- 
当我越过无尽虚空的时候,我看见星辰的欲望,光荣和毁灭,这是光辉世界的宿命, 
一切的一切,最终必将落入黑暗和虚无。 
所以,我随着星光飞翔,去逃脱必然的终结,也许有一天,我将回到世界的原初, 
等待新的星辰的诞生。 
尘埃是星的起源,星的终结。 
 
 
※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.112.90.20] 

BBS水木清华站∶精华区