首页 > 代码库 > 七、Linux脚本进阶和进程管理

七、Linux脚本进阶和进程管理

一、进程


进程:init(1)-->系统的第一个进程,通过fork调用其他进程,自身由内核发起。

通过pstree可以查看进程之间的父子关系。

[root@localhost ~]# pstree
init─┬─NetworkManager─┬─dhclient
     │                └─{NetworkManager}
     ├─abrtd
     ├─acpid
     ├─atd
     ├─auditd───{auditd}
     ├─crond
     ├─cupsd
     ├─dbus-daemon───{dbus-daemon}
     ├─hald─┬─hald-runner─┬─hald-addon-acpi
     │      │             └─hald-addon-inpu
     │      └─{hald}
     ├─master─┬─pickup
     │        └─qmgr
     ├─6*[mingetty]
     ├─modem-manager
     ├─rsyslogd───3*[{rsyslogd}]
     ├─sshd───sshd───bash───pstree
     ├─tpvmlp
     ├─udevd───2*[udevd]
     ├─vmtoolsd───{vmtoolsd}
     ├─vmware-vmblock-───4*[{vmware-vmblock}]
     └─wpa_supplicant

1、进程的分类

内存地址空间分配使用情况说明

技术分享1

进程间通讯:IPC inter process communication

不同程序调用相同的库文件,就需要进程间通讯。

进程分为两类:

CPU-bound:CPU密集型进程

IO-bound:IO密集型进程

进程按处理时间分:

批处理进程

实时进程

交互式进程

2、进程间工作原理

进程切换

为什么要有进程切换

因为一个系统要提供多个进程同时工作,也就是多任务的概念,那么每个程序可能由多个进程组成,每个进程又分配了优先级和时间片,如果一个进程时间片用完,就要给另一个进程使用了,另一种情况是,一个进程的工作需要调用另一个进程来协助完成,再有就是被抢占。这三种方式都需要进程切换。

如何实现进程切换

进程进行切换前需要有现场保护的一个工作,对方进程完毕切换回来还需要一个现场恢复的过程。

进程如果需要切换到其他进程上需要由内核来完成,自己不能直接处理,这个时候就有了系统调用的概念,就是内核帮助进程完成某些工作,cpu的工作模式分为内核模式(ring0)和用户模式(ring3),内核会依据级别来确定是工作在内核模式上还是用户模式上,所以说有系统调用就必然有模式切换。

什么是模式切换?

就是在进行系统调用的时候产生的对cpu工作模式的切换,带内核工作完成后再将工作还给进程。

技术分享

模式切换不是上下文切换,什么是上下文切换呢?

上下文切换是指一个进程结束,执行另一个进程或者被抢夺的情况,称为上下文切换。

3、IO操作

什么是io(输入输出)

一个系统的运行,是要为人服务的,就是说人可以进行输入操作,并通过输出获得结果,这个就是io操作。

系统如何识别io的操作

io操作有很多,可以是键盘输入,批处理命令,远程操作等等,内核如何识别这些操作,并准确处理呢,

首先如何获取io操作,早期是通过忙等待的方式,就是保留一个资源给io接口,等待它的操作指令,第二种是轮询,定期查看io接口是否有输入操作。第三种是中断,就是当有io操作时发送一个中断信号给内核,要求内核处理,这里就可以知道io操作的优先级还是比较高的。

4、优先级

如何设置进程的运行等级?调度器!

         进程优先级:

               动态优先级

               静态优先级:100-139 数值越小优先级越高

                                     可以通过nice值来手动调整,-20,19。

                                     普通用户只可以调大数字,降低优先级。

                                      用法:nice -n # command

               实时优先级:调度实时进程,1-99 数值越大优先级越高

技术分享

5、进程的状态

ready、running、sleeping、stopped,zombie(僵死状态)

多cpu如何应用?

一个程序要运行,(只)开启一个进程的,通常一个程序是只有一个数据流的(按照程序编写的顺序自上向下执行),并只会占用一个cpu的内核,当有多个cpu同时工作的情况,如何利用cpu的优势呢,通常有两种情况:1、将多个进程分配到多个cpu内核上,每个内核就分配到了一定数量的进程,达到了合理分配资源的目的。2、如果只有一个程序占用大量的资源,要给他分配多个cpu内核如何操作呢,就是需要程序在编写的时候,允许多个数据流同时进行,这样在程序创建进程的时候,就可以在一个进程中创建多个线程,每个线程就是一个数据流。linux对线程的支持并不是很好,表现的最终形式就是轻量级进程,最终体现的还是“进程”哦。

基于线程的访问优势就是它是进程的子集,所有在访问重复资源的时候,不需要重复范围,可以通过其他线程上访问,更加快捷,非常适用于web服务。


二、进程管理


进程管理类的命令:

pstree、ps、top、vmstat、htop

1、pstree:查看进程树

[root@localhost ~]# pstree

init─┬─NetworkManager

     ├─abrtd

     ├─acpid

     ├─atd

     ├─auditd───{auditd}

     ├─automount───4*[{automount}]

     ├─bluetoothd

     ├─certmonger

     ├─console-kit-dae───63*[{console-kit-da}]


2、PS详解

ps:显示当前进程状态的命令;静态显示。

[root@localhost ~]# ps -efH

UID         PID   PPID  C STIME TTY          TIME CMD

root          1      0  0 May15 ?        00:00:01 /sbin/init

root        575      1  0 May15 ?        00:00:00   /sbin/udevd -d

root       2121    575  0 May15 ?        00:00:00     /sbin/udevd -d

root       2122    575  0 May15 ?        00:00:00     /sbin/udevd -d

root       1535      1  0 May15 ?        00:00:00   auditd

root       1569      1  0 May15 ?        00:00:00   /sbin/rsyslogd -i /var/run/s

rpc        1620      1  0 May15 ?        00:00:00   rpcbind


常用参数:

-a所有和终端相关的进程    

-x所有和终端无关的进程,用?来表示和终端无关

-u以用户为中心显示进程

-e:显示所有进程

-f:完整格式列表

            ppid:父进程号

-F:显示额外信息

            psr:表示运行在那颗cpu上

-H:显示进程间的父子关系

-o:自定义显示格式

进程条目:

        stat:

                   S:可中断睡眠状态,

                   D:不可中断的睡眠。

                   R:运行或可运行

                   T:停止

                   Z:僵死

                   s:session leader 一个进程的主要进程

                   l:多线程进程

                   +:前台进程

                   N:低优先级进程

                   <:高优先级进程

time:运行时长

command:进程发起者,命令

vsz:线性地址空间大小,非实际占用大小

rss:实际占用空间大小

%cpu:进程占用cpu时间比

paid:父进程号码

stime:第一次启动时间

time:运行时长

PSR:表示运行在多cpu的那个cpu内核上

u:以用户为中心显示进程的相关信息

TTY:

  控制台:/dev/console

  虚拟终端:/dev/tty1-6,

  模拟终端:远程连接的终端 /dev/pts/0

  串行终端:/dev/ttys

ps命令详解:http://www.cnblogs.com/wangkangluo1/archive/2011/09/23/2185938.html


3、pgrep详解

 显示指定的进程信息。

   -U:username 显示相关用户的进程

   -G:groupname 显示组的进程

   -l:查看指定程序或进程的进程号

[root@localhost ~]# pgrep -U root

1

2

3

4

5


4、pidof

显示某进程的进程号

[root@localhost ~]# pidof sshd

5449 1878


5、top详解

[root@localhost ~]# top


top - 01:18:07 up 19:56,  2 users,  load average: 0.00, 0.00, 0.00

Tasks:  99 total,   1 running,  98 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:   1004768k total,   230948k used,   773820k free,    33972k buffers

Swap:  2031612k total,        0k used,  2031612k free,    69424k cached


   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND          

     1 root      20   0 19364 1540 1228 S  0.0  0.2   0:01.32 init              

     2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd          

     3 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0     

条目详解

load average:每隔5/10/15分钟的队列长度。一般是一个小数

cpu:us:用户空间程序占用%

          sy:内核空间程序占用%,她与us的合理比例是7:3,就是us占70%,sy占30%

          ni:调整nice值

          id:cpu空闲%

          wa:(wait)等待磁盘io完成输入输出工作所占据的时间比例

          hi:硬件中断占据的百分比

          si:软中断占据的百分比

          st:被偷走的时间,虚拟机占用运行的时间

PR:优先级 priority

NI:nice值

virt:虚拟内存级

res:实际内存级

shar:共享内存优先级

s:状态stats

%cpu:自从上次刷新到现在cpu被此进程占用的百分比。


选项和参数:

top是交互式命令,通过输入不同的字母显示不同的信息,实际上就是条目的第一个缩写,比如

M:按内存空间占用大小排序

P:按cpu时间占用大小排序

T:按累计时间排序

k:杀死一个进程,输入后需要制定kill 后面的选项1-15,常用是9 强制杀死。

m、p、l用于是否显示抬头的相关信息。

q:退出

-d #:刷新时间

-b:批次显示

-n #:指定批次显示的次数

6、vmstat

查看服务器cpu使用情况,内存、虚拟内存使用情况和磁盘读写情况。

[root@localhost ~]# vmstat

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

 0  0      0 164752 1484028 449036    0    0     0   138   10   18  0  0 100  0  0

[root@localhost ~]# vmstat


procs:

r:运行或等待cpu时间片的进程的个数

b:被阻塞的进程队列的长度


memory:

swpd 虚拟内存(swap)已使用的大小,如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器。

free   空闲的物理内存的大小,我的机器内存总共8G,剩余3415M。

buff   Linux/Unix系统是用来存储,目录里面有什么内容,权限等的缓存,我本机大概占用300多m

cache cache直接用来记忆我们打开的文件,给文件做缓冲,我本机大概占用300多M(这里是Linux/Unix的聪明之处,把空闲的物理内存的一部分拿来做文件和目录的缓存,是为了提高 程序执行的性能,当程序使用内存时,buffer/cached会很快地被使用。)

si  每秒从磁盘读入(放到swap中的数据量)虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。我的机器内存充裕,一切正常。

so  每秒虚拟内存写入磁盘的大小(从swap中读取的数据量),如果这个值大于0,同上。

bi  块设备(磁盘)每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备,默认块大小是1024byte,我本机上没什么IO操作,所以一直是0,但是我曾在处理拷贝大量数据(2-3T)的机器上看过可以达到140000/s,磁盘写入速度差不多140M每秒

bo 块设备每秒发送的块数量,例如我们读取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO过于频繁,需要调整。

in 每秒CPU的中断次数,包括时间中断

cs 每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中,我们一般做性能测试时会进行几千并发甚至几万并发的测试,选择web服务器的进程可以由进程或者线程的峰值一直下调,压测,直到cs到一个比较小的值,这个进程和线程数就是比较合适的值了。系统调用也是,每次调用系统函数,我们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换,导致CPU干正经事的时间少了,CPU没有充分利用,是不可取的。

us 用户进程占用CPU时间的百分比,我曾经在一个做加密解密很频繁的服务器上,可以看到us接近100,r运行队列达到80(机器在做压力测试,性能表现不佳)。

sy 系统进程占用CPU时间的百分比,如果太高,表示系统调用时间长,例如是IO操作频繁。

id  空闲 CPU时间,一般来说,id + us + sy = 100,一般我认为id是空闲CPU使用率,us是用户CPU使用率,sy是系统CPU使用率。

wt cpu等待IO完成的时间。

st:被虚拟化偷走的时间

选项:


vmstat delay count:设置vmstat显示的刷新的时间间隔和显示次数 vmstat 2 2

[root@localhost ~]# vmstat 2 2

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

 0  0      0 164612 1484036 449036    0    0     0   138   10   18  0  0 100  0  0

 0  0      0 164612 1484036 449036    0    0     0     0   71   78  0  0 100  0  0

每个两秒显示一次,一共显示两次。

7、sar (system activity reporter)

用来收集、显示保存系统活动信息及报告。

-u:

-P:指定显示cpu的信息

linux sar命令详解

8、iostat:显示系统性能相关信息,硬盘读写情况

[root@localhost ~]# iostat

Linux 4.6.0 (localhost.localdomain) 2016年05月18日 _x86_64_(1 CPU)


avg-cpu:  %user   %nice %system %iowait  %steal   %idle

           0.03    0.00    0.14    0.02    0.00   99.81


Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

sda               1.75        25.03         2.41     592778      57170

dm-0              1.82        24.63         2.41     583402      57152

dm-1              0.01         0.11         0.00       2600          0



9、dstat -c 显示cpu详细 实时显示

[root@localhost ~]# dstat

----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--

usrsysidlwaihiqsiq| read  writ| recv  send|  in   out | int   csw 

  0   0 100   0   0   0|  151602B|   0     0 |   0     0 | 103   127 

  0   0 100   0   0   0|   0    28k|20671234B|   0     0 | 101    97 


  0   0 100   0   0   0|   0     0 |1612 452B|   0     0 |  80    79 


三、信号

引用信号的方法:通过数字、信号名、简写。

显示信号:kill -l

常用信号:

1:sighup:进程不用终止,而可以重读配置文件。对于在线服务可以使用。

2:sigint:中断正在运行的进程,相当于ctrl+c

9:sigkill:杀死一个进程

15:sigterm:终止进程,容许进程可以完成当前工作。

19:sigstop:停止

18:sig

命令:

1、kill -信号 pid

[root@localhost ~]# kill -9 9761

[root@localhost ~]# kill -sigkill 2119


2、killall -信号 进程名

kill是按照pid进行查找并按照信号要求做相应的处理,而killall是按照进程名进行查找并处理相关进程。

3、killall5 -信号 

对所有相关进程有效

4、调整进程nice值

nice -n # command  默认优先级是120

renice # pid 对正在运行的进程调整其nice数值

5、作业控制

前台送往后台可以使用ctrl+z,但属于停止状态,后台调到前台使用fg %作业号码

+:下一次后台要运行的作业

-:是在+作业运行完再运行的作业。

bg %作业号码 :让其在后台运行。

启动时,让作业直接在后台运行:command &

用户退出后继续运行作业:nohup command &

终止作业:

kill %作业号码

如果一个程序会产生多个进程,那么快速杀死多个进程的方法:

    1、killall,必须给出完整的进程名。

[root@node3.dtedu.com ~]# killall ha_logd


    2、pkill,简单给出进程名就可以,名称可以不完整。

[root@node3.dtedu.com ~]# pkill -9 heartbeat

[root@node3.dtedu.com ~]# /sbin/service: line 66:  2291 Killed                  env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}


[1]+  Exit 137                service heartbeat stop


    3、正则表达式杀死多进程。

[root@node3.dtedu.com ~]# kill -9 `pgrep crond`


5.1screen

当我们在运行一个程序需要很长时间的时候,可以使用screen,它的特点是用户退出后程序继续运行,并且可以切换到原来窗口中再次查看运行情况。

这里说一下detach(分离、断开),表示用户离开当前shell窗口,并将其放到后台继续执行。并通过screen -r重新登录(attach,附件、连接物)继续后面的操作。

下面实例终端中的


创建一个新的shell窗口,建议取一个名字,8506是进程号,可以通过kill杀死它。也可以使用简便方法直接在screen后面跟shell命令,比如:screen -r test vi ./gongbing.txt

[root@localhost ~]# screen -ls

There are screens on:

8334.pts-0.localhost(Detached)

8506.gong(Detached)#从shell窗口分离出来了,可以重新登录。

8580.cpfrom56(Attached)#表示此shell窗口并没有被分离出来,使用 screen -d 8506解决。

3 Sockets in /var/run/screen/S-root.


[root@localhost ~]# screen -S cpfrom56创建一个新的shell窗口

[root@localhost ~]# ps -axu |grep 8506

Warning: bad syntax, perhaps a bogus ‘-‘? See /usr/share/doc/procps-3.2.8/FAQ

root       8506  0.0  0.1 118776  1556 ?        Ss   16:38   0:00 SCREEN -S gong


查看运行中的screen程序screen-ls

BingGongtekiMacBook-Pro:~ binggong$ screen -ls

There is a screen on:

1396.ttys000.BingGongtekiMacBook-Pro(Detached)

1 Socket in /var/folders/dw/wp5cbg3j121_1lvp89533qlr0000gn/T/.screen.


进入某一个screen程序screen-rid

BingGongtekiMacBook-Pro:~ binggong$ screen -r 1396

[screen is terminating]

一个shell窗口中创建多个窗口可以使用ctrl+a+n的方法,切换窗口使用ctrl+a+p,从当前子shell中分离出来ctrl+a+d。

任务完成,退出操作,exit。

shell窗口屏幕共享给其他用户,其他用户远程登录服务器后通过screen -ls查看想要共享的shell窗口,通过screen -x pid来实现共享同一个shell窗口,方便做演示使用。

screen命令详解:http://www.cnblogs.com/mchina/archive/2013/01/30/2880680.html




七、Linux脚本进阶和进程管理