一、systemd的简介
systemd是linux的初始化启动系统,从当年的sysv init到upstart再到现在的systemd,可以说启动系统在不断的优化启动效率。当年的sysvint在启动系统的时候,使用的是串行启动的方式,也就是每个服务必须在等待前面的服务系统启动完毕再进行启动。这样就大大增加了启动时间。upstart使用的是半并行的事件触发机制,也就是说只要不需要依赖的都独立出来并行启动,这种方式比之前的sysvinit的方式快了很多,但是在某种程度上来说,还是局部串行的,也就是存在依赖的处理程序还需要一个接一个的进行启动。有没有办法将需要依赖的程序也并行起来独立启动呢?这个时候就诞生了systemd。
二、linux系统的启动过程
既然是初始化启动程序,必须先从开机说起,开机后首先是进行post上电自检,也就是检测cpu,磁盘,内存条,主板等有没有坏掉,然后是bios读取设备的设置并把系统管理控制权交给MBR,MBR读取Bootloader管理器(我们一般使用Grub)引导程序的相关信息,然后进行初始化内核,并进行第二次硬件自检,当内核文件
而Grub作为引导程序,会在配置文件里面说明引导管理程序,这里我们用的是systemd,在systemd启动管理里面会去启动相应的系统挂载和服务。在upstart系统系统中会依次启动/etc/rc[0-6].d的文件,而在systemd系统中执行的是.target文件,这两种方式的区别是第一种的runlevel是串行依次执行的,第二种是可以并行执行的。这里的target代表的是一个包含多个unit组,也就是含有不同资源的包。
unit一共分成12种:
Service unit:系统服务
Target unit:多个 Unit 构成的一个组
Device Unit:硬件设备
Mount Unit:文件系统的挂载点
Automount Unit:自动挂载点
Path Unit:文件或路径
Scope Unit:不是由 Systemd 启动的外部进程
Slice Unit:进程组
Snapshot Unit:Systemd 快照,可以切回某个快照
Socket Unit:进程间通信的 socket
Swap Unit:swap 文件
Timer Unit:定时器
传统的runlevel和target的对照表
Traditional runlevel New target name Symbolically linked to...
Runlevel 0 | runlevel0.target -> poweroff.target
Runlevel 1 | runlevel1.target -> rescue.target
Runlevel 2 | runlevel2.target -> multi-user.target
Runlevel 3 | runlevel3.target -> multi-user.target
Runlevel 4 | runlevel4.target -> multi-user.target
Runlevel 5 | runlevel5.target -> graphical.target
Runlevel 6 | runlevel6.target -> reboot.target
三、systemd的优化
优化启动方式的三个方向:socket通信依赖,文件系统依赖,D-bus依赖
socker通信依赖:
因为绝大多数的服务依赖是socket依赖,可能某一个通信服务需要另一个服务开启才能通信,这样一来假如这个需要通信依赖没有开启就去通信的话就会报错。那么有没有办法同时开启这些服务,在这些服务完全开启后再进行通信。这里systemd的办法是将请求服务先存放到linux系统的缓存里面,当真正完全开启后再去请求缓存进行通信。这样就避免了不同服务同时开启后带来的请求失败的错误,从而可以让有socket依赖的服务也能够并行开启
文件系统依赖:
在系统的启动过程中,有很大部分时间是在进行文件系统检测,这些活动执行时系统是处于空闲状态的,因为有些服务必须要挂载了才能使用。所以有没有可能在这个时候同时启动这些需要文件系统挂载后才能执行的服务?systemd里面的设计就是创建一个临时的挂载点,按需挂载,服务要什么挂载,就挂载什么。等到文件系统的检测和挂载全部完成后再切换到真正的挂载点。这样就实现了有依赖文件系统的服务也能在文件系统检测挂载时同时启动
D-bus依赖:
D-bus是一个高效的进程间通信机制,也用于应用程序和内核通信。当我们A,B要进行通信时,A启动了,B没有启动,那么这个时候”bus activation“功能就开启了,A会去拉起服务B,并且请求会被D-bus缓存。服务A等待服务B就绪。这样也就解决了进程通信依赖造成的无法同步的问题