运维面试题

Posted by 墨晴 on October 22, 2019

运维面试题

一、从输入www.baidu.com到展现到浏览器,经过哪些过程?

环节如下:
DNS寻址 --> 负载均衡 --> 建立链接 --> 发送请求 --> 服务器处理并回传 --> 浏览器接受并渲染 --> 释放链接

详述:

1.DNS寻址

首先寻找域名对应的IP,为提高效率,DNS解析是有层次的,具体的原则就是就近原则。浏览器首先去浏览器缓存里找,如果没有,会从hosts文件中寻找对应的IP地址,如果找到了,就是用该IP;如果找不到,便会到主机所连网络的高速缓存中去寻找;如果还是没找到。这个时候便会通过递归查询的方式到本地域名服务器去查询,如果本地域名服务器中有该url地址对应的IP地址便将其返回给主机;反之,就会采用迭代查询的方式代替主机去询问根域名服务器,如果根域名服务器也不知道,它就会告诉本地域名服务器,接下来该去哪台顶级域名服务器查询,如果该顶级域名服务器也不知道,就会告诉本地域名服务器接下来改去哪台权限域名服务器查询,等等..知道查询到该url对应的IPD地址,本地域名服务器拿到该IP地址,首先会自己缓存一份,然后告诉浏览器。

2.负载均衡

一般通过DNS解析拿到的是公网IP。一般互联网企业为了高并发高可用,会使用四层/七层负载均衡集群。请求经过四层、七层负载均衡算法被分配到真实提供服务的后端服务器上。

3.建立链接

找到目标服务器后,需要先将数据的传输通道建立起来,TCP三次握手: 第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

4.发送请求

建立起连接之后,浏览器-服务器双方就可以开始传输数据了。首先,在请求报文中,需明确请求的端口,然后浏览器向服务器发送请求。从应用层开始,消息以HTTP请求报文的形式在传输层、网络层、数据链路层逐层打上头部,进行传输。在服务器端接受数据的时候,再逐层解套,最终接收到HTTP协议的请求报文,保证请求报文正确完整的被服务器端接收。

5.处理并回传

服务器端接收到请求报文,就会根据请求报文提供的要求,比如端口,参数之类的,去执行响应的操作,并将执行结果以响应报文的形式回传给浏览器。至于这个响应的操作,如果请求的是静态资源,现成的,那就直接回传,如果请求的资源需要动态生成,则web服务器就会调用不同的程序和调用数据库生成最终的HTML文件,再回传给浏览器。

6.浏览器接受并渲染

同样经过层层的增加头部和去除头部,浏览器最终得到服务器返回的HTML数据,这个时候浏览器就会加载数据,根据内容开始渲染页面,数据加载完成就会触发onload的事件。 浏览器会根据响应的内容,来处理响应。如果响应可缓存,浏览器将把响应存入缓存。 需要注意的时候,第一次浏览器获得的是HTML文件,但是HTML文件如果继续有新资源的请求,那么就会建立新的连接,跟刚刚的过程一样。比如外部的css,js,图片等文件。 现代浏览器渲染页面的过程是这样的:jiexiHTML以构建DOM树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树 DOM树是由HTML文件中的标签排列组成,渲染树是在DOM树中加入CSS或HTML中的style样式而形成。渲染树只包含需要显示在页面中的DOM元素,像<head>元素或display属性值为none的元素都不在渲染树中。 在浏览器还没接收到完整的HTML文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送HTTP请求重复上述的步骤。在收到CSS文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。

7.释放链接

TCP连接是无状态的,不会永久保存这个状态,所以双方完成一次数据的传输之后,如果没有持续的请求,那就要释放连接。 TCP连接的释放需要四次挥手。客户端和服务器端任意一方发起关闭请求。之所以要四次握手,还是要确认双方都确实完成各自的工作,防止有文件还没传完就断开的连接。


网络

二、三次握手、四次挥手,各种网络状态都是怎么转换的?

三次握手:

在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态。

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。

四次挥手:

第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接受数据。

第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。

第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。

第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

数据传输过程:
超时重传

超时重传机制用来保证TCP传输的可靠性。每次发送数据包时,发送的数据报都有seq号,接收端收到数据后,会回复ack进行确认,表示某一seq 号数据已经收到。发送方在发送了某个seq包后,等待一段时间,如果没有收到对应的ack回复,就会认为报文丢失,会重传这个数据包。

快速重传

接受数据一方发现有数据包丢掉了。就会发送ack报文告诉发送端重传丢失的报文。如果发送端连续收到标号相同的ack包,则会触发客户端的快速重传。比较超时重传和快速重传,可以发现超时重传是发送端在傻等超时,然后触发重传;而快速重传则是接收端主动告诉发送端数据没收到,然后触发发送端重传。

流量控制

这里主要说TCP滑动窗流量控制。TCP头里有一个字段叫Window,又叫Advertised-Window,这个字段是接收端告诉发送端自己 还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。 滑动窗可以是提高TCP传输效率的一种机制。

拥塞控制

滑动窗用来做流量控制。流量控制只关注发送端和接受端自身的状况,而没有考虑整个网络的通信情况。拥塞控制,则是基于整个网络来考虑的。考虑一下这 样的场景:某一时刻网络上的延时突然增加,那么,TCP对这个事做出的应对只有重传数据,但是,重传会导致网络的负担更重,于是会导致更大的延迟以及更多 的丢包,于是,这个情况就会进入恶性循环被不断地放大。试想一下,如果一个网络内有成千上万的TCP连接都这么行事,那么马上就会形成“网络风 暴”,TCP这个协议就会拖垮整个网络。为此,TCP引入了拥塞控制策略。拥塞策略算法主要包括:慢启动,拥塞避免,拥塞发生,快速恢复。

三、为什么连接的时候是三次握手,关闭的时候却是四次挥手?

这是因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。

但是关闭连接时,当Client端发送FIN报文仅仅表示它不再发送数据了但是还能接收数据,Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。


Linux基础

Linux的启动过程

BIOS --> 引导扇区(boot.img) --> diskboot.img -->lzma_decompress.img(实模式到保护模式,
建立分段分页,打开地址线) --> kernel.img (选择一个操作系统) --》 启动内核

1.打开电脑电源,主板通电;主板上的ROM(只读存储器)固化了一些初始化的程序,即BIOS(基本输入输出系统),会被最先读取。首先加电自检,检查CPU、内存、计算机最基本的组成单元(控制器、运算器、存储器)及其他硬件是否有异常,无异常则加载BIOS程序到内存中。

2.MBR-主引导记录,存储于磁盘的头部,大小为512bytes,其中446bytes用于存储BootLoader程序,64bytes用于存储分区表信息,最后2bytes用于MBR的有效性检查。

3.GRUB-多系统启动程序,其执行过程可分为三个步骤:

Stage1:这个其实就是MBR,它的主要工作就是查找并加载第二段Bootloader程序(stage2),但系统在没启动
时,MBR根本找不到文件系统,也就找不到stage2所存放的位置,因此,就有了stage1_5   

Stage1_5:该步骤就是为了识别文件系统   
   
Stage2:GRUB程序会根据/boot/grub/grub.conf文件查找Kernel的信息,然后开始加载Kernel程序,
当Kernel程序被检测并在加载到内存中,GRUB就将控制权交接给了Kernel程序。

4.Kernel-内核,Kernel是Linux系统最主要的程序,实际上,Kernel的文件很小,只保留了最基本的模块,并以压缩的文件形式存储在硬盘中,当GRUB将Kernel读进内存,内存开始解压缩内核文件。讲内核启动,应该先讲下initrd这个文件, initrd(Initial RAM Disk),它在stage2这个步骤就被拷贝到了内存中,这个文件是在安装系统时产生的,是一个临时的根文件系统(rootfs)。 因为Kernel为了精简,只保留了最基本的模块,因此,Kernel上并没有各种硬件的驱动程序,也就无法识rootfs所在的设备, 故产生了initrd这个文件,该文件装载了必要的驱动模块,当Kernel启动时,可以从initrd文件中装载驱动模块,直到挂载真正的rootfs,然后将initrd从内存中移除。 Kernel会以只读方式挂载根文件系统,当根文件系统被挂载后,开始装载第一个进程(用户空间的进程),执行/sbin/init,之后就将控制权交接给了init程序 Init

5.init,初始化,顾名思义,该程序就是进行OS初始化操作,实际上是根据/etc/inittab(定义了系统默认运行级别)设定的动作进行脚本的执行,第一个被执行的脚本为/etc/rc.d/rc.sysinit,这个是真正的OS初始化脚本:   

1、激活udev和selinux;   
2、根据/etc/sysctl.conf文件,来设定内核参数;   
3、设定系统时钟;   
4、装载硬盘映射;   
5、启用交换分区;   
6、设置主机名;   
7、根文件系统检测,并以读写方式重新挂载根文件系统;   
8、激活RAID和LVM设备;   
9、启用磁盘配额;   
10、根据/etc/fstab,检查并挂载其他文件系统;   
11、清理过期的锁和PID文件 执行完后,根据配置的启动级别,执行对应目录底下的脚本,最后执行/etc/rc.d/rc.local这个脚本,至此,系统启动完成。

6.Runlevel-运行级别,不同的级别会启动的服务不一样,init会根据定义的级别去执行相应目录下的脚本,Linux的启动级别分为以下几种:

0:关机模式
1:单一用户模式(直接以管理员身份进入)
2:多用户模式(无网络)
3:多用户模式(命令行)
4:保留
5:多用户模式(图形界面)
6:重启

top命令里每行有哪些字段,都是什么意思?

第一行:当前时间、系统已运行时间、当前登录用户的数量、最近1、5、15分钟内的平均负载

load
系统平均负载表示
  系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程树。如果一个进程满足以下条件则其就会位于运行队列中:
  - 它没有在等待I/O操作的结果
  - 它没有主动进入等待状态(也就是没有调用’wait’)
  - 没有被停止(例如:等待终止)
  Update:在Linux中,进程分为三种状态,一种是阻塞的进程blocked process,一种是可运行的进程
  runnable process,另外就是正在运行的进程running process。当进程阻塞时,进程会等待I/O设备
  的数据或者系统调用。
  进程可运行状态时,它处在一个运行队列run queue中,与其他可运行进程争夺CPU时间。 系统的load是指
  正在运行running one和准备好运行runnable one的进程的总数。比如现在系统有2个正在运行的进程,3个
  可运行进程,那么系统的load就是5。load average就是一定时间内的load数量。
  
  Linux top命令的load average满负荷是cpu核心的个数,实际上应该比满负荷的值要小,不然会影响性能。
  如果负载超过cpu核心数的话,则说明系统超负荷运行。而负载最大值和并发执行的线程数有关,大小基本和并发
  执行的线程数一致。

第二行:任务(进程)总数、运行进程数、睡眠进程数、停止进程数、僵尸进程数

第三行:CPU状态

这里显示不同模式下所占cpu时间百分比,这些不同的cpu时间表示:
us, user: 运行(未调整优先级的) 用户进程的CPU时间
sy,system: 运行内核进程的CPU时间
ni,niced:运行已调整优先级的用户进程的CPU时间
id:空闲CPU百分比
wa,IO wait: 用于等待IO完成的CPU时间
hi:处理硬件中断的CPU时间
si: 处理软件中断的CPU时间
st:这个虚拟机被hypervisor偷去的CPU时间(译注:如果当前处于一个hypervisor下的vm,实际上hypervisor也是要消耗一部分CPU处理时间的)。

第四行:内存使用 - 物理内存使用

全部可用内存、已使用内存、空闲内存、缓冲内存

第五行:内存使用 - 虚拟内存使用(交换空间)

全部交换空间、已使用交换空间、空闲交换空间、缓冲交换空间

第六行:空行

第七行:各进程的状态监控

PID:进程ID,进程的唯一标识符
USER:进程所有者的实际用户名。
PR:进程的调度优先级。这个字段的一些值是'rt'。这意味这这些进程运行在实时态。
NI:进程的nice值(优先级)。越小的值意味着越高的优先级。负值表示高优先级,正值表示低优先级
VIRT:进程使用的虚拟内存。进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES:驻留内存大小。驻留内存是任务使用的非交换物理内存大小。进程使用的、未被换出的物理内存大小,
单位kb。RES=CODE+DATA
SHR:SHR是进程使用的共享内存。共享内存大小,单位kb
S:这个是进程的状态。它有以下不同的值:
D - 不可中断的睡眠态。
R – 运行态
S – 睡眠态
T – 被跟踪或已停止
Z – 僵尸态
%CPU:自从上一次更新时到现在任务所使用的CPU时间百分比。
%MEM:进程使用的可用物理内存百分比。
TIME+:任务启动后到现在所使用的全部CPU时间,精确到百分之一秒。
COMMAND:运行进程所使用的命令。进程名称(命令名/命令行)