Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)html
idle进程其pid=0,其前身是系统建立的第一个进程,也是惟一一个没有经过fork或者kernel_thread产生的进程。shell
各个进程的主要职责:编程
* idle进程(PID = 0,swapper,也叫idle)由系统自动建立, 运行在内核态 ,建立了第一个用户进程(init进程(PID = 1) /sbin/init)和经过kernel_thread建立第一个内核进程kthreadd(PID = 2) 以后idle进程(PID = 0)进入idle状态,
当没有进程能够被调度的时候运行该进程,不作具体的事情。即 完成加载系统后,演变为进程调度、交换。ubuntu
*init进程完成系统的初始化. 是系统中全部其它用户进程的祖先进程。主要做用是处理僵尸进程。当某个父进程比子进程提早消亡时,父进程会给子进程从新寻找“养父进程”,通常就是进程1,由进程1负责处理该子进程的消亡。
首先Linux内核启动,而后在用户空间中启动init进程,再启动其余系统进程。在系统启动完成完成后,init将变为守护进程监视系统其余进程。缓存
*kthreadd进程由idle经过kernel_thread建立,并始终运行在内核空间, 负责全部内核线程的调度和管理
它的任务就是管理和调度其余内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的做用就是运行kthread_create_list全局链表中维护的kthread, 当咱们调用kernel_thread建立的内核线程会被加入到此链表中,所以全部的内核线程都是直接或者间接的以kthreadd为父进程服务器
进程之间的关系:父子关系、兄弟关系
task_struct的 real_parent成员指向父进程,
parent成员指向“养父进程”;
children成员表示该进程的子进程链表;
sibling成员表示该进程的兄弟进程链表。网络
要说清 Systemd,得先从 Linux 操做系统的启动提及。Linux 操做系统的启动首先从 BIOS 开始,而后由 Boot Loader 载入内核,并初始化内核。内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程,也叫根进程。它负责产生其余全部用户进程。全部的进程都会被挂在这个进程下,若是这个进程退出了,那么全部的进程都被 kill 。若是一个子进程的父进程退了,那么这个子进程会被挂到 PID 1 下面。(注:PID 0 是内核的一部分,主要用于内进换页,参看:Process identifier)架构
SysV Init并发
PID 1 这个进程很是特殊,其主要就职务是把整个操做系统带入可操做的状态。好比:启动 UI – Shell 以便进行人机交互,或者进入 X 图形窗口。传统上,PID 1 和传统的 Unix System V 相兼容的,因此也叫 sysvinit
,这是使用得最悠久的 init 实现。Unix System V 于 1983 年 release。app
在 sysvint
下,有好几个运行模式,又叫 runlevel
。好比:常见的 3 级别指定启动到多用户的字符命令行界面,5 级别指定启起到图形界面,0 表示关机,6 表示重启。其配置在 /etc/inittab
文件中。
与此配套的还有 /etc/init.d/
和 /etc/rc[X].d
,前者存放各类进程的启停脚本(须要按照规范支持 start
,stop
子命令),后者的 X 表示不一样的 runlevel 下相应的后台进程服务,如:/etc/rc3.d
是 runlevel=3 的。 里面的文件主要是 link 到 /etc/init.d/
里的启停脚本。其中也有必定的命名规范:S 或 K 打头的,后面跟一个数字,而后再跟一个自定义的名字,如:S01rsyslog
,S02ssh
。S 表示启动,K表示中止,数字表示执行的顺序。
UpStart
Unix 和 Linux 在 sysvint
运做多年后,大约到了 2006 年的时候,Linux 内核进入 2.6 时代,Linux 有了不少更新。而且,Linux 开始进入桌面系统,而桌面系统和服务器系统不同的是,桌面系统面临频繁重启,并且,用户会很是频繁的使用硬件的热插拔技术。因而,这些新的场景,让 sysvint
受到了不少挑战。
好比,打印机须要 CUPS 等服务进程,可是若是用户没有打机印,启动这个服务彻底是一种浪费,而若是不启动,若是要用打印机了,就没法使用,由于sysvint
没有自动检测的机制,它只能一次性启动全部的服务。另外,还有网络盘挂载的问题。在 /etc/fstab
中,负责硬盘挂载,有时候还有网络硬盘(NFS 或 iSCSI)在其中,可是在桌面机上,有极可能开机的时候是没有网络的, 因而网络硬盘都不能够访问,也没法挂载,这会极大的影响启动速度。sysvinit
采用 netdev
的方式来解决这个问题,也就是说,须要用户本身在 /etc/fstab
中给相应的硬盘配置上 netdev
属性,因而 sysvint
启动时不会挂载它,只有在网络可用后,由专门的 netfs
服务进程来挂载。这种管理方式比较难以管理,也很容易让人掉坑。
因此,Ubuntu 开发人员在评估了当时几个可选的 init 系统后,决定从新设计这个系统,因而,这就是咱们后面看到的 upstart
。 upstart
基于事件驱动的机制,把以前的彻底串行的同步启动服务的方式改为了由事件驱动的异步的方式。好比:若是有U盘插入,udev
获得通知,upstart
感知到这个事件后触发相应的服务程序,好比挂载文件系统等等。由于使用一个事件驱动的玩法,因此,启动操做系统时,不少没必要要的服务能够不用启动,而是等待通知,lazy 启动。并且事件驱动的好处是,能够并行启动服务,他们之间的依赖关系,由相应的事件通知完成。
upstart 有着很不错的设计,其中最重要的两个概念是 Job 和 Event。
Job 有通常的 Job,也有 service 的 Job,而且,upstart
管理了整个 Job 的生命周期,好比:Waiting, Starting, pre-Start, Spawned, post-Start, Running, pre-Stop, Stopping, Killed, post-Stop 等等,并维护着这个生命周期的状态机。
Event 分红三类,signal
, method
和 hooks
。signal
就是异步消息,method
是同步阻塞的。hooks
也是同步的,但介于前面二者之间,发出 hook 事件的进程必须等到事件完成,但不检查是否成功。
可是,upstart
的事件很是复杂,也很是纷乱,各类各样的事件(事件没有归好类)致使有点凌乱。不过由于整个事件驱动的设计比以前的 sysvinit
来讲好太多,因此,也深得欢迎。
Systemd
直到 2010 的有一天,一个在 RedHat 工做的工程师 Lennart Poettering 和 Kay Sievers ,开始引入了一个新的 init
系统—— systemd
。这是一个很是很是有野心的项目,这个项目几乎改变了全部的东西,systemd
不但想取代已有的 init 系统,并且还想干更多的东西。
Lennart 赞成 upstart
干的不错,代码质量很好,基于事件的设计也很好。可是他以为 upstart
也有问题,其中最大的问题仍是不够快,虽然 upstart
用事件能够达到必定的启动并行度,可是,本质上来讲,这些事件仍是会让启动过程串行在一块儿。 如:NetworkManager
在等 D-Bus
的启动事件,而 D-Bus
在等 syslog
的启动事件。
Lennart 认为,实现上来讲,upstart
实际上是在管理一个逻辑上的服务依赖树,可是这个服务依赖树在表现形式上比较简单,你只须要配置——“启动 B 好了就启动A”或是“中止了A后就中止B”这样的规则。可是,Lennart 说,这种简单实际上是有害的(this simplification is actually detrimental)。他认为,
sysvint
。 也就是说,当用户配置了 “启动 D-Bus
后请启动 NetworkManager
”, 这个 upstart
能够干,可是反过来,若是,用户启动 NetworkManager
,咱们应该先去启动他的前置依赖 D-Bus
,然而你还要配置相应的反向 Event。原本,我只须要配置一条依赖的,结果如今我要配置不少不少状况下的 Event。upstart
里的 Event 的并不标准,很混乱,没有良好的定义。好比:既有,进程启动,运行,中止的事件,也有 USB 设备插入、可用、拔出的事件,还有文件系统设备 being mounted、 mounted 和 umounted 的事件,还有 AC 电源线链接和断开的事件。你会发现,这进程启停的、USB 的、文件系统的、电源线的事件,看上去长得很像, 可是没有被标准化抽像出来掉,由于绝大多数的事件都是三元组:start, condition, stop 。这种概念设计模型并无在 upstart
中出现。由于 upstart
被设计为单一的事件,而忽略了逻辑依赖。 固然,若是 systemd
只是解决 upstart
的问题,他就改造 upstart
就行了,可是 Lennart 的野心不仅是想干个这样的事,他想干的更多。
首先,systemd
清醒的认识到了 init 进程的首要目标是要让用户快速的进入能够操做 OS 的环境,因此,这个速度必定要快,越快越好,因此,systemd
的设计理念就是两条:
也就是说,按需启动,能不启动就不启动,若是要启动,能并行启动就并行启动,包括大家之间有依赖,我也并行启动。按需启动还好理解,那么,有依赖关系的并行启动,它是怎么作到的?这里,systemd
借鉴了 MacOS 的 Launchd
的玩法(在 Youtube 上有一个分享——Launchd: One Program to Rule them All,在苹果的开源网站上也有相关的设计文档——About Daemons and Services)
要解决这些依赖性,systemd 须要解决好三种底层依赖—— Socket, D-Bus ,文件系统。
systemd
能够帮你在S尚未启动好的时候,创建一个 socket,用来接收全部的C的请求和数据,并缓存之,一旦S所有启动完成,把 systemd 替换好的这个缓存的数据和 Socket 描述符替换过去。D-Bus
全称 Desktop Bus,是一个用来在进程间通讯的服务。除了用于用户态进程和内核态进程通讯,也用于用户态的进程以前。如今,不少的如今的服务进程都用 D-Bus
而不是 Socket 来通讯。好比:NetworkManager
就是经过 D-Bus
和其它服务进程通信的,也就是说,若是一个进程须要知道网络的状态,那么就必须要经过 D-Bus
通讯。D-Bus
支持 “Bus Activation”的特性。也就是说,A要经过 D-Bus
服务和B通信,可是B没有启动,那么 D-Bus
能够把B起来,在B启动的过程当中,D-Bus
帮你缓存数据。systemd
能够帮你利用好这个特性来并行启动 A 和 B。systemd
参考了 autofs
的设计思路,使得依赖文件系统的服务和文件系统自己初始化二者能够并发工做。autofs
能够监测到某个文件系统挂载点真正被访问到的时候才触发挂载操做,这是经过内核 automounter
模块的支持而实现的。好比一个 open ()系统调用做用在 “/misc/cd/file1
” 的时候,/misc/cd
还没有执行挂载操做,此时 open ()
调用被挂起等待,Linux 内核通知 autofs
,autofs
执行挂载。这时候,控制权返回给 open ()
系统调用,并正常打开文件。下图来自 Lennart 的演讲里的一页 PPT,展现了不一样 init 系统的启动。
除此以外,systemd 还在启动时管理好了一些下面的事。
用C语言取代传统的脚本式的启动。前面说过,sysvint
用 /etc/rcX.d
下的各类脚本启动。然而这些脚本中须要使用 awk
, sed
, grep
, find
, xargs
等等这些操做系统的命令,这些命令须要生成进程,生成进程的开销很大,关键是生成完这些进程后,这个进程就干了点屁大的事就退了。换句话说就是,我操做系统干了那么多事为你拉个进程起来,结果你就把个字串转成小写就退了,把我操做系统当什么了?
在正常的一个 sysvinit
的脚本里,可能会有成百上千个这样的命令。因此,慢死。所以,systemd
全面用 C 语言所有取代了。通常来讲,sysvinit
下,操做系统启动完成后,用 echo $$
能够看到,pid 被分配到了上千的样子,而 systemd
的系统只是上百。
另外,systemd 是真正一个能够管住服务进程的——能够跟踪上服务进程所 fork/exec 出来的全部进程。
fork ()
建立子进程,在子进程中 setsid ()
,而后父进程退出(为了后台执行)fork ()
,建立孙子进程,肯定没有交互终端。而后子进程退出。/dev/null
上,还要建立 pid 文件,日志文件,处理相关信号 ……fork
外还会 fork
出不少不少的子进程(好比说一些 Web 服务进程,会根据用户的请求连接来 fork 子进程),这个进程树是至关难以管理的,由于,一旦父进程退出来了,子进程就会被挂到 PID 1 下,因此,基本上来讲,你没法经过服务进程自已给定的一个 pid 文件来找到全部的相关进程(这个对开发者的要求过高了),因此,在传统的方式下用脚本启停服务是至关至关的 Buggy 的,由于没法作对全部的服务生出来的子子孙孙作到监控。upstart
经过变态的 strace
来跟踪进程中的 fork ()
和 exec ()
或 exit ()
等相关的系统调用。这种方法至关笨拙。 systemd
使用了一个很是有意思的玩法来 tracking 服务进程生出来的全部进程,那就是用 cgroup
(我在 Docker 的基础技术“cgroup 篇”中讲过这个东西)。cgroup 主要是用来管理进程组资源配额的事,因此,不管服务如何启动新的子进程,全部的这些相关进程都会同属于一个 cgroup
,因此,systemd
只须要简单的去遍历一下相应的 cgroup
的那个虚文件系统目录下的文件,就能够正确的找到全部的相关进程,并将他们一一中止。 另外,systemd
简化了整个 daemon 开发的过程:
fork ()
,只须要实现服务自己的主逻辑就能够了。setsid ()
,systemd
会帮你干pid 文件
,systemd
会帮处理。syslog
,或是处理HUP
的日志 reload 信号。把日志打到 stderr
上,systemd
帮你管理。SIGTERM
信号,这个信号就是正确退出当前服务,不要作其余的事。 除此以外,systemd
还能——
systemd
改造了传统的 syslog 的问题,采用二进制格式保存日志,日志索引更快。还有好多好多,他接管不少不少东西,因而就让不少人不爽了,由于他在干了不少本不属于 PID 1 的事。
Systemd 争论和八卦
因而 systemd
这个东西成了多是有史以来口水战最多的一个开源软件了。systemd
饱受各类争议,最大的争议就是他破坏了 Unix 的设计哲学(相关的哲学能够读一下《Unix 编程艺术》),干了一个大而全并且至关复杂的东西。固然,Lennart 并不一样意这样的说法,他后来又写一篇 blog “The Biggest Myths”来解释 systemd
并非这样的,你们能够前往一读。
这个争议大到什么样子呢?2014 年,Debian Linux 由于想准备使用 systemd
来做为标准的 init 守护进程来替换 sysvinit
。而围绕这个事的争论达到了空前的热度,争论中充满着仇恨,systemd
的支持者和反对者都在互相辱骂,致使当时 Debian 阵营开始分裂。还有人给 Lennart 发了死亡威胁的邮件,用比特币雇凶买杀手,扬言要取他的性命,在 Youbute 上传了侮辱他的歌曲,在 IRC 和各类社交渠道上给他发下流和侮辱性的消息。这已经不是争议了,而是一种彻彻底底的仇恨!
因而,Lennart 在 Google Plus 上发了贴子,批评整个 Linux 开源社区和 Linus 本人。他大意说,
这个社区太病态了,全是 ass holes,大家不停用各类手段在各类地方用不一样的语言和方式来侮辱和漫骂我。我仍是一个年轻人,我历来没有经历过这样的场面,可是今天我已经对这种场面很熟悉了。我有时候说话可能不许确,可是我不会像他样那样说出那样的话,我也没有被这些事影响,由于我脸皮够厚,因此,为何我能够在如何大的反对声面前让
systemd
成功,可是,大家 Linux 社区太可怕了。大家里面的有精神病的人太多了。另外,对于 Linus Torvalds,你是这个社区的 Role Model,但惋惜你是一个 Bad Role Model,你在社区里的刻薄和侮辱性的言行,基本从必定程度上鼓励了其它人跟你同样,固然,并不仅是你一我的的问题,而是在你周围汇集了一群和你同样的这样干的人。
送你一句话——
A fish rots from the head down !
一条鱼是从头往下腐烂的……
这篇契文很长,喜欢八卦的同窗能够前往一读。感觉一下 Lennart 当时的心态(我以为能算上是很是平稳了)。
Linus 也在被一媒体问起 systemd
这个事来(参看“Torvalds says he has no strong opinions on systemd”),
Linus 在采访里说,
我对
systemd
和 Lennart 的贴子没有什么强烈的想法。虽然,传统的 Unix 设计哲学—— “Do one thing and Do it well”,很不错,并且咱们大多数人也实践了这么多年,可是这并不表明全部的真实世界。在历史上,也不仅有systemd
这么干过。可是,我我的仍是 old-fashioned 的人,至少我喜欢文本式的日志,而不是二进制的日志。可是systemd
没有必要必定要有这样的品味。哦,我说细节了……
今天,systemd
占据了几乎全部的主流的 Linux 发行版的默认配置,包括:Arch Linux、CentOS、CoreOS、Debian、Fedora、Megeia、OpenSUSE、RHEL、SUSE 企业版和 Ubuntu。并且,对于 CentOS, CoreOS, Fedora, RHEL, SUSE 这些发行版来讲,不能没有 systemd
。(Ubuntu 还有一个不错的 wiki – Systemd for Upstart Users 阐述了如何在二者间切换)
其它
还记得在《缓存更新的套路》一文中,我说过,若是你要作好架构,首先你得把计算机体系结构以及不少老古董的基础技术吃透了。由于里面会有不少能够借鉴和相通的东西。那么,你是否从这篇文章里看到了一些有分布式架构类似的东西?
好比:从 sysvinit
到 upstart
再到 systemd
,像不像是服务治理?Linux 系统下的这些服务进程,是否是很像分布式架构中的微服务?还有那个D-Bus,是否是很像 SOA 里的 ESB?而 init 系统是否是很像一个控制系统?甚至像一个服务编排(Service Orchestration)系统?
分布式系统中的服务之间也有不少依赖,因此,在启动一个架构的时候,若是咱们能够作到像 systemd 那样并行启动的话,那么是否是就像是一个微服务的玩法了?
嗯,你会发现,技术上的不少东西是相通的,也是互相有对方的影子,因此,其实技术并很少。关键是咱们学在了表面仍是看到了本质。
https://news.cnblogs.com/n/573985/