7.3 启动与内核

内核


  • 内核类型

单内核

设计简单,把内核从整体上作为一个单独的大的过程来实现,内核所有服务都运行在同一地址空间,内核可以直接调用函数,就好像用户空间的应用程序一样

微内核

依据功能划分为多个独立的过程,每个过程叫做一个服务器。理想情况下,只有强烈请求特权的服务器才能运行在特权模式下,其它服务器都运行在用户空间。因为所有服务器都保持独立的地址运行空间,因此不能像单内核那样直接调用函数,而是通过消息传递处理微内核之间的通信:IPC机制。

因为IPC机制的开销多于函数调用,又因为会涉及内核空间与用户空间的上下文切换,因此,消息传递需要一定的周期,而单内核的函数调用却没有这些开销。结果,所有实际应用的基于微内核的系统都让大部分或全部服务器都位于内核,这样就可以直接调用函数,消除频繁的上下文切换。Windows NT内核(Windows XP、Windows 7等)和Mach(Mac OS X的组成部分)都是微内核的典型实例。不管是Windows NT还是Mac OS X,都在其新版本中不让微内核服务器运行在用户空间,很显然,这违背了微内核的设计初衷。

Linux则采用了单内核的方式。

  • 核心文件

/boot/vmlinuz-VERSION-release  核心文件
/lib/modules/VERSION-release  模块文件
ramdisk  辅助的伪根系统

initramfs 是在 kernel 2.5中引入的技术,实际上它的含义就是:在内核镜像中附加一个cpio包,这个cpio包中包含了一个小型的文件系统,当内核启动时,内核将这个 cpio包解开,并且将其中包含的文件系统释放到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,作为用户层进程来执行。这样带来的明显的好处是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制

  • 内核参数优化

# 内核panic时,1秒后自动重启
kernel.panic = 1

# 允许更多的PIDs (减少滚动翻转问题); may break some programs 32768
kernel.pid_max = 32768

# 内核所允许的最大共享内存段的大小(bytes)
kernel.shmmax = 4294967296

# 在任何给定时刻,系统上可以使用的共享内存的总量(pages)
kernel.shmall = 1073741824

# 设定程序core时生成的文件名格式
kernel.core_pattern = core_%e

# 当发生oom时,自动转换为panic
vm.panic_on_oom = 1

# 表示强制Linux VM最低保留多少空闲内存(Kbytes)
vm.min_free_kbytes = 1048576

# 该值高于100,则将导致内核倾向于回收directory和inode cache
vm.vfs_cache_pressure = 250

# 表示系统进行交换行为的程度,数值(0-100)越高,越可能发生磁盘交换
vm.swappiness = 20

# 仅用10%做为系统cache
vm.dirty_ratio = 10

# 增加系统文件描述符限制 2^20-1
fs.file-max = 1048575



###网络层优化###

# listen()的默认参数,挂起请求的最大数量,默认128
net.core.somaxconn = 1024

# 增加Linux自动调整TCP缓冲区限制
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# 进入包的最大设备队列.默认是300
net.core.netdev_max_backlog = 2000

# 开启SYN犯洪保护
net.ipv4.tcp_syncookies = 1

# 开启并记录欺骗,源路由和重定向包
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# 处理无源路由的包
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# 开启反向路径过滤
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# 确保无人能修改路由表
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# 增加系统IP端口限制
net.ipv4.ip_local_port_range = 9000 65533

# TTL
net.ipv4.ip_default_ttl = 64

# 增加TCP最大缓冲区大小
net.ipv4.tcp_rmem = 4096 87380 8388608
net.ipv4.tcp_wmem = 4096 32768 8388608

# Tcp自动窗口
net.ipv4.tcp_window_scaling = 1

# 进入SYN包的最大请求队列.默认1024
net.ipv4.tcp_max_syn_backlog = 8192

# 打开TIME-WAIT套接字重用功能,对于存在大量连接的Web服务器非常有效。 
net.ipv4.tcp_tw_recycle = 1 
net.ipv4.tcp_tw_reuse = 0  

# 表示是否启用以一种比超时重发更精确的方法(请参阅 RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项
net.ipv4.tcp_timestamps = 0

# 表示本机向外发起TCP SYN连接超时重传的次数
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2

# 减少处于FIN-WAIT-2连接状态的时间,使系统可以处理更多的连接。 
net.ipv4.tcp_fin_timeout = 10  

# 减少TCP KeepAlive连接侦测的时间,使系统可以处理更多的连接。 
# 如果某个TCP连接在idle 300秒后,内核才发起probe.如果probe 2次(每次2秒)不成功,内核才彻底放弃,认为该连接已失效.
net.ipv4.tcp_keepalive_time = 300 
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_intvl = 2

# 系统所能处理不属于任何进程的TCP sockets最大数量
net.ipv4.tcp_max_orphans = 262144

# 系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。
net.ipv4.tcp_max_tw_buckets = 20000 

# arp_table的缓存限制优化
net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh3 = 4096

启动


  • CentOS 6

1.加载 BIOS 的硬件信息,获取第一个启动设备
2.读取第一个启动设备 MBR 的引导加载程序(grub)的启动信息
3.加载核心操作系统的核心信息,核心开始解压缩,并尝试驱动所有的硬件设备
4.核心执行 init 程序,并获取默认的运行信息
5.init程序执行 /etc/rc.d/rc.sysinit 文件
6.启动核心的外挂模块
7.init执行运行的各个批处理文件(scripts)
8.init 执行 /etc/rc.d/rc.local
9.执行 /bin/login 程序,等待用户登录
10.登录之后开始以 Shell 控制主机

POST

按下电源,计算机开始通电,最重要的是要接通 cpu 的电路,然后通过cpu的针脚让 cpu 运行起来,只有 cpu 运行起来才能执行相关代码跳到 BIOS。

BIOS 是按下开机键后第一个运行的程序,它会读取 CMOS 中的信息,以了解部分硬件的信息,比如硬件自检(post)、硬件上的时间、硬盘大小和型号等。当硬件检测和信息获取完毕,开始初始化硬件,最后从排在第一位的启动设备中读取MBR,如果第一个启动设备中没有找到合理的MBR,则继续从第二个启动设备中查找,直到找到正确的MBR

BOOTLOADER

MBR 一共512个字节
446b 的 bootloader(引导加载器)用来引导某个分区加载
64b   的 partition table(分区表)每16b标识一个分区,只能划分4个分区
2b     的 magic nmuber(魔数)用于标记MBR是否有效,恒定为55AA

GRUB

使用 grub 管理启动,则 MBR 中的 boot loader 是由 grub 程序安装的,此外还会安装其他的 boot loader。CentOS 6 使用的是传统的grub,而 CentOS 7 使用的是 grub2

stage1 的作用是当 MBR 段 boot loader 执行后,它的目的是跳转到 stage1_5 的第一个扇区上,然后由该扇区的代码加载剩余的内容,并跳转到 stage2 的第一个扇区上

stage1_5存在的理由是因为stage2功能较多,导致其文件体积较大。但stage1并不识别boot分区的文件系统类型,所以借助中间的辅助boot loader即stage1_5来跳转。stage1_5的目的之一是识别文件系统,但文件系统的类型有很多,所以对应的stage1_5也有很多种

[root@CentOS69 ~]# ls /boot/grub/*_stage1_5
/boot/grub/e2fs_stage1_5  /boot/grub/ffs_stage1_5      /boot/grub/jfs_stage1_5    /boot/grub/reiserfs_stage1_5  /boot/grub/vstafs_stage1_5
/boot/grub/fat_stage1_5   /boot/grub/iso9660_stage1_5  /boot/grub/minix_stage1_5  /boot/grub/ufs2_stage1_5      /boot/grub/xfs_stage1_5

虽然有很多种 stage1_5,但每个 boot 分区也只能对应一种 stage1_5。这个 stage1_5 对应的 boot loader 一般会被嵌入到 MBR 后、第一个分区前的中间一段空间中。当执行了stage1_5对应的boot loader后,stage1_5就能识别出boot所在的分区,并找到stage2文件的第一个扇区,然后跳转过去

当控制权交给了stage2,stage2就能加载grub的配置文件/boot/grub/grub.conf并显示菜单并初始化grub的运行时环境,当选中操作系统后,stage2将和kernel.img一样加载操作系统内核,传递内核启动参数,并将控制权交给操作系统内核

当误删了 grub 文件,可以使用 grub-install 引导盘 进行修复,但是无法创建 grub.conf 与 splash.xpm.gz 文件

[root@CentOS69 ~]# grub-install /dev/sda
Probing devices to guess BIOS drives. This may take a long time.
Installation finished. No error reported.
This is the contents of the device map /boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.

(fd0)	/dev/fd0
(hd0)	/dev/sda

grub-install 命令无法修复 grub.conf 文件,所以在修复完以后一定要手创建 grub.conf 与 splash.xpm.gz

grub.conf

[root@CentOS69 ~]# cat /boot/grub/grub.conf 
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/sda3
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0   #默认使用第几个选项启动
timeout=5   #超时时间
password linux   #修改启动项的密码
splashimage=(hd0,0)/grub/splash.xpm.gz  #载入背景
hiddenmenu
title CentOS 6 (2.6.32-696.el6.x86_64)
	root (hd0,0)
	kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=UUID=92cb6d7b-cb87-4988-9873-027413ab3e87 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
	initrd /initramfs-2.6.32-696.el6.x86_64.img

每个 title 中的 kernel 与 initrd 字段顺序固定,若设置错误可以在启动菜单中通过 e 键进入编辑模式进行调整。当有 password 项时需要通过 p 键输入密码后再进入编辑模式

splash.xpm.gz

这是一个登录界面时的背景图片,可以自定义

核心文件解压缩

所有的内核都是以 bzImage 方式压缩过的,压缩后 CentOS 6 的内核大小大约为 4M,CentOS 7 的内核大小大约为 5M。内核要能正常运作下去,它需要进行解压释放

[root@CentOS69 ~]# ll -h /boot/vmlinuz-2.6.32-696.el6.x86_64 
-rwxr-xr-x. 1 root root 4.1M Mar 22  2017 /boot/vmlinuz-2.6.32-696.el6.x86_64

解压释放之后,将创建 pid 为 0 的 idle 进程,该进程非常重要,后续内核所有的进程都是通过 fork 它创建的。然后创建 pid=1 和 pid=2 的内核进程。pid=1 的进程也就是 init 进程,pid=2 的进程是 kthread 内核线程,它的作用是在真正调用 init 程序之前完成内核环境初始化和设置工作

要加载 /sbin/init 程序,首先要找到根分区,根分区是有文件系统的,所以内核需要先识别文件系统并加载文件系统的驱动,但文件系统的驱动又是放在根分区的,所以必须要有一种方法能够暂时加载文件系统:

解决方法采用的中间过渡文件称为 init ramdisk,它是在安装完操作系统时生成的,这样它会收集到当前操作系统的根文件系统是什么类型的文件系统,也就能只嵌入一个对应的文件系统驱动模块使其变得足够小

[root@CentOS69 ~]# ll -h /boot/initramfs-2.6.32-696.el6.x86_64.img 
-rw-------. 1 root root 26M Jun  3 21:39 /boot/initramfs-2.6.32-696.el6.x86_64.img

当误删了 initramfs 文件时,可以使用 mkinitrd 命令再次制作 ramdisk

[root@CentOS69 ~]# mkinitrd /boot/initramfs-`uname -r`.img `uname -r`

initramfs

旧版本 CentOS 中 initrd 必须是一个文件系统,是在内存中模拟出磁盘分区的,所以内核必须要带有它的文件系统驱动。而 initramfs 则仅仅只是一个镜像压缩文件而非文件系统,所以它不需要带文件系统驱动,在加载时,内核会将其解压的内容装入到一个 tmpfs 中

initramfs 和 initrd 最大的区别在于 init 进程的区别对待。initramfs 为了尽早进入用户空间,它将 init 程序集成到了 initramfs 镜像文件中,这样就可以在 initramfs 装入 tmpfs 时直接运行 init 进程,而不用去找根文件系统下的 /sbin/init,由此挂载根文件系统的工作将由 init 来完成,而不再是内核线程 kernel_init 完成,最后从虚根切换到实根

系统初始化

操作系统初始化涉及了不少过程,大致如下:读取运行级别→初始化系统类的环境→根据运行级别初始化用户类的环境→执行rc.local文件完成用户自定义开机要执行的命令→加载终端

读取运行级别

当 init 进程掌握控制权后,意味着已经进入了用户空间,后续的事情也将以用户空间为主导来完成。首先会去读取 /etc/inittab 文件来读取运行级别

id:5:initdefault:

# 0:halt,即关机
# 1:单用户模式
# 2:不带NFS的多用户模式
# 3:完整多用户模式
# 4:保留未使用的级别
# 5:X11,即图形界面模式
# 6:reboot,即重启

系统环境初始化

执行系统初始化脚本(/etc/rc.d/rc.sysinit),对系统进行基本的配置,以读写方式挂载根文件系统及其它文件系统,到此系统算是基本开始运行,其中脚本中初始化内容大致有:

    获取网络环境与主机类型。首先会读取网络环境设置文件"/etc/sysconfig/network",获取主机名称与默认网关等网络环境
    测试与载入内存设备/proc及usb设备/sys。除了/proc外,系统会主动检测是否有usb设备,并主动加载usb驱动,尝试载入usb文件系统
    决定是否启动SELinux
    接口设备的检测与即插即用(pnp)参数的测试
    用户自定义模块的加载。用户可以再"/etc/sysconfig/modules/*.modules"加入自定义的模块,此时会加载到系统中
    加载核心的相关设置。按"/etc/sysctl.conf"这个文件的设置值配置功能
    设置系统时间(clock)
    设置终端的控制台的字形
    设置raid及LVM等硬盘功能
    以方式查看检验磁盘文件系统
    进行磁盘配额quota的转换
    重新以读取模式载入系统磁盘
    启动quota功能
    启动系统随机数设备(产生随机数功能)
    清楚启动过程中的临时文件
    将启动信息加载到"/var/log/dmesg"文件中

执行批处理文件

当 /etc/rc.d/rc.sysinit 执行完后,系统就可以顺利工作了,只是还需要启动系统所需要的各种服务,这时会根据 /etc/inittab 中定义的运行级别初始化用户环境

[root@CentOS69 ~]# ls /etc/rc.d/
init.d  rc  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.local  rc.sysinit

执行 /etc/rc.d/rc 脚本。该文件定义了服务启动的顺序是先 K 后 S,而具体的每个运行级别的服务状态是放在 /etc/rc.d/rc*.d(*=0~6)目录下,所有的文件均是指向 /etc/init.d 下相应文件的符号链接。rc 脚本通过执行 /sbin/runlevel 来确定系统的启动级别,然后才去执行/etc/rc.d/rc*.d下的文件

所有这些文件都是由 /etc/rc.d/rc 这个程序调用的,K 开头的则传给 rc 一个 stop 参数,S 开头的则传给 rc 一个 start 参数

[root@CentOS69 ~]# /etc/rc.d/rc3.d/S28autofs start
Starting automount: automount: program is already running.
                                                           [  OK  ]

当 rc*.d 中以 K 开头的服务并为启动,rc 脚本并不会继续传递 stop 参数,判断条件是 /var/lock/subsys/ 中是否有对应服务同名的文件

[root@CentOS69 ~]# ll /var/lock/subsys/
total 0
-rw-r--r-- 1 root root 0 Jun 10 20:55 abrt-ccpp
-rw-r--r-- 1 root root 0 Jun 10 20:55 abrtd
-rw-r--r-- 1 root root 0 Jun 10 20:55 acpid
-rw-r--r-- 1 root root 0 Jun 10 20:55 atd
-rw-r--r-- 1 root root 0 Jun 10 20:55 auditd
-rw-r--r-- 1 root root 0 Jun 11 00:33 autofs
... ...

执行自定义脚本文件

而在 rc[2-5].d 这几个目录中,都有一个 S99local 文件,且它们都是指向 /etc/rc.d/rc.local 的软链接。S99 表示最后启动的一个程序,所以 rc.local 中的程序是上述四个运行级别初始化过程中最后运行的一个脚本。这是 Linux 提供给我们定义自己想要在进入运行级别就执行的脚本文件

[root@CentOS69 ~]# ll /etc/rc.d/rc3.d/S99local 
lrwxrwxrwx. 1 root root 11 Jun  3 21:33 /etc/rc.d/rc3.d/S99local -> ../rc.local

执行登录系统/bin/login

Linux是多任务多用户的操作系统,它允许多人同时在线工作,但每个人都必须要输入用户名和密码才能验证身份并最终登录。

虚拟终端是由 getty 命令(get tty)来完成的,getty 命令有很多变种,有 mingetty、agetty、rungettty 等,在 CentOS 5 和 CentOS 6 都使用 mingetty,在 CentOS 7 上使用 agetty。getty 命令的作用之一是调用登录程序 /bin/login

[root@CentOS69 ~]# cat /etc/init/tty.conf 
# tty - getty
#
# This service maintains a getty on the specified device.
#
# Do not edit this file directly. If you want to change the behaviour,
# please create a file tty.override and put your changes there.

stop on runlevel [S016]

respawn   #表示当终端进程消失,则会立刻重启终端
instance $TTY
exec /sbin/mingetty $TTY
usage 'tty TTY=/dev/ttyX  - where X is console id'

 

 

 

 

 

 

 

 

 

 

 

 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/M30_Miriam/article/details/80341697
个人分类: Linux基础
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭