并行启动服务加快系统启动速度
发表于:2007-07-04来源:作者:点击数:
标签:
今天无意间看到一篇使系统服务并行运行加快系统启动速度的文章,于是 尝试了下,感觉办法很不错,同时让我对lfs的系统引导脚本有了更深的理解 现在系统从加载内核到login只要5秒,飞一样的感觉 ^_^ Ok ! Let`s Go ! 因为要修改系统启动的脚本,很可能让系统启
今天无意间看到一篇使系统服务并行运行加快系统启动速度的文章,于是
尝试了下,感觉办法很不错,同时让我对lfs的系统引导脚本有了更深的理解
现在系统从加载内核到login只要5秒,飞一样的感觉 ^_^
Ok ! Let`s Go !
因为要修改系统启动的脚本,很可能让系统启动不正常,所以最好有双linux系统,即使修改错误了还可以从另一个系统引导修复。如果很不幸,没有的话,可以先学下这招,紧急救护系统也有用 :p 紧急救援模式:
grub菜单中选择linux,按e,e,进入编辑模式,kernel......那一行最后加上init=/bin/bash,这样引导系统可以得到一个bash shell这样进入的系统会是read-only的,首先先使用fsck检查系统fsck -a /dev/hdaX 处理根分区fsck -R -A -a 处理其他分区如果系统在上次重启,是正常重启的,文件系统是正常卸载的,可以不用fsck检查直接把系统挂载成read-write的mount / -o remount,rwmount /procswap on -a 打开所有的交换分区在修复好系统后将系统重新挂载成ro的,就可以安全重启了。mount / -o remount,ro 简单的说一下linux系统的启动过程。
当grub加载内核后,内核执行/sbin/init,init程序读取/etc/inittab内容,开始系统的初始化。 init读取initdefault字段,取得系统运行级别
id:3:initdefault: 这里启动级别是3,通常是多用户字符登陆模式 init读取sysinit字段,开始系统基本的初始化
si::sysinit:/etc/rc.d/init.d/rc sysinit这一行表示init会去执行/etc/rc.d/init.d/rc这个文件,sysinit是传入的参数,这里要做的是:挂载proc系统拉,检查根分区拉,开启swap拉。等等但是在不同的发行版可能不同,比如在Mandrakelinux中是:si::sysinit:/etc/rc.d/rc.sysinit这样初始化的脚本就成了/etc/rc.d/rc.sysinit init读取wait字段,开始系统服务初始化
l3:3:wait:/etc/rc.d/init.d/rc 3经过基本初始化后,init读取run-level中的脚本,这些脚本位于/etc/rc.d/rcX.d目录下。X是当前的运行级别.这里是系统启动的服务,比如network,alsa,httpd....等/etc/rc.d/init.d/rc接收一个运行级别作为参数,然后逐一的开启/关闭/etc/rc.d/rcX.d目录下的脚本。wait表示init会等待它结束再去执行其他程序。 有些发行版在执行rcX.d之后去执行/etc/rc.d/rc.local
最后就看到可爱的login拉在/etc/rc.d/rcX.d中的脚本都是以"SXX+服务名"或者"KXX+服务名"组成的并且都是到/etc/rc.d/init.d中相应脚本的符号链接,有的发行版是/etc/init.d,只是位置不同而已。其中XX是0-9的数字,数字越小,则启动的时间越早。以S开头的表示系统启动时传递start参数的服务,就是开启拉。K开头的就是传递stop参数。/etc/rc.d/rc3.d:S10sysklogd@ S20network@ S25random@ S30httpd S40alsa@ S85numlock@可以看出,我的系统进入rc3.d时首先启动的服务是sysklogd,最后是numlock很明显,httpd服务必须要在network之后运行,不然没有网络哪来的web服务?在lfs中是通过ls -v 列出它们,然后逐一的执行它们,这样就会使系统启动的速度很慢,服务越多越明显现在希望做的就是:让那些相互之间没有依赖关系的服务可以同时开启,而不是逐一的执行这样系统启动的速度就会大大的提高了。make 就是实现这个功能的工具。相互有依赖关系的服务,让make去解决它们的依赖性。再使用make -j 参数使服务可以并行启动。在makefile中写入服务之间的相依赖关系:httpd : network这样就表示httpd依赖network,当network启动完毕,就可以立刻启动httpd而其他不相依赖的服务列在makefile中,同时开启。原理就是这样,下面是我的实际做法:首先是写make的配置文件,该文件的样例在本文的结尾可以找到./etc/rc.d/runlevel.mk######################################################################### Description : Gnu Makefile to control the services in the specified# runlevel. It will run the required services, and log# the output of the services to the file# /var/log/initd.start (for service startup) and# /var/log/initd.stop (for service shutdown).## This controlling program is designed to be invoked by# the "/etc/rc.d/rc" script.## Author : jameshunt@uk.ibm.com## Notes :## - Run as,## make [-n] -j -f runlevel.mk \# RUNLEVEL= \# JOB=## - $(JOB) is not validated - that is left to the service program.# - $(RUNLEVEL) is not validated - that is left to the calling program# (usually /etc/rc.d/rc).# - It wouldn't take too much effort to auto-generate this Makefile.########################################################################## passed as a parameterRUNLEVEL =# passed as a parameter (start, stop, status, etc)JOB =# set to a value to enable debug outputDEBUG =######################################################################### START CONFIGURATION# system commands used by this facilityCAT = /bin/catRM = /bin/rmECHO = /bin/echoDATE = /bin/date# Directory containing scripts/programs to run.INITD_DIR := /etc/rc.d/init.d #这里要修改成自己系统的所有服务脚本存放目录#有些发行版是/etc/init.d 这个目录必须正确# Directory into which a lock file is created when a service starts.# (Note that the lock file is created by the service).SUBSYS_FILE_DIR := /var/lock/subsys #这个目录必须存在,如果没有自己建立# Used to create temporary files, before collating them all into# $(FINAL_OUTPUT_FILE).TMP_DIR := /tmpTMPFILE_PREFIX := .runlevelTMP_FILE = $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).$@# File that contains all output of programs/scripts run.FINAL_OUTPUT_FILE = /var/log/initd.$(JOB)# List of *all* services.## (Important Note: if you don't include a service in this list,# it won't get run!)#这里写上所有的需要启动的服务,这些服务的名字必须要与/etc/rc.d/init.d#中的名字一致的。这样make 就会去并行的开启它们拉。ALL = \sysklogd \network \httpd \random \alsa \numlock \# END CONFIGURATION######################################################################### Check command-line parametersifndef RUNLEVEL$(error must specify RUNLEVEL, so I know what to run)endififndef JOB$(error must specify JOB, so I know what to do)endifdefault: $(ALL) create_final_output_fileifneq ($(DEBUG),)@$(ECHO) "RUNLEVEL=$(RUNLEVEL)"@$(ECHO) "JOB=$(JOB)"@$(ECHO) "FINAL_OUTPUT_FILE=$(FINAL_OUTPUT_FILE)"@$(ECHO) "TMP_FILE=$(TMP_FILE)"@$(ECHO) "ALL=|$(ALL)|"#@$(ECHO)#@$(ECHO) "ALL (less local)=|$(filter-out local,$(ALL))|"#@$(ECHO)#@$(ECHO) "ALL (less kudzu)=|$(filter-out kudzu,$(ALL))|"#@$(ECHO)endif############################################################### Generic rule to control a service.## Note that we capture all output to a file.$(ALL) : $(SUBSYS_FILE_DIR)/$@@$(ECHO) "Begin \"$(JOB) $@\" at `$(DATE)`" > $(TMP_FILE)@$(INITD_DIR)/$@ $(JOB) >> $(TMP_FILE) 2>&1@$(ECHO) "End \"$(JOB) $@\" at `$(DATE)`" >> $(TMP_FILE)############################################################### List of services that have dependencies.## (Note: It is not necessary to list services that have no# dependencies).# Include the relevant dependencies. If you intend to use this facility,# you must provide 2 makefiles / runlevel, one for starting the services# in the runlevel, and one for stopping the services in the runlevel.## WARNING: If make attempts to include a file that does not exist, it will# exit. This could cause your system to boot in an unfamiliar way.include /etc/rc.d/start3.mk #这里是服务有依赖关系的记录文件位置.## Lastly, merge all the service output files into a single file.# Note that the order of the service output in the merged file is not# chronological.create_final_output_file :$(CAT) $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).* \> $(FINAL_OUTPUT_FILE)$(RM) -f $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).*# EOF 注意的地方:
/etc/rc.d/start3.mk 由上面的runlevel.mk决定位置名称 httpd : network 其中的空格必须是用TAB键打出来的 makefile写好了,现在修改rc脚本,让它当传递进来参数为3时不去逐一的执行/etc/rc.d/rc3.d中的各个脚本,而去通过make 执行刚刚写好的runlevel.mk,实现并行启动服务。 很简单,一行判断语句 ^_^ /etc/rc.d/init.d/rc : #!/bin/sh# Begin $rc_base/init.d/rc - Main Run Level Control Script # Based on rc script from LFS-3.1 and earlier.# Rewritten by Gerard Beekmans - gerard@linuxfromscratch.org . /etc/sysconfig/rc. $rc_functions # This sets a few default terminal options.stty sane # These 3 signals will not cause our script to exittrap "" INT QUIT TSTP [ "" != "" ] && runlevel= if [ "$runlevel" = "" ]thenecho "Usage: <runlevel>" >&2exit 1fi previous=$PREVLEVEL[ "$previous" = "" ] && previous=N if [ ! -d $rc_base/rc$runlevel.d ]thenecho "$rc_base/rc$runlevel.d does not exist"exit 1fi # Attempt to stop all service started by previous runlevel,# and killed in this runlevelif [ "$previous" != "N" ]thenfor i in $(ls -v $rc_base/rc$runlevel.d/K* 2> /dev/null)do check_script_status suffix=$prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffixsysinit_start=$rc_base/rcsysinit.d/S[0-9][0-9]$suffix if [ "$runlevel" != "0" ] && [ "$runlevel" != "6" ]thenif [ ! -f $prev_start ] && [ ! -f $sysinit_start ]thenecho -n -e $WARNINGecho "$i can't be executed because it was"echo "not started in the previous runlevel ($previous)"echo -n -e $NORMALcontinuefifi$i stoperror_value=$? if [ "$error_value" != "0" ]thenprint_error_msgfidonefi ################# 由于我都是从文本模式登陆,所以加上判断句,如果 ##runlevel为3的话,就去执行runlevel.mk,而不逐一执行这些脚本if [ "$runlevel" = 3 ]then make -j -f /etc/rc.d/runlevel.mk RUNLEVEL=3 JOB=start # -j 表示以并行的方式去启动在runlevel.mk中定义的服务 # -f 指定MakeFile为runlevel.mk,否则make只尝试运行 #当前目录下的MakeFile.RUNLEVEL=3在这里没有任何意义,因为 #我没有使用$runlevel可以在任何run-level下并行服务 # #JOB=start表示去start /etc/rc.d/rc3.d中的服务 else #如果启动级别不是3的话,仍然按照正常去引导系统. #这样就不用写stop的脚本,我只想让系统启动的更快些 #因为lfs的启动脚本比较怪,它不象其他的发行版使用/etc/rc.d/rc.sysinit #作为系统的初始化,而是把那些过程分开成几个脚本运行 #si::sysinit:/etc/rc.d/init.d/rc sysinit 传入的sysinit参数去执行 #/etc/rc.d/rcsysinit.d目录下的脚本,这样我就不能轻易的使用$runlevel #去使在任何运行级别都可以并行服务了,它会传进来个sysinit @_@ #for i in $( ls -v $rc_base/rc$runlevel.d/S* 2> /dev/null) do if [ "$previous" != "N" ]thensuffix=$stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffixprev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix [ -f $prev_start ] && [ ! -f $stop ] && continuefi check_script_status case $runlevel in0|6) $i stop ;;*) $i start ;;esacerror_value=$? if [ "$error_value" != "0" ]thenprint_error_msgfidonefi# End $rc_base/init.d/rc 要注意的地方:
每个发行版的rc脚本都不相同,要先熟悉系统启动过程,然后再尝试修改,这样才不会出错。修改rc脚本时,语法必须完全正确。修改后用sh -n rc 测试有没有语法错误有一点错误的话,系统就进不去了。:(另外这个rc脚本位置是由/etc/inittab决定的。就是 "l3:3:wait:/etc/rc.d/init.d/rc 3 "啦 相关资源:
《通过并行化 Linux 系统服务来提高引导速度》http://www-900.ibm.com/developerWorks/cn/linux/l-boot/index.shtml我就是看了这篇文章做的了,打算试试的话,必须要看看啦。里面有作者的各个脚本样例。《From PowerUp To Bash Prompt》http://www.faqs.org/docs/Linux-HOWTO/From-PowerUp-To-Bash-Prompt-HOWTO.html这篇文章详细的介绍了sys V风格的启动过程,绝对的好文!不可错过!
原文转自:http://www.ltesting.net