如果事事都追求客观,那么不是虚伪就是愚蠢,且没有主见。by 我
作为第一个被内核启动的进程,PID 1 有着无与伦比的特殊地位和重任。
在内核准备就绪后,PID 1进程被内核启动,这个init system负责启动其他的守护进程,后台进程和用户所需的服务。在如此重要的场合,却在很长一段时间里用着古老的解决方案:SysVinit。这一用就是近20年。
SysVinit由一堆shell脚本组成,在启动的时候,一个一个脚本按一定的顺序串行的执行。整个过程简单易于理解却显得很笨拙。其一,每个服务都必须等待排在它之前的服务启动完毕后才能启动,而这些等待有时是非必需的。其二,脚本由shell写成,用shell写是简单了,但却带来解析执行时的耗时增加。其三,这种启动方式会在开机时就启动所有的服务,而不管它是不是会被用到。
没有人反对应当对SysVinit进行改进或寻找替代品,Upstart就是由Ubuntu推动的一次尝试,因其现代的设计理念而被寄予了厚望。但是,Upstart的表现却不尽如人意,以至于当systemd开始席卷各大发行版的时候,Ubuntu也最终选择了采用systemd。事实上,Upstart采用的事件驱动模型启动方式是一种有点别扭的解决方案,因为不是所有的程序或者服务都能和事件的概念对应上的,大部分的服务只是需要启动,停止,重启,重载,仅此而已。
到了2010年,systemd横空出世,自此一发不可收拾。systemd首先带来的变化,就是系统启动速度的大大改观。
它做到了两点:1)尽可能的启动少的服务。2)尽可能的并发启动。
systemd只会保证启动一开始就必须的服务,如log服务,D-Bus system等等,而像蓝牙,打印机这些,因为不是一开机就会马上用到的,systemd都会推迟去启动它们,甚至如果你的其他软件都没有用到打印机,打印机这个服务进程就不会被启动。而动态的启动服务是现代计算机的需要,尤其对于笔记本而言,如果能支持各种硬件的热插拔,将是对用户体验的一大提升。这两者事实上是一个概念:只启动必须的服务,而其他的服务等到可用或要用的时候才启动。
systemd对并发启动的支持,概念则是源自于Mac OS的launchd。之所以SysVinit需要串行启动,是由于各种程序各种服务之间是有依赖关系的,GNOME依赖于D-Bus,则GNOME需要等D-Bus完全启动后才能启动,而D-Bus和GNOME均依赖于syslog,则它们都需要等待syslog启动完成后才能启动,又如网络连接服务和nginx服务,也是这种先后关系。SysVinit简单的对这些服务进行先后排序(事实上这个排序任务需要用户自己完成),然后依次进行启动,再次强调这两个词:简单,笨拙。要对此进行改进,就要理解各种服务间具体是如何相互依赖的。
we need to understand what exactly the daemons require from each other, and why their start-up is delayed.
服务/守护进程需要等待它所需要的其他服务/守护进程所提供的socket准备就绪后,才能正常的启动。
既然如此,我们完全可以在一开始就创建好所有的socket,然后并发的启动所有的服务。这样做,将会出现两个场景:
1)A服务通过socket向B服务发送异步请求,若此时B服务还没有准备好,这些请求将被存入对应的socket buffer,等到B服务启动完成后,将消费这些请求,而这个过程对于A服务来说,是透明的。
2)A服务通过socket向B服务发送同步请求,若此时B服务还没有准备好,这个请求将被阻塞,直到B服务启动完成为止。而结果也仅是这个进程/线程被阻塞,并不会影响其他的启动任务。
socket可以这么做,D-Bus更加可以这么做,systemd也正是借(cao)鉴(xi)了launchd的这个设计,将原始的串行启动变为并发启动。
以上两点将linux系统的启动速度提高了一个等级,两个词形容:精巧,高效。
如果故事只到这里,那么一切都会很美好,可systemd却不想这么简单。
systemd借鉴Mac OS(在开源社区里这被视为罪恶的闭源软件的代表)的设计,采用C而不是系统管理员熟练的shell,记录日志采用二进制文件。这几个“缺点”常被反对者挂在嘴边用于口水战。然而,我认为这几个都无关紧要,最要命的其实是:it is not the unix way.
Arch Linux在决定采用systemd的时候,在论坛里发过一条回复贴:
these things are not hugely important.
let’s ignore all of those old boring arguments
作为常年的Arch Linux使用者,我不喜欢这样的回应。因为systemd作为一个init system很不纯粹,它接管了太多的服务,破坏了我们一直坚持的原则。PID 1不应该管得这么宽:
systemd-journald:
接管了日志服务,而且日志存储用的是二进制文件。
.timer:
取代了cron。
systemd-consoled:
取代了内核提供的virtual terminal。
systemd-logind:
管理登陆会话。
systemd-networkd:
网络服务也由它管。
systemd-timedated:
PID 1想帮你打理时间和时区。
udevd:
被合并进了systemd
systemd-boot:
同样合并自其他项目,管理你的boot过程。
systemd-resolved:
DNS也由PID 1管了。
systemd-ask-password:
密码它帮你记。
。。。。。
至于Arch Linux,我选中它作为我学习用的的桌面系统,就是看中它够KISS (Keep it simple,stupid),一切都是可定制可替换的。可选择了systemd,意味着用户的选择权变少,整个系统几乎都被systemd接管了,systemd的开发者也说,他们想让构建基于systemd的linux发行版变得简单,可不是嘛,我看现在Arch,也就是linux kernel+systemd+pacman了,自己家的东西变少,和其他发行版开始趋同了。这样,使用Arch和使用其他发行版还有什么不同吗?(是的,我就是在说逼格)
对于服务器系统来说,启动速度的提升是一件无关紧要的事,稳定性才是王道,所以systemd进入服务器系统,首先要被考虑的是稳定性而不是启动速度。可systemd接管了这么多服务,集成到单一的binary中,万一出个什么事,直接整个系统就挂了,你可是一人之下万人之上的init system啊!systemd的代码质量一直被人诟病不说,不遵循do one thing and do it well原则,将导致的结果就是,一旦某一子程序出问题了,整个系统就挂了,而且还替换不了。
对于桌面系统来说(目前只有开发人员会用linux作为日常的桌面系统吧?),启动速度确实带来了很大的帮助,集成一大堆服务也自有其道理,但是,要不是看中linux的可玩性可定制性,谁会用linux发行版作为日常的桌面系统?使用Arch和使用Mac OS,前者让人觉得掌控了一切,后者让人感觉被掌控了一切。如果我追求的是启动速度这些东西,我直接用Mac OS不就完了吗干嘛折腾Arch呢?(事实上Arch Linux被我用于学习,Winodws和Mac OS被我用于生活娱乐,而工作用的是Ubuntu)。如果说使用Windows是无奈,Mac OS是因其颜值,那么使用Arch就是信仰:)。现在是,Arch Linux = linux kernel + systemd + pacman。手动再见。
我想,只有你赞成do one thing and do it well 和 KISS原则是一件需要坚持的事情,才会赞同我的观点,否则,你会觉得我是个傻叉。
我认为systemd做错的事情,就是在做好init system该做的事情之后,又做了很多不应该做的事情。甚至,只要systemd将它现在接管的这么多服务抽离出来,变成一个个独立的互不强制依赖的二进制包,反对的人会少很多,我也会开始喜欢它。也有人早已经这么做了,systemd的反对者们创建了一个分支:uselessd。这个项目将systemd的主服务抽离出来,去掉其他不相关的东西(如systemd-journald,udev等),将其改装成一个纯粹的init程序。这个思路是非常对的,可不幸的是,这个项目已经死了。so sad。
到今天,历史已经改变不了,自fedora率先采用systemd起,如今各大发行版包括Arch,debian,Ubuntu都已经切换到systemd或正在切换到systemd,只有Geetoo还没决定好。正如uselessd的发起者所说,发行版的维护者们变得懒惰了,systemd一统天下后维护工作将会变得异常简单。
The End: 我赞赏systemd的设计,当我使用的发行版决定采用它的时候,它却带来了个全家桶:(
原文自谢培阳的博客