2.3 进程、线程
AIX操作系统属于多任务系统,允许同时执行多个程序。那么程序和进程、线程有什么关系?
2.3.1 进程、线程、优先级概念
系统中执行的程序被称为进程。为了提高运行效率,进程可以被拆分成多个线程执行(需要程序本身支持,采用多线程编写方式编写),每个CPU在同一时刻,只能执行一个线程,一个线程执行完毕退出(或者自己主动进入睡眠状态)、线程等待其他外设(IO操作)、有更高优先级的中断发生(在vmstat命令输出中表现为一次in,即一次Interrupt)、或者达到了此线程最大允许运行时间,操作系统就会强制进行线程切换(在vmstat命令输出中表现为一次cs,即一次Content Switch),让CPU去执行另一个线程。
在AIX操作系统中,所有等待执行的线程都放在运行队列里面,每隔10 ms,操作系统重新计算线程的优先级(也就是每隔10ms,线程的执行顺序会重新排列),CPU优先执行队列前面的几个线程(每个CPU执行一个线程,n个CPU的系统则可以同时执行队列前n个线程)。如果CPU正在执行一个线程,此线程的优先级在计算时就会被降低(当使用默认的调度模式时),因此如果一个线程长时间占据CPU,它的优先级会越来越低。如果下一次优先级计算的时候,另一个线程的优先级高于此线程,则CPU就会将此线程“踢”到等待队列里面(执行队列中靠后的位置),而去执行另一个更高优先级(执行队列中靠前的位置)的线程。线程本身也会由于IO、任务执行结束休眠等原因,自己降低执行优先级,而进入等待队列。
一个4 CPU的系统可以用这样的情况来比喻:这是一个有人监督管理的排队队列,有4个窗口在进行处理,每个窗口有2个工作人员,一个审核,一个盖章(这就是4个CPU开启了SMT的情况)。这样这个系统可以同时让8个人到窗口(相当于8个线程),但是由于窗口只有4个,所以前4个人能够递交审核,另外4个需要稍等片刻。审核的时间有长有短,以第一窗口为例,审核结束,交给盖章的人处理,这是第二个人就可以递交自己的文件等待审核,而第一个人要等待文件盖章,任务还没有执行完。这就是SMT启动的情况:有时可以并行两条指令,有时则不行。
可能第二个人审核的时候,发现材料不全,要求他再准备(这就是等待IO),这个人就只好排到队列后面,慢慢找材料(进行IO处理),系统又可以分派一个人到第一窗口。此时第一窗口盖章工作结束,第一个人拿着完整材料退出(相当于执行完操作),又有一个新人被指派到第一窗口。也就是永远都有两个人在一个窗口(一个CPU),这就是SMT的功能。
我们再来看那个准备材料的人,假如他已经准备好,此时就可以向管理队列的人申请“加塞儿”(提高优先级),管理人员看到他是由于准备材料而离开,则允许插队,从队列的后面插到队列前面,那么下一个空闲窗口处理的人就可能是他。
要是此时又进来一个人,拿着领导批条(也就是更高优先级的中断产生了),管理人员不敢怠慢,甚至让当前正在处理的一个窗口停下来,先把他撵回队列(在队列中的位置根据已经处理的时间长短决定,如果已经处理了很长时间,则排在队列靠后,否则靠前),让这个优先级高的人先处理。
实际情况与以上排队情况类似如图2-7所示,优先级总计128级,0为最高级,127为最低级,虽然是一个大队列,但是在每个级别可能有多个等待线程,当轮到此优先级线程执行的时候,具有相同优先级的线程按一定顺序关系(线程调度规则)先后执行。
优先级少于40(优先级较高,数值越低优先级越高)的线程为系统内核线程。每个普通线程的默认优先级是60,通过nice命令可以增加或者减少优先级,上下幅度为20,这样一个普通程序的优先级可以在40~80之间的变化范围。除了nice之外,还有一些数值是由占用CPU时间片产生的所谓CPU惩罚值确定的,占用CPU时间片越长,优先级越低。
图2-7 AIX线程调度中的128级优先级和等待队列
问题:是否系统CPU越多,程序执行越快?
答案:不一定。由于CPU最小执行单位是线程,因此即使某个程序负载很大,需要消耗大量CPU计算能力,但是如果此程序不能拆分成更多的线程,则尽管有很多CPU,也只能闲置。不过通常系统不止一个程序在执行,有很多操作系统的调度程序、设备驱动程序,都需要CPU执行,因此一般情况下,增加CPU数量会让分配给这个单线程程序的CPU时间片不会被别的任务抢占,从而间接提高程序的计算速度。不过由于只是辅助作用,更多的CPU对程序执行速度提升的效果会越来越不明显。
操作系统有几种调度模式和参数控制线程优先级,在默认模式下,通过修改这些参数(使用schedutune命令),能够对CPU执行线程情况产生很多影响:
(1)加快线程切换速度,对OLTP(OnLine Transaction Process在线交易,例如银行窗口,需要交互输入输出)一类业务有好处,可以让交易更快地得到响应。方法是通过参数加快占据CPU资源的线程的优先级衰减,尽快进行进程切换。
(2)延长每个线程执行时间,有益于计算性业务(大量查询、报表、统计、科学计算)。由于每次切换都有不必要的操作系统处理,让每个线程执行时间最长可以更快速完成线程的工作。
(3)将某个进程(及其线程)与某个CPU绑定,防止此进程的过渡耗费系统CPU资源,将其占用量限制在某(几)个CPU。
而AIX系统有更多的预先定义的进程调度规则,影响具有相同优先级的进程(队列):
(1)SCHED_FIFO,先进先出模式。如果设定此种规则,则线程会持续执行,直到自动退出、被终止或者更高优先级的线程需要执行。只有固定优先级线程才可以使用此方式。
(2)SCHED_RR,循环模式。如果某个线程用完CPU时间片,将被扔到队列中的最后排队。也是只有固定优先级的线程才能使用这种规则。
(3)SCHED_OTHER,这种策略在POSIX标准1003.4a中定义,每个时间片后都重新计算线程优先级。
(4)SCHED_FIFO2,与SCHED_FIFO相同,除了一点:只允许某个线程处于队列首位一定的时间,而不允许无限期执行它。此策略的意思是尽力保证执行此线程,但到了一定时间还是禁止它永远占据CPU。这个时间可以用schedtune –a参数控制。
(5)SCHED_FIFO3,属于SCHED_FIFO3策略的线程永远占据执行队列首位(在同一优先级队列中),为了防止属于SCHED_FIFO2规则的线程占据在属于SCHED_FIFO3规则线程之前,一旦一个SCHED_FIFO3线程进入队列,队列规则参数即被修改,以阻止SCHED_FIFO2规则对此优先级队列起作用。也就是说,FIFO3的线程会屏蔽属于同一优先级的FIFO2线程。
(6)SCHED_FIFO4,SCHED_FIFO4规则使即使有高优先级线程进入队列,如果低优先级线程只比它低一个等级(优先级数字多1),那么低优先级线程仍将继续占据此CPU。
控制命令(AIX 5.2以前版本,注意,数字越小,优先级越高):
#/usr/samples/kernel/schedtune → 控制CPU线程调度参数 -t → 修改时间片大小 -r -d → 配合使用修改线程优先级衰减控制
比较小的r使得线程优先级计算变化范围缩减,nice对程序的优先级控制更加明显;
比较大的r则相反,线程优先级计算变化跨度加大,nice作用更为不明显;
比较小的d增大了CPU惩罚值,加速线程切换;
比较大的d减少了CPU占用惩罚,降低线程切换。
-D → 将所有的schedtune参数都恢复为默认值; #vmo → AIX 5.2以后提供的新命令,类似vmtune #schedo → AIX 5.2以后提供的新命令,类似schedtune #bindprocessor -q → 查看可用的CPU #bindprocessor 13039 3 → 将进程13039绑定到第3号CPU(不可以用其他的CPU) #bindprocessor -u 13039 → 解除对13039的绑定 #nice -5 vmstat 10 3 → 设定vmstat进程的优先级(降低5,从60降低到65) #nice --5 vmstat 10 3 → 设定优先级,提高5,从60提高到55) #renice -5 7569 → 重新调整进程7569的优先级(在原来基础之上提高5)
对于CPU的使用情况,可以通过vmstat命令查看:
#vmstat 1 5 →每个一秒显示一次,共显示10次系统状况。 System Configuration: lcpu=16 mem=31488MB kthr memory page faults cpu ----- ----------- ------------------------ ------------ ----------- r b avm fre re pi po fr sr cy in sy cs us sy id wa 4 2 3127273 3272 0 4 8 338 937 0 2357 22962 1561 13 1 83 3 5 3 3127257 1556 0 4 0 0 0 0 2890 15790 2165 20 0 59 21 2 4 3127903 958 0 7 4 1014 1673 0 2353 7290 1670 17 1 53 29 3 3 3127948 966 0 23 12 1392 2693 0 2620 7943 1779 18 1 62 19 3 3 3128040 968 0 43 7 1524 3643 0 2898 16537 2938 22 1 62 15
其中各项含义如下。
r:当前在队列中等待执行的线程数,如果这个数值经常非常大(例如达到2~5倍以上的CPU数),就说明系统中等待执行的线程比较多,可能存在性能问题。注意,对于大型应用系统,需要执行的线程非常多,所以等待队列中经常有个位数的数字是很正常的情况,并不是说只有等待队列永远是0,才说明系统的CPU满足了要求。
b:当前队列中处于等待状态的线程,由于IO(存储、网络)操作未完成,无法继续执行,必须挂起,此时CPU可以切换到另外一个线程操作。显然,如果有很多(大于2~5倍CPU数)线程处于b状态,系统就可能有IO瓶颈。
avm:Active Memory,而不是available memory!这是经常被理解错误的一项,它等于当前使用的物理内存和使用的交换区的总和减去作为文件系统缓存的物理内存,单位为4KB,即一个内存页。
fre:空闲的物理内存,单位为4KB。
pi:在vmstat两次检查间隔期间,系统将磁盘交换区读回物理内存页的数量。通常多是内存不够的表现。
po:在vmstat两次检查间隔期间,系统将物理内存页交换到磁盘的数量。越多代表系统内存越紧张,但偶尔出现的pi, po并不能说明任何问题,而且通常系统大量文件操作(例如文件系统备份/恢复,tar操作等),往往伴随着大量的pi, po,这都是正常现象。
re:pi/po,数值长期趋近于1,并且pi, po都很大,说明系统可能有thrash(抖动)的现象,即刚交换出去的内存马上又需要使用,必须交换回来,物理内存可能严重不足。
fr:代表在此段时间内,有多少不使用的物理内存被释放,可能是内存页被程序释放,也可能是已经将其内存交换到了磁盘。
sr:代表在此段时间内,由于有内存使用申请,而物理内存空闲不足,进行少内存页搜索的页数。此数值越大,代表内存申请越多,也就是内存需要量比较大。
cy:进行内存搜索、清理消耗的时钟周期,此数值越大,说明内存越紧张,操作系统用了过多的时间进行内存清理。当然,也有可能系统内的程序调度(起/停)过于频繁。无论如何,cy多大都说明当前内存使用、管理方面需要仔细分析。
in:中断次数,在此段时间内由各种不同原因产生的中断次数,中断的原因可能是CPU处理时间片到期、设备IO产生中断等。vmstat –i可以查看更详细的关于中断的信息
cs:上下文切换,对于一个CPU,当正在执行的线程与即将执行的线程不是同一个的时候,就会产生一个cs(Content Switch)。有三种情况会导致cs:当前线程等待资源(磁盘/网络IO完成),线程自己要求sleep或等待资源解锁;更高优先等级线程要求CPU;此线程用尽了10ms时间片。由于自然情况下,每CPU可以产生100次线程切换(10ms一次),所以cs次数除以vmstat的间隔时间,再除以CPU个数可以用来判断系统繁忙的指标之一,这个数字如果远远高于100(通常是10~20倍以内的比例,即每个CPU对应1000~2000次cs都算正常),则可能有CPU瓶颈。对于最新的P5系列CPU,由于支持SMT,一个物理CPU同时支持2个线程,则可以考虑再除2或1.5,以进行合理的判断。
sy:(在faults区的sy)此时间段内系统调用次数,用户程序执行过程中发出系统执行调用申请,以便普通用户请求核心操作,例如进行磁盘IO等操作。
us:系统中用户操作所占CPU时间百分比。
sy:(在cpu区的sy)系统中系统调用所占CPU时间百分比。
id:系统中CPU的空闲时间百分比。
wa:系统等待磁盘IO所占时间百分比(此时CPU闲置)。
问题:是否wa很高的时候一定有IO瓶颈?
答案:wa很高的时候不代表一定有IO问题(尽管通常如此),反之wa很低也不代表没有IO问题。因为最后这4个参数只是一个比例关系,例如如果系统IO性能很差,但同时CPU异常繁忙,则看到的wa并不很高。同样的IO负荷,如果换到比较快的CPU的机器上,wio就会增加(因为相对于CPU处理时间,IO占用时间的比例更大了)。
在进行了CPU共享(需要POWER 5并购买微分区功能才支持)的机器上,还有另外两项,pc和ec,pc代表实际分配给此分区的CPU数量(可能是小数,以1%为单位),而ec代表授权此分区使用CPU的数量与实际使用的比例(超出100时说明当前分区临时使用了超过了指派给它的CPU资源)。
2.3.2 查看系统进程情况
下面的命令可以看到系统全部进程情况:
#ps -ef
如果想看到各个进程占用CPU情况,可以用下面的命令:
#ps aux
以下命令查看用户guest的进程CPU使用:
#ps -lu guest F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 241801 S 200 7032 7286 0 60 20 1b4c 108 pts/2 0:00 ksh 200801 S 200 7568 7032 0 70 25 2310 88 5910a58 pts/2 0:00 vmstat 241801 S 200 8544 6494 0 60 20 154b 108 pts/0 0:00 ksh
其中,
PRI:进程/线程优先级。
NI:nice的设定值。
SZ等参数和进程使用的内存有关,在本书下一章节有详细介绍。
下面的命令可以看到系统全部线程情况:
#ps -kef
2.3.3 zombie(僵尸进程)
如果由于程序的原因,某个子程序的父进程一直没有收到子程序的SIGCHLD信号,即使这个子程序已经释放了所有资源(已经退出),但仍然占据着进程表中一个位置,这种程序被叫做:Zombie(僵尸进程),ps –ef结果中显示的程序名是<defunct>。
$ps -ef ....F S UID PID PPID C PRI NI ADDR SZ TTY TIME CMD 200003 A 0 1 0 0 60 20 500a 704 - 0:03 init 240401 A 0 2502 1 0 60 20 d2da 40 - 0:00 uprintfd 240001 A 0 2622 2874 0 60 20 2965 5208 - 0:46 X 40001 A 0 2874 1 0 60 20 c959 384 - 0:00 dtlogin 50005 Z 0 3776 1 1 68 24 0:00 <defunct> 40401 A 0 3890 1 0 60 20 91d2 480 - 0:00 errdemon 240001 A 0 4152 1 0 60 20 39c7 88 - 0:21 syncd 240001 A 0 4420 4648 0 60 20 4b29 220 - 0:00 writesrv 240001 A 0 4648 1 0 60 20 b1d6 308 - 0:00 srcmstr 50005 Z 0 10072 1 0 68 24 0:00 <defunct> 50005 Z 0 10454 1 0 68 24 0:00 <defunct>
只查看僵尸进程用如下命令:
#ps as <defunct>
如图2-8所示,进程由fork()函数启动,在Idle状态等待分配CPU资源,直到进入CPU执行队列而被激活;如果进程收到Stop信号,就被置于后台等待状态,而通过激活可以重新进入执行队列;进程执行一段时间之后会被交换出去在队列中排队,等待重新获得CPU;当程序退出时,会暂时处于Zombie状态,但正常情况下,很快就会彻底退出,如果不能完成退出动作,进程就变成了僵尸进程,永远存在于系统进程表中,直到系统重新启动。通常僵尸进程除了占用进程号之外,不会消耗其他的系统资源,例如CPU,内存,但并不能一定保证如此,因此如果系统中有很多僵尸进程,建议重新启动计算机以清除。
图2-8 进程状态、关系图
2.3.4 进程定时执行控制
另一种对于进程的控制是定时启动。cron守护进程可以用来定时启动进程,该进程的控制文件是crontab文件,存放于/var/spool/cron/目录中,以用户名为文件名,如root用户的crontab文件就是/var/spool/cron/root。AIX支持AT&T风格crontab文件,每条包含下列格式:
mm hh dd mm ww command
mm:分钟(0~59)
hh:小时(0~23)
dd:日期(1~31)
mm:月(1~12)
ww:星期的日子(0~6,从星期六到星期天)
command:需要执行的shell命令
如果希望多次执行,可以连续写多个分钟、小时、日期,中间用逗号隔开(注意无空格),如果此时间没有要求,则添加星号填充空位。
crontab –e可以编辑自己的crontab,使用何种编辑器取决于EDITOR变量值。从编辑环境保存并且退出后,crontab文件即时生效。使用crontab –l可以显示crontab的内容。
由于crontab的执行是由root用户进程调用的,因此执行的环境变量也是root用户的,建议在crontab执行的脚本中把相关的环境变量设置好,以防止执行时出现环境变量不匹配的问题。
crontab执行过程中,如果出现错误,将会向所有这账户发送邮件,该用户登录系统的时候会有You have new mail提示,可以用mail命令查看(子命令h查看标题,d删除)。