• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Linux系统原理之整体概述

系统初识 彭东稳 9年前 (2015-10-12) 24484次浏览 已收录 0个评论

首先,要知道计算机有硬件和软件组成。硬件最核心的就是五大部件,分别是计算器、控制器、存储器、输入设备、输出设备;这也就是冯若依曼体系结构,如下图所示:

Linux系统原理之整体概述

再向上就是我们的OS操作系统,但是要明白操作系统本身是不做任何有意义性的工作,这些工作都是由操作系统之上特定的应用程序来完成。

然后把它们组合到一块来看,首先就是硬件系统。在CPU中除了计算器和控制器之外,还需要了解寄存器和缓存等。寄存器在计算机内部是非常重要的。而缓存则是用来协调各部件之间速度不协调的问题而设定的,同时也是提供计算机性能的一个重要组件。可以说缓存在计算机中无处不在。计算机除了CPU,还需要存储器(内存)用来存储数据的,而现代内存存储器其实是编址结构的(平面编址,比如编址方式从0000000-11111111),不然CPU是无法访问的。而CPU可以寻址多少内存,这取决于CPU的位长,32位的CPU可以寻址2的32次方个存储单元(内存每一个单元是1字节)而64位的CPU可以寻址2的64次方个存储单元。但是由于内存属于易失性存储器,一断电数据就都没有了。所以就需要一些外部存储设备如光盘,硬盘等也称为I/O设备。在计算机上外部I/O设备有很多不可能都直接连接到CPU总线上去,而是通过我们当前主板上通过一些芯片把这些I/O总线汇总起来之后再连入当前CPU的总线上去,而这些芯片有高速芯片就是北桥和低速芯片南桥。北桥离CPU比较近用来连接内存(显卡也有接入北桥的,因为数量大),而南桥就是用来汇聚各I/O设备的然后连入北桥。但现在也有一些如PCI-E就是直接连接到北桥上面的。然后可以通过PCI-E来连接I/O设备。

 

接着我们回想一下我们的计算机上面有这么多I/O设备,在某一个时间点有某一个I/O设备发生I/O事件时怎么让CPU在第一时间得知呢?这就需要一种机制如CPU不断地去轮询检查I/O设备,当然这种方式非常低效。第二种是中断机制,当其中某种I/O设备发生I/O事件时如网卡接收到ping包或键盘鼠标动了一下就会通过中断控制器来通知CPU,CPU在某个针脚上发现中断控制器有事件产生于是去通过跟中断控制器交互从而得知到底是哪个硬件发生了中断。而CPU又如何得知是哪个I/O设备发生中断了呢?由于I/O总线是汇总的所有I/O都是通过一个总线传输数据所以也无法判别到底是哪个。所以又有了I/O端口。计算机一开机所有硬件都会向CPU申请I/O端口使用。这些都是计算机工作的基本概念。而这些基本概念的理解是有助于更好地理解计算机是怎样工作的。

 

硬件本身提供了计算和运算能力,但事实上它本身并不做任何具体工作的。如果要做工作我们需要应用程序。所以我们在利用计算机的这种能力这个芯片和所谓的计算机语言实现编程就可以开发出应用程序了。这个应用程序要想真正工作就需要能够驱动和使用计算机芯片,由于各种硬件的不同所以只能针对某一套计算机硬件进行编程,如果有一天硬件发生变化那么就需要重新编写新的应用程序。又由于底层的硬件是非常复杂的那么想编写一个程序可以跑在上面也是非常困难的。所以就出现了操作系统这个一个程序主要用于把底层的各个细节都隐藏起来而提供一个统一的规范的风格重新提供给程序员编程。所以无论你的CPU事Intel的还是AMD的,内存是金士顿的其它厂家的,这些都由操作系统来处理然后通过软件提供一个统一规范简介的接口输出。然后程序员在编程的时候就不用关心底层硬件了,只需要关心这个操作系统本身是什么样子的。这就是操作系统的重要意义所在,当然操作系统的功能非常强大而这些只是它的一部分功能而已。

操作系统通过统一的接口将计算机的计算能力输出出来,这些输出我们通常称之为系统调用(System Call)。比如在编程时需要用到声卡那么只需要调用系统输出的接口即可而不需要关系声卡是哪个厂家的和驱动这个声卡的驱动程序。这些细节和底层部分都是由操作系统来实现了。所以我们说操作系统就是虚拟机把硬件的计算机能力通过另外一个方式虚拟出来了提供给应用程序使用。而操作系统提供的这种系统调用对于软件级别来说也属于非常底层,想要实现一个功能就需要很多个系统调用组合而成,并且每一个软件都需要这么做,甚至有一些通用功能是每一个软件都需要使用的。于是在系统调用之上又出现了系统库(二次开发的系统调用),又称为之API。这些库就是用于把底层的系统调用组合成一个具体的功能实现然后直接提供给程序员使用,然后有很多库也并也没有使用一个系统调用而就是为了实现一个功能而开发的。所以现在在编写程序时大部分功能都是可以直接使用系统或其它软件提供的库。如果某一个功能没有库可用,那么就需要直接调用系统调用来实现了。所以系统库就是操作系统提供给编程人员的友好环境,封装了各种各样的功能。

如果说现在有两个不同的操作系统,如果一个程序员利用了A操作系统提供的库开发了一个程序,想要在B操作系统上运行取决于什么?是不是就是双方的库是相同的或是程序员所调用的接口是相同的。如果一个软件在一个系统上开发的,能够做到在其他操作系统上也能运行,至少编译之后可以运行。那么最重要的一点是不是要取决于这个库或库提供的接口啊!其实库也是有一种规范的就是POSIX规范。POSIX 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。

现在的绝大部分系统都遵循POSIX规范,如windows,Linux,Unix等它们都是C语言研发的。事实上现在在Windows上基于ANSI C研发的程序在Linux上编译是没有问题的。注意这里说的是编译不是运行,因为API只是编程规范。事实上真正程序在执行的时候还要需要ABI(application binary interface,应用二进制接口)。而ABI则是跟你的内核执行二进制的机制有关,或跟你二进制程序本身的格式密切相关。所以你在Windows上所编译的程序是.exe格式的,而在Linux上编译的程序是ELF格式的。所以你在Windows上编译好的程序你在Linux上时运行不了的。反之亦然,因为它们的二进制格式不一样。

前面也说了,想要计算机为我们做具体的工作时就需要特定的应用程序。在我们操作系统上有很多应用程序,其中有一些比较特殊是随着操作系统一起启动的。那么这些应用程序就是为了系统能够提供正常功能就需要运行的。这种进程再Linux上通常被称为守护进程。在我们的Linux操作系统上某一时刻想要去启动一个程序该怎么去指挥操作系统去启动这个程序呢?那么就需要一个能够跟操作系统交互的接口,在Linux上提供的这个接口的就是我们的特定程序Shell。Shell本身也是一种程序,它也需要在内核的支持下才能跑起来。那么Shell又是怎么启动的呢?很显然,操作系统在初始化的时候必须以服务的形式把接口功能启动,不然就无法进入计算机了。所以开机以后有些程序必须要能自动启动,而有些则不需要,必要的时候我们在指挥程序启动即可。其实在Linux中当系统初始化完成之后就会生成一个init进程器PID号为1,这个进程什么也不干主要负责用来启动其它的子进程,init是所有进程的父进程。

在一个系统内,运行多个进程也就意味着运行多个程序,也就是多任务的概念。一个系统的运行就是内核加内核之上运行的进程(进程就是一个程序在计算机上运行的实体)所组成;系统分内核空间和用户空间分别对应CPU的ring0特权指令和ring3普通指令;再利用虚拟内存技术来存放每个独立的进程。我们现在的系统都是所谓的多进程多任务无非就是把CPU分片,内存分页然后由内核来负责管理分配硬件给系统中的每个进程使用的限制;调度进程到CPU上执行并分配给多长时间;内核必须要追踪每个进程的执行状态而且还要明确知道当前系统上运行了多少个进程;维护一个进程队列慢慢交给CPU运行。还有一个就是中断技术。这几种技术也就是多任务得以实现的核心。

在Linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为1/100秒),这段时间内进程被分配到CPU,然后独占使 用。如果使用完,同时未到时间片的规定时间,那么就主动放弃CPU的占用,如果到时间片尚未完成工作,那么CPU的使用权也会被收回,进程将会被中断挂起等待下一个时间片。其实在内核中维护了一个内核数据结构称为task structure,用来保存每个进程的PPID、PID、NAME和上一次执行的指令到第几条了等等,还有存放这此进程的逻辑页面占据对应的物理页面(负责转换这两者之间数据的是CPU中的芯片MMU内存管理单元)。然后根据这些信息来调度进程到CPU上执行和进程的保存现场和恢复现场,系统中进程之间的上下文切换是非常麻烦的消耗系统资源的。


Linu
x系统整体结构,如下图:

Linux系统原理之整体概述

系统的硬件资源都是有内核统一管理,应用层程序要使用这些资源必须向内核申请;应用层向内核申请功能是通过系统调用(system call)完成的。那么系统调用是如何实现的呢? 当前大部分操作系统通过软中断实现。 应用程序调用内核函数时,会同时发送一个中断到cpu,cpu在中断向量表里找到此中断号对应的处理程序,从而执行内核代码。现在x86等cpu已经从硬件层开始支持系统调用这个功能,并且性能提升了不少。 因为一个程序的越少的系统调用性能越好。 通过命令strace可以看到你的可执行代码都调用了那些系统调用。

现在常用的CPU架构为SMP结构(即所有CPU共享L1/L2,memory,外设),区别与NUMA结构。 所以一个某一个瞬间一个进程/线程只会在一个核上运行,一个进程频繁的在不同的CPU上运行性能会降低;因为每个核之间不共享高速缓存。如果进程频繁在核之间切换,高速缓存命中率下降,严重影响性能。操作系统内核会保证一个进程尽量运行在一个核上,并保证每个核的负载均衡。我们知道cpu要频繁的响应中断,有些中断来了,cpu必须放下正在执行的进程去响应中断,比如对于web服务器网络流量很高的服务器,网络中断很频繁;操作系统提供一个亲和度算法将一个终端号绑定到一个核上。这样其他核就不会受中断影响,提高系统性能。

cat 02 >> /proc/irq/xx/smp_affinity


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (2)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!