linux 服务与进程

linux启动流程

通电 –>BIOS(哪个磁盘有MBR) –>MBR(哪个分区为要开启的OS) –>OS –>/boot(kernel) –>init(PID:1) –>/etc/rc*.d/ –>/etc/init.d/ –>用户登陆(/etc/profilc–>~/.profile .bash_login .bash_profile–>~/.bashrc)

添加启动项

/etc/rc[0~6].d 这7个目录中,每个目录分别存放着对应运行级别加载时需要关闭或启动的服务,每个脚本文件都对应着/etc/init.d/目录下具体的服务

K开头的脚本文件代表运行级别加载时需要关闭的,S开头的代表需要执行,数字代表执行顺序
因此,当我们需要开机启动自己的脚本时,只需要将可执行脚本丢在/etc/init.d目录下,然后在/etc/rc*.d中建立软链接即可

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo shmod 755 /etc/init.d/ssh
cd /etc/init.d
sudo update-rc.d ssh defaults 95 5 . # 执行顺序95,加入运行级别5级中
#即在rc*.d中各建立了一个软连接,因此也可以自己手动建立软连接,如下
ln -s /etc/init.d/ssh /etc/rc5.d/S95sshd
sudo /etc/init.d/ssh start
sudo service S95sshd start
# 开机启动
sudo apt-get install openssh-server
# 二选一
sudo /etc/init.d/ssh start
sudo service sshd start

简单的启动命令

Linux 在启动的时候会执行 /etc/rc.local 里面的脚本,所以只要在这里添加执行命令就可以

1
2
3
4
5
6
7
8
9
10
11
vim /etc/rc.local
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
# 如果是 Ubuntu 16.04 以上,rc.local 被当成了服务,而且默认是不会启动,需要手动启用一下服务
# 启动rc.local服务:
ln -fs /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service
systemctl cat rc.local
sudo systemctl enable rc-local.service
# 如果有图形桌面的话
super键--search "startup"-->设置开机启动选项,最重要的就是找到程序的绝对路经写上就可以.可以通过如下命令查看:
vim ~/.config/autostart/chromium-browser.desktop

使用systemd设置开机启动

systemd默认读取/etc/systemd/system下的配置文件,该目录下的文件会链接/lib/systemd/system/下的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo vim /lib/systemd/system/rslsync.service
[Unit]
Description=rslsync
After=network.target
[Service]
Type=forking
ExecStart=/home/femn/resilio-sync_glibc23_x64/rslsync
[Install]
WantedBy=multi-user.target
sudo chmod 754 /lib/systemd/system/rslsync.service
sudo systemctl start rslsync.service
sudo systemctl enable rslsync.service

也可以使用第三方包来管理启动程序

定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
vim /etc/crontab
# 权限要一致,且要可执行
# 分 时 日 月 周 命令
# 每天11点执行
0 11 * * * root sh /home/python/xx.sh
# 每两个小时
0 */2 * * * echo "Have a break now." >> /tmp/test.txt
# 晚上11点到早上8点之间每两个小时和早上八点
0 23-7/2,8 * * * echo "Have a good dream" >> /tmp/test.txt
# 保存退出即生效(刚添加的任务会到2-3分钟后才开始生效)

查看服务状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ubuntu centos
service sshd status/stop/restart # service 在rc*.d/的名字
systemctl start docker #centos启动服务
systemctl enable docker # 开机启动
systemctl status nginx
systemctl start firewalld.service
systemctl enable firewalld.service
systemctl daemon-reload # 修改启动参数时的
systemctl restart docker
# 只有systmectl 状态 服务名
# redhat 操作系统下
chkconfig 命令
chkconfig --list sshd

进程有关的

“衍生出来的进程”正是 Linux 的父子进程的概念.
当我们登录系统后,会取得一个 bash shell,然后我们利用这个 bash 提供的接口去执行另一个命令,

例如 bash 或者 ps 等.那些另外执行的命令也会被触发成为 PID,那个后来执行的命令产生的 PID 就是”子进程”,而原本的 bash 环境下,就称为”父进程”了

1
2
3
4
5
6
7
8
9
10
11
12
bash
ps -o pid,ppid,tty,time,cmd
PID PPID TT TIME CMD
11373 4396 pts/12 00:00:00 bash
13043 11373 pts/12 00:00:00 bash
13110 13043 pts/12 00:00:00 ps -o pid,ppid,tty,time,cmd
PID: 运行着的命令(CMD)的进程编号
PPID:父进程号
TTY: 命令所运行的位置(终端)
TIME: 运行着的该命令所占用的CPU处理时间
CMD: 该进程所运行的命令
# ps 仅仅显示本终端的进程

我所做的操作是在原来的 bash shell 中执行了 bash 命令,然后又执行了 ps -o pid,ppid,comm命令.我们可以看到
,第二个进程 bash 是第一个进程 bash 的子进程,而第三个进程ps是第二个进程的子进程

新的进程要通过老的进程复制自身得到,这就是 fork.fork 是一个系统调用.
进程存活于内存中.每个进程都在内存中分配有属于自己的一片空间 (内存空间,包含栈、堆、全局静态区、文本常量区、程序代码区).

当一个程序调用 fork 的时候,实际上就是将上面的内存空间,又复制出来一个,构成一个新的进程,
并在内核中为该进程创建新的附加信息 (比如新的 PID,而 PPID 为原进程的 PID).此后,两个进程分别地继续运行下去.
新的进程和原有进程有相同的运行状态(相同的变量值,相同的指令…).我们只能通过进程的附加信息来区分两者.

工作管理(job control)

是用在 bash 环境下的,也就是说,当我们登录系统取得 bash shell 之后,在单一终端机下可以同时进行多个工作的行为管理.

假如我们只有一个终端,因此在可以出现提示符让你操作的环境就成为前台(foreground),至于其他工作就可以放在后台(background)去暂停或运行
程序调用 exec 的时候,进程清空自身的内存空间,并根据新的程序文件重建程序代码、文本常量、全局静态、堆和栈(此时堆和栈大小都为 0),并开始运行.

直接将命令放到后台执行 ( &)

将目前工作放到后台并暂停(ctrl+z)

将后台工作拿到前台来处理(fg %工作序号)

进程管理命令

ps: PID,CMD,PORT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ps # 仅仅显示本终端的进程
-a # 显示终端中进行的所有进程
-x # 会显示没有控制终端的进程
-e # 所有的进程
-u # 查看某个用户的所有进程
-f # 来查看格式化的信息列表
ps -u femn # 查看所有femn用户的进程
ps aux # 可以对系统进程更加全面的了解
ps -aux | less
# less是一个分页显示文件的工具工具,它允许你一页一页(或一个屏幕一个屏幕)地查看信息
ps -ef # 所有进程 PID PPID
ps -efH # 把输出的进程组成一个层级的格式 树状
ps axjf # 树状视图 等于 pstree
ps -ef | grep python3 | cut -c 10-15 | xargs kill -9
# Kill 某个用户或命令的所有进程
ps axjf |grep nginx
pgrep nginx # 单单的得到PID,和其子进程号
ps -aux --sort -pcpu | head -n 10
# 根据 CPU 使用来升序排序 +pcpu倒序
ps -aux --sort -pmem | head -n 10
# 根据 内存 使用来升序排序
ps -aux --sort -pcpu,-pmem | head -n 10
# 仅仅得到本机的程序名相关的进程
ps aux/-ef |grep ssserver # 程序名(命令名)或者PID

netstat:PID,CMD,PORT

1
2
3
4
5
6
7
8
# 会牵扯到此程序 相关联的socket服务,或其它的网络相接进程(网络是双向的)
netstat -anp |grep ssh #程序名 得到PID 端口号
netstat -lnp |grep 8388 #端口号 得到PID,进程名
sudo lsof -i :8001 #查看此端口 PID,User,进程名
ll /proc/进程号
sudo lsof -p 1609
killall http* 它支持通过进程名而不是进程号来结束进程,也支持通配符.

top

1
2
3
4
5
6
top # 动态显示进程 q 退出, M 内存占用降序排序,P 按CPU占用降序排序
[top使用说明](http://www.linuxidc.com/Linux/2011-03/33582.htm)
ssserver内存占用随时间升高
free -m # 内在的使用情况
# 查看目前进程正在实际被使用的内存,是used-(buffers+cache)
htop # 更加友好的显示top

进程的状态

sleeping

D(sleeping),往往是由于 I/O(磁盘IO,网络IO,其他外设IO) 资源得不到满足,而引发等待

举个例子,当 NFS 服务端关闭之时,若未事先 umount 相关目录,在 NFS 客户端执行 df 就会挂住整个登录会话,按 Ctrl+C 、Ctrl+Z 都无济于事.
断开连接再登录,执行 ps axf 则看到刚才的 df 进程状态位已变成了 D ,kill -9 无法杀灭.

正确的处理方式,是马上恢复 NFS 服务端,再度提供服务,刚才挂起的 df 进程发现了其苦苦等待的资源,便完成任务,自动消亡.若 NFS 服务端无法恢复服务,在 reboot 之前也应将 /etc/mtab 里的相关 NFS mount 项删除,以免 reboot 过程例行调用 netfs stop 时再次发生等待资源,导致系统重启过程挂起.

zombile

Z(zombie) 之所以杀不死,是因为它已经死了,否则怎么叫 Zombie(僵尸).在UNIX/Linux中,每个进程都有一个父进程,进程号叫PID(Process ID), 相应地,父进程号就叫PPID(Parent PID).

当进程死亡时,它会自动关闭已打开的文件,舍弃已占用的内存、交换空间等等系统资源,然后向其父进程返回一个退出状态值,报告死讯.如果程序有 bug,就会在这最后一步出问题.子进程说我死了,父进程却没听见,所以子进程便成了僵尸.在UNIX/Linux中消灭僵尸的手段比较残忍,执行 ps axjf 找出僵尸进程的父进程号(PPID,第一列),先杀其父,然后再由进程天子 init(其PID为1,PPID为0)来一起收拾父子僵尸.注意,子进程变成僵尸只是碍眼而已,并不碍事,如果僵尸的父进程当前有要务在身,则千万不可贸然杀之.

这些进程已经死亡,但没有释放系统资源,包括内存和一些一些系统表等,如果这样的进程很多,会引发系统问题.用ps -el看出的进程状态如果是Z,就是僵尸进程.

1
2
3
4
5
ps -ef|grep defunc # 可以找出僵尸进程
# 清除ZOMBIE(僵尸)进程可以使用如下方法:
kill –18 PPID (PPID是其父进程)
# 这个信号是告诉父进程,该子进程已经死亡了,请收回分配给他的资源.

如果不行则看能否终止其父进程(如果其父进程不需要的话).先看其父进程又无其他子进程,如果有,可能需要先kill其他子进程,也就是兄弟进程.方法是:

1
2
kill –15 PID1 PID2 # (PID1,PID2是僵尸进程的父进程的其它子进程).
kill –15 PPID # 然后再kill父进程,这样僵尸进程就可能被完全杀掉了

Share Comments