Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1040768
  • 博文数量: 46
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1701
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-24 10:06
文章分类
文章存档

2014年(19)

2013年(27)

分类: 网络与安全

2013-10-17 18:54:27

2.4 程序的执行问题

Linux的多用户说完了,还需要进行下一个话题,那就是多任务的问题。所谓多任务,就是同一时刻能够执行多个程序。这个问题其实对于大多数Windows用户它都不是个问题,因为我们经常会一边浏览网页,一边用QQ聊天,同时还能听音乐。因为Windows可以在将这些软件的界面同是展现在屏幕上,即便放不下,也可以通过“窗口”堆叠的方式堆起来。要用哪个就将哪个放到最上面好了。Linux在使用图形环境下的时候也是这样,所以没有什么要专门拿它来说一说的必要。但是在命令行下这就真是一个问题了。比如你知道如何在命令行下同时运行多个程序吗?同时开几个终端的做法您就别耍这个小聪明了,因为那个不算。接下来我们就要看看Linux是怎么解决这个问题的。

2.4.1 执行程序的方法

如果只是简单的在命令行上执行一个程序则是一个非常简单的问题,基本上有一些计算机常识的人都应该能够猜到,直接输入程序的名称就能执行程序。没错,Linux就是这样设计的,而且我们之前执行的那些命令,绝大多数都是具体的程序,而命令名也就是具体的程序名。如果你根据这个经验,当你要执行当前你所在的目录下的一个可执行文件时,可能会不假思索的直接输入程序名以期望它的执行,因为Windows就是这样设计的。但是,在Linux你可能会收获失败,因为Linux与Windows的设计是不同的。当我们直接在命令行下输入命令之后,Linux系统只会在$PATH环境变量所指定的那些路径中搜索对应的程序(Windows会先搜索一下当前目录,再搜索$PATH所指定的目录),如果找不到就失败。如果要执行不在$PATH所指定的路径中的程序,必须使用相对路径或绝对路径。所以,即便是在当前路径下的一个程序文件,比如abc.exe,则需要使用./abc.exe。根据使用Windows的习惯,执行型文件的扩展名是可以忽略的,但是Linux根本不需要扩展名来决定文件的可执行性,所以也不能忽略所谓的扩展名。

但是像我们前面给出的cpio程序执行的例子又是我们遇到的一个新问题,因为它的形式比较古怪。比如我们要将/boot目录下的所有文件打包成一个文件,我们可以执行这样的命令:

$ find /boot | cpio -ocB > /tmp/boot.img

这条命令一共包含了两个不同的命令程序——find和cpio。那是不是这两个命令程序会同时执行呢?答案是肯定的。这就体现出Linux系统多任务的特性了,而且还体现出Linux系统多任务可协调的特性,即多个任务之间是能够互帮互助的。两个命令之间的竖线“|”就是起这种协调作用的,比较专业的称呼叫“管道符”,而这种程序直接的协调技术也被称之为“管道”,更为专业的名称叫“匿名管道”。

管道是Linux系统提供的多任务协调机制的一种,应用十分广泛。管道可分为匿名和命名两种,但是不管怎样它们都拥有一个共同的特性,就是数据只能从管道的一端写入并从另一端读取,而且读出的顺序与写入的顺序是相同的。所以管道也叫做FIFO(First Input First Output)。那么匿名和命名管道有什么区别呢?其实就是临时工和正式工的差别。所谓匿名就是不记名,随用随叫,属于临时工;而命名的则需要分配固定的资源,有固定的岗位和编制,不管你用还是不用它都得在那儿,除非你将它除名才行,所以是正式工。就我们前面的例子,使用竖线“|”建立的管道就是匿名的临时工,而要建立命名管道则需要使用mkfifo命令,它会在我们指定的路径上创建一个文件类型为“p”的文件。其实这年头正式工是越来越少的,很多事情都是临时工干的,Linux这点还是非常与时俱进的。

我们再回到前面列举的例子,find命令处于管道的写入端,cpio命令处于管道的读取端。通过单独执行“find /boot”命令我们可以了解它将/boot目录下的所有文件都显示在屏幕上了。在本例中,这些原本要输出到屏幕上的内容不见了。去了那里了呢?管道里。然后“流到”了cpio内部,并被统统打包压缩到了/tmp/boot.img文件中。但是这就更让人糊涂了,怎么好端端的往屏幕上输出的内容跑到管道里去了呢?这就引出了Linux中的另外一项技术——I/O重定向。

I/O重定向也是Linux提供的一种多任务协调机制。所以的I/O冲定向,就是把输出给A的东西重定向给了B,或者反过来说将要从A处获得的输入重定向到B处去获得了。在我们的例子中正反两种重定向都应用了,而且还应用了隐式重定向和显示重定向两种方式。隐式重定向发生在“匿名管道”处,find命令将输出给屏幕的东西重定向给了管道写入端,而cpio命令要从键盘获得的输入重定向到了管道读出端。这样,find和cpio就建立数据通路,find查询出来的文件名源源不断的送给cpio来处理并将对应的文件打包起来。而在cpio处应用了一个显示的重定向,就是右尖括号“>”,它显示的指明将命令输出到屏幕的内容重定向到磁盘文件中。我们的例子就是将cpio的输出内容重定向到/tmp/boot.img文件中保存起来。顺便说一句,由于命名管道也是创建了具体的文件,所以使用命名管道时对其读写应该使用显示的I/O重定向。

通过上述内容的介绍,大家是否已经有所察觉,在这个例子中find和cpio就像流水线一样在加工数据。其实我们如果愿意,还能够在这条流水线上继续增加元素。比如我们要对cpio打包的文件还要进行压缩,可以执行这样的命令:

$ find /boot | cpio -ocB | gzip -9 >/tmp/boot.img

这就会有三个命令程序一同运行了,并且数据从find开始,流过cpio打包,流过gzip进行压缩,最后流向/tmp/boot.img文件。整体犹如行云流水连绵不绝。所以这种程序执行方式也有一个十分贴切的名字——流式处理。

还有一个重定向符是左尖括号“<”,它显示的指明将一个文件的内容重定向到键盘输入中。那么对于cpio命令来讲,在做解包的时候,应该这样操作:

$ gzip-dc /tmp/boot.img | cpio -idc

Linux上的大多数程序都支持这种流式处理,而且这种流式处理可以让若干简单的命令结合起来去完成很多让人无法想象的复杂任务。这也正是Linux迷人的地方所在,到处都是“只有你想不到没有它做不到”。而且要想你的程序也支持这种流式处理也是非常简单的,只要从键盘获得输入,然后将结果输出到屏幕上就基本可以满足要求了。更为具体的,本书后续章节还会有详细论述。

虽然流式处理可以允许多个程序一同执行,但是这些都是一些相关联的程序。如果我要同时执行一些不相关的程序,而且还希望像在图形界面中那样能够来回切换该怎么处理呢?这就要涉及到了前后台任务了。

所谓前台任务就是当前与我们交互的程序,而后台任务就虽然执行着但是不与我们交互的程序。与图形界面不同,在命令行下,前台任务是我们唯一可见的任务。后台任务要想成为前台任务,必须先当前的前台任务切换成后台任务。把当前任务切换成后台任务需要使用快捷键“Ctrl+Z”。比如执行命令:

$ tail -f /etc/profile

之后,按下快捷键“Ctrl+Z”,就会看到输出这样的内容:

[1]+ Stopped tail-f /etc/profile

然后执行命令:

$ bg

[1]+ tail -f /etc/profile &

这就代表我们已经将刚才创建的前台任务切换到后台了。而我们想直接创建一个后台任务,也可以直接在命令末尾添加“&”符号来完成,例如:

$ tail -f /etc/bashrc &

[2] 29732

……

然后轻轻回车,就可以继续做其他的事情了。经过上述的两个过程,我们已经创建了两个后台任务。如果要查看这些任务,可以使用jobs命令,例如:

$ jobs

[1]- Running tail -f /etc/profile&

[2]+ Running tail -f /etc/bashrc &

注意前面的[1]、[2]这些数字,这是是任务号,要想将某个后台任务切换到前台,就用利用这个任务号了。切换命令是fg。例如:

$ fg 1

tail -f /etc/profile

这样,“tail -f /etc/profile”就被切换到前台了。还有注意任务号后面的那个“+”和“-”。带有“+”的任务属于默认任务,即执行不带任何参数执行fg命令时切换到前台的任务。

对于如何结束一个处于前台的程序恐怕大家都不陌生。要么等它执行完毕,要么就按“Ctrl+C”干掉它。但是对于被切换到后台的程序“Ctrl+C”可就不管用了,难道我们要结束这样的程序就只能等它自己执行完毕或者切换到前台吗?不是,Linux下还有第三种选择,就是使用kill命令干掉它。比如我要干掉2号任务,可以这样操作:

$ kill -9 %2

$ jobs

[1]- Running tail -f /etc/profile&

[2]+ Killed tail -f /etc/bashrc&

需要注意,kill命令是传递信号给具体的任务或进程,-9就是一个信号。这个信号相当霸道,会强制干掉一个不正常的任务或进程。而kill默认发出的信号实际上是-15,这个信号会使得程序正常退出。至于有关信号方面的信息,本书后面的内容还会有详细介绍,等不及的人可以执行“man 7 signal”命令提前学习。另外,kill最后面的那个参数实际上是传递一个数字的进程ID,但是这与任务号有冲突,所以要加上%来加以区分。

刚才说的是要干掉某个任务,但是还有一个十分棘手的问题就是不希望任务被无故干掉。任务在什么情况下会被无故干掉呢?你退出终端的时候就会。因为Linux下任务是与操作者终端关联的,只要你退出了终端,与其关联的所有任务都会被干掉。但是有些时候你又不能总是守在终端前,还不想任务被干掉,怎么办呢?使用nohup命令,它能保证被他启动的任务脱离与终端的关联。一般的用法是:

$ nohup [命令与参数] &

需要注意,这样命令的所有输出都会输出到nohup.out这个文件中,但是这个任务就不再与你的终端有什么联系了。放心的关掉终端回家陪老婆去吧!

上述的过程就基本梳理出了Linux进行多任务使用和切换的方法,虽然要比Windows等图形界面上的体验要差很多,但是在执行少量任务的时候还是比较方便的,毕竟Linux的设计目的不是让你来回切换任务玩的。它是从正面鼓励你使用流式方式执行程序的,所以要很好的掌握管道和I/O重定向的技巧。

2.4.2计划任务

使用计划任务是在Linux下执行程序的另外一种方式,分为一次性的和周期性的两类。

执行一次性的计划任务需要使用at命令。每次执行at命令需要给他传递一个时间参数,来指明计划任务执行的时间。比如:

$ at 10:00 tomorrow

这条命令要求明天上午10点整执行一个程序。那么怎么设定具体要执行什么程序呢?要知道答案就地继续往下看。就在执行at命令之后,命令行会变成这样:

at>

只要直接输入想执行的命令即可,比如echo "hello world"。输入完命令之后,按组合键Ctrl+D来保存。然后就会立即显示类似这样的内容:

job 1 at 2012-12-20 10:00

这说明“job 1”将在2012年12月20日的10点整执行。这样,你就成功的创建了一个一次性任务。需要注意,我们在列举这个例子的时候有些偷懒,主要是echo这个命令我们没有提供全路径。这并不是不对,而是不很规范。因为直接使用名称来执行程序能够成功的根本是因为有PATH环境变量。如果PATH环境变量没有设定,那么所有直接使用名称执行的程序都会失败。虽然我们平时很难遇到PATH环境变量没有被设置的情况,但是在计划性任务中确很常见,所以使用全路径来执行计划任务是非常良好的习惯。为此,我们的例子应该改成“/bin/echo "hello world"”,这样虽然看起来不是很美观,但是总是能够保证它被执行成功。而且每个计划任务也不是只能执行一个程序,也可以是一个按行划分的程序列表,待执行任务时,按程序出现的次序依次执行。

不知道你是否注意到,at命令在接受完输入的时候使用了比较有特点的Ctrl+D命令来保存内容。在Linux中Ctrl+D代表EOF,说明已经输入完毕。但是这种EOF仅对直接从键盘中获得输入的情况下有效,即输入Ctrl+D之后,代表从键盘中获得的输入完毕了。所有的这种从标准输入获取输入数据的程序都可以使用类似方法输入数据。但是这种录入数据的方法有一个缺点,就是一旦中间有错误,就只能全部重来。为了弥补这个缺点,可以使用I/O重定向将一个文件中的内容输入给它,我们要做的就是编辑好那个文件的内容。就比如这个例子,我们可以先创建一个包含命令的文件然后我们就可以使用“<”操作符将文件的内容传给它,并称为一个新的计划任务,而且你再也不会看到“at>”这样的提示符了。

一般一次性计划任务是很少应用的,大多都是周期性计划任务。这也就时很多人都会听过大名鼎鼎的cron,而很少了解at的根本原因。

使用cron都是通过crontab命令来完成的。“crontab –e”来编辑当前用户的cron表;“crontab -l”查看当前用户的cron表;“crontab –r”删除当前用户的cron进程;“crontab -u 用户名”以某用户的身份来控制cron表。这些基本上就是操纵cron的全部了。

为了创建一个周期性任务,需要使用“crontab –e”命令来打开cron表。这个命令会启动vi程序来编辑cron表,具体如何使用vi,本书后面会有专门的章节来介绍,目前只需要按一下“i”键进入编辑模式即可。

一个cron任务在cron表用一行来表示。每一行被分为两列,左边是时间,右边是具体运行的命令,与at相同,尽量使用命令的全路经。时间是由5个部分组成,每部分用空客隔开,分别代表:

l每小时的第几分钟:0~59;

l每天的第几小时:0~23;

l每月的第几天:0~31;

l每年的第几月:1~12;

l每周的星期几:0~6,0表示星期日。

此外,在时间和命令之间,还有一个可选的用户名,用来说明cron以何种用户身份来执行命令。因此,一个cron任务的完整定义应该是:


分钟小时日月周 [用户名] 命令


如果要设定在我太太生日那天,每到整点就提醒我买礼物,那么可以在cron表中添加如下一条:

0 * 1 8 * echo "老婆大人的生日,要买礼物。"

然后按“ESC”键退出到命令模式,输入“:wq”,退出并保存。这样,每到8月1日,整点就会提醒我。但是,我突然发现整点提醒我有点太宽泛了,甚至0点就开始提醒我。这有些不妥,干脆做了一下修改:

0,15,30,45 12 1 8 * echo "老婆大人生日,要买礼物。"

这样,只有8月1日的中午12点,每隔15分钟,会提醒我一次。这个设定显然不错,但是对于有代码洁癖的我来讲,还需要改进一下:

*/15 12 1 8 * echo "老婆大人生日,要买礼物。"

作用没变,显然简洁了一些,我很满意。

通过上面的这些内容,可以比较直观地看出,cron表中的时间设定拥有极高的灵活性,使得设定周期任务非常方便。每一个时间参数可以有几种符号表示,如表2-1所示:

表2-1cron时间符号

符号
    

含义

*
    

代表任意时间

,
    

代表分隔出不连续的时间点,比如2,3表示2和3都行

-
    

代表连续的时间段,比如2-4表示2、3、4

*/n
    

表示每隔单位时间

虽然计划任务有时非常有用,但是也不是所有用户都能添加的,具体谁能添加计划任务,主要有系统中这四个文件来决定:at.allow、at.deny、cron.allow和cron.deny。其实不用解释也能猜到,以at开头的管at,以cron开头的管cron。而且这些文件是有互斥性的,即allow的deny不会同时存在。allow也叫白名单,deny也叫黑名单,所以在allow中的用户就允许指定计划任务,在deny中的用户就不允许指定计划任务。当前的大多数Linux发行版使用黑名单机制,对计划任务权限的管理相对很宽松。

2.4.3 守护进程

计划任务基本上就算介绍完了,还有什么不明白的就找那个“男”的问吧。那么接下来就要看看计划任务是怎么被执行的了,这主要归功于守护进程。

Linux服务器在启动时需要启动很多系统服务(其实Windows也这样),它们向本地或网络用户提供了Linux的系统功能接口,直接面向应用程序和用户。提供这些服务的程序是由运行在后台的守护进程(daemons)来执行的。

守护进程是生存期很长的一种进程。它们独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它们常常伴随着Linux系统启动时启动,关闭时关闭。linux系统有很多守护进程,大多数服务器都是用守护进程实现的。另外,某些守护进程还协助完成了很多系统任务,比如负责计划任务的atd和crond、负责打印的lqd等。

有些资料也把守护进程称作:“服务”,但严格意义上来讲还是有一些不同的,只是一般我们不用去强调它们的异同。如果一定要分出个是非来,那么“服务”是静态的概念,而守护进程是动态的概念。服务由守护进程提供。选择运行哪些守护进程,要根据具体需求来决定。查看系统中拥有哪些守护进程,或者说能够提供哪些服务,可以使用ntsysv命令(在RedHat或Cent OS中)。要成功执行这个命令,需要使用root权限。

实际上守护进程也是有分类的,可以按照它的启动和管理方式来区分,分为独立启动的stand alone和xinetd两类。

所谓的stand alone,从字面上的意思来看就是“独立”的含义。这种类型的守护进程有两大特点,一是可以自行启动运行而不需要利用系统其他机制来管理,二是启动之后会一直占用内存与系统资源。因而这种守护进程拥有了一个非常突出的有点:响应最快。stand alone守护进程非常多,常见的apache、mysql等都是。

至于xinetd是一种比较新型的守护进程。它由一个统一的stand alone守护进程来负责唤起。这个特殊的守护进程还有一个好听的名字——superdaemon。之所以会引入这种机制,就是因为stand alone会一直占用内存和资源会显得很浪费。所以一些喜欢精打细算的人就提出来按需分配这种概念。也就是说,当没有客户端要求的时候,xinetd类型的守护进程都是未启动,待有客户端要求服务是,super daemon才会去唤醒具体的xinetd守护进程。但是这种按需分配的机制的致命缺点就是不能及时响应。但是优点也非常鲜明。其一,由于super daemon负责唤醒各项服务,因此可以赋予super daemon安全管控的机制,这就类似网络防火墙的功能了;其二,也是它的设计初衷,即客户端的联机结束后就关闭不会一直占用系统资源。

大多数Linux发行版会将所有stand alone守护进程的启动脚本都放置在/etc/init.d/目录下,这是一个公认的目录。而Cent OS实际上是放在了/etc/rc.d/init.d/目录下了,而/etc/init.d只是它的一个符号连接。大家在记忆的时候,只要记住公认目录即可,那些发行版自己耍的小聪明就不要理会了。

直接执行某个stand alone守护进程的启动脚本会显示这个启动脚本的用法,比如“/etc/init.d/atd”这个脚本,会有这样的用法提示:

Usage: atd{start|stop|status|restart|condrestart|try-restart|reload|force-reload}

其中start、stop和restart这三个命令选项是最通用的,几乎所有stand alone守护进程的启动脚本支持,分别代表启动、停止和重启。

xinetd守护进程的配置文件放置在/etc/xinetd.d/目录下和/etc/xinetd.conf文件。一般不用关心xinetd.conf文件的内容。而/etc/xinetd.d中的每个文件代表一个独立的xinetd守护进程。比如rsync的配置内容如下所示:

# default: off

# description: The rsync server isa good addition to an ftp server, as it \

#allows crc checksumming etc.

service rsync

{

disable = yes

flags = IPv6

socket_type = stream

wait = no

user = root

server = /usr/bin/rsync

server_args = --daemon

log_on_failure += USERID

}

其中“disable=yes”代表该守护进程处于关闭状态。如果要开启rsync服务,只要改成“disable=no”即可。然后执行/etc/init.d/xinetd restart重启super daemon。这样,当有客户端请求rsync服务的时候,xinietd守护进程就会启动/usr/bin/rsync程序来提供服务。

虽然我们知道了如何开启一个xinetd守护进程,但是当客户请求rsync服务的时候,xinetd怎么就知道启动/usr/bin/rsync这个程序呢?答案在/etc/services文件中,在这个文件中我们会找到类似这样的内容:

……

rsync 873/tcp #rsync

rsync 873/udp #rsync

……

因为rsync对外提供服务的端口是873,而xinetd也会监听这个端口,当发现有客户端连接到这个端口上,根据/etc/services文件就了解到是rsync服务。然后根据/etc/xinetd.d/rsync文件中的内容判断是开启状态,于是启动服务。

2.4.4 程序信息

到目前为止,Linux下如何执行程序,程序都有那些存在形式都已经介绍完了,但是这些内容对于一个拥有多任务功能的系统还远远不够,还应该让用户能够了解到当前系统中运行着那些程序、都使用了哪些资源以及程序之间的关系是什么。ps、top和pstree这三个命令正好提供了这些功能。

ps命令主要是查看程序的静态信息,即将某个时间的程序运行情况撷取下来。比较常用的用法有:“ps aux”查看系统中所有程序的数据;“psux”查看当前用户所有程序的数据;“ps –l”查看与当前终端关联的程序数据。注意,有的有“-”,有的没有“-”。由于ps的man page非常复杂,所以大家只要记住我们提供的这三个常用用法基本上就能满足日常工作了。

对于“ps -l”命令,在我们的机器中执行的结果如下所示:


F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD

0 S 500 2570 2569 0 80 0 - 27134 wait pts/1 00:00:00 bash

0 R 500 10716 2570 0 80 0 - 26487 - pts/1 00:00:00 ps

这些字段的定义见表2-2所示:

表2-2“ps -l”命令输出的各字段说明

字段
    

说明

F
    

程序标志,代表程序的执行权限,常见的取值有:0,普通权限;4,root权限;1,此程序仅执行了fork而没有执行exec

S
    

程序状态:R,运行中;S,睡眠状态,可唤醒;D,不可被唤醒状态,一般是在等待I/O;T,停止状态,比如被调试的时候;Z,僵尸状态,程序已经终止但却无法被移除至内存外

UID
    

此进程拥有者的UID

PID
    

此进程的进程ID

PPID
    

此进程的父进程ID

C
    

CPU的使用率,单位为百分比

PRI
    

运行优先级

NI
    

运行优先级调整值

ADDR
    

指出该程序在内存的哪个部分,如果是个 running 的程序,一般就会显示“-”

SZ
    

此程序用掉的内存

WCHAN
    

表示目前程序是否运行中,若为“-”表示正在运行中

TTY
    

登陆者的终端机位置,若为远程登陆则使用动态终端介面

TIME
    

使用掉的CPU时间,注意,是此程序实际花费 CPU 运行的时间,而不是系统时间

CMD
    

就是command的缩写,也就是程序名称

虽然对照上表理解“ps -l”命令的输出不是什么难事,但是千万别以为这些就是全部了,因为“psaux”命令的输出还不太一样,具体可参考如下所示:

220340804.jpg

这下傻眼了吧?两个命令的输出内容有点不一样,所幸就再列一个表吧,见表2-3所示:

表2-3“ps aux”命令输出的各字段说明

字段
    

说明

USER
    

该进程所属的使用者用户名

PID
    

该进程的进程ID

%CPU
    

该进程所占CPU资源的百分比

%MEM
    

该进程所占实体内存的百分比

VSZ
    

该进程用掉的虚拟内存量(kbytes)

RSS
    

该进程占用的固定的内存量(kbytes)

TTY
    

该进程所运行的终端机,若与终端机无关则显示“?”。另外,tty1-tty6 是本机上面的登陆者程序,若为pts/0等等的,则表示为由网络连接进主机的程序

STAT
    

该进程的当前状态,与“ps –l”的S字段相同(R/S/T/Z)

START
    

进程启动时间

TIME
    

该进程使用CPU运行的时间

COMMAND
    

改程序的实际命令

有些时候“ps aux”命令输出的COMMAND字段会非常长,以至于被终端屏幕截断。解决这个问题的方法是使用more命令,就是这样使用:

$ ps aux | more

如果输出内容一屏无法显示完毕,more命令会在屏幕满是停止输出。按回车(enter)键,可以继续查看更多的内容,要退出可以按“Q”键。

给ps传递不同的参数会产生不同的输出结果显然是比较坑人的设计,但是这也是ps强大的体现。因为这样设计,可以使得ps命令很容易的与Linux系统中的其他命令结合使用(利用管道和I/O重定向),来实现更为复杂的程序信息观测程序。但也正因为ps要满足这样的需求,使得它存在一定的局限性,那就是只能撷取某一个时间点的程序状态。如果期望动态监测系统中程序的运行状态,可以使用top命令。顺便提一句,使用ps命令和Linux中的其它工具相结合,也能够实现类似top的功能。至于如何实现,相信读完本书的人应该能够自行完成。

top命令输出非常丰富,而且每隔5秒钟就会刷新一次。如下所示展示了top命令的大部分输出内容:

220435113.jpg

总体来看,top命令的输出共分为两个部分。上面的部分展示的是整个系统的资源的使用状态,而下面的部分展示的则是单个进程的资源使用情况。

top使用5行文本来描述整个系统的资源使用状态,显示的内容依次是:

l第一行:top - 当前时间 up 系统连续运行时间,已登录系统的用户数(3 users),系统在1、5、15分钟的平均工作负载(load average)。

l第二行:进程的总数、正在运行数、睡眠数、停止数和僵尸数。

l第三行:用户空间占用CPU的百分比(%us)、内核空间占用CPU的百分比(%sy)、改变过优先级的进程占用CPU的百分比(%ni)、空闲CPU百分比(%id)、I/O等待专用CPU的百分比(%wa)、硬中断占用CPU的百分比(%hi)、软中断占用CPU的百分比(%si)、被强制等待虚拟CPU的时间(%st,在虚拟系统中有效)。

l第四行:物理内存总数、已用数、空闲数、缓冲数。

l第五行:交换分区总数、已用数、空闲数、缓存数。

至于top所提供的单独进程信息,与前面介绍的ps命令所提供的信息基本类似,这里不做复述。不太一样的就是VIRT、RES和SHR这三个字段。它们分别代表虚拟内存用量(只是需要的,不是实际使用量)、常住内存量(实际使用量,包含共享部分)和共享内存。计算一个进程所占用的真实物理内存可以使用公式:RES-SHR来计算。

在top的上半部分输出中的cpu占比部分,有些时候会出现超过100%的情况。其实这是非常正常的,因为top计算的CPU占比是按照单个CPU核心来计算的,如果一个计算机内有16个CPU核心,那么这个CPU占比最高可以达到1600%。

top命令所展示的数据当中最让人迷惑的就是平均工作负载(load average)了。这是一个什么概念呢?我们可以做一个行车过桥的比喻。对于一个单核处理器,就好比是一条单车道。设想下,你现在需要收取这条道路的过桥费--忙于处理那些将要过桥的车辆。你首先当然需要了解些信息,例如车辆的载重、以及还有多少车辆正在等待过桥。如果前面没有车辆在等待,那么你可以告诉后面的司机通过。如果车辆众多,那么需要告知他们可能需要稍等一会。因此,需要些特定的代号表示目前的车流情况,例如:

l0.00,表示目前桥面上没有任何的车流。实际上这种情况与0.00和1.00之间是相同的,总而言之很通畅,过往的车辆可以丝毫不用等待的通过。

l1.00,表示刚好是在这座桥的承受范围内。这种情况不算糟糕,只是车流会有些堵,不过这种情况可能会造成交通越来越慢。

l超过1.00,那么说明这座桥已经超出负荷,交通严重的拥堵。那么情况有多糟糕?例如2.00的情况说明车流已经超出了桥所能承受的一倍,那么将有多余过桥一倍的车辆正在焦急的等待。3.00的话情况就更不妙了,说明这座桥基本上已经快承受不了,还有超出桥负载两倍多的车辆正在等待。

由此可见,平均工作负载不能超过1.00,超过了就说明系统已经快要不堪重负了。但是很多人的实际经验是经常看到查过1.00的情况。其中一种与CPU占比相同,与核心数量有关。如果是16核心的系统,平均工作负载可以达到16.00;而另外一种则是系统已经不堪重负了,虽然依然能够运行,但这个只能从侧面说明Linux系统的稳定性很好了。

top命令还有很多选项可用,其中比较重要的是“-d”选项,用来修改top刷新数据的频率的。top命令还能单独最终某个进程的运行状态,方法就是使用“-p”选项,例如:

$ top -d 2 -p 12201

就是表明每两秒刷新一次,只监控PID为12201的进程。top在运行中,也有一些按键可以操作,比如:P键,让单个进程信息按照CPU使用率排序;M键,以内存的使用率排序;N键,以进程的PID排序;等等。

ps和top命令可以很方便的获得单个进程的信息。如果要查看进程的父子祖先关系,虽然ps命令能够满足,但是最方便的应该是pstree了。至于是什么的效果,你直接操作一下就好了,毕竟浪费纸张是一件十分可耻的事情。
阅读(2302) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~