初步了解Kubernetes(k8s)及其工作原理

k8s是介于应用服务服务器之间的中间层,通过策略,协调和管理多个应用服务,只需要一个yaml文件配置,定义应用的部署顺序等信息,就能自动部署应用到各个服务器上,还可以实现服务器的自动重启,自动扩缩容

k8s架构原理

为了实现以上功能,k8s将服务器划分为两部分,控制平面(control plane)、工作结点(Node)

字面意思,控制平面控制工作结点,工作节点负责运行各个应用服务

控制平面内部组件
  • API Server
    通过k8s提供的API接口,就可以快捷地操作服务器资源
  • Scheduler
    调度器,负责找到cpu和内存资源充足的服务器,在该服务器上部署应用
  • Controller Mannager
    控制管理器,负责找到服务器后控制和关闭服务
  • 存储层
    保存上述功能产生的数据,目前使用的是etcd
Node内部组件

使用了k8s之后,只需要将服务代码打包成Container Image(容器镜像),就能一行命令将它部署。而容器镜像简单理解就是应用代码和系统环境的压缩包。
为了下载和部署容器镜像,Node中有一个Container runtime组件
每一个应用服务都可以认为是一个Container(容器),服务器通常情况下还有日志收集器Container或者监控收集器Container,多个Container共同组成一个Pod,Pod运行在Node上
k8s可以将Pod从一个Node调度到另一个Node,还可以以Pod为单位去重启和动态扩缩容。所以,**Pod是k8s中最小的调度单位

kubelet主要通过从Controller Manager接受命令来管理和监控Pod
Kube Proxy负责Node的网络通信功能,有了它,外部请求才能被转发到Pod内

Cluster

控制平面和Node共同组成了一个Cluster,也就是集群,同时,为了将集群内部的服务暴露给外部用户使用,我们一般还会部署一个入口控制器,比如 Ingress 控制器(比如 Nginx),它可以提供一个入口让外部用户访问集群内部服务

kubectl

kubectl是一个命令行工具,只要我们执行命令,kubectl内部就会调用k8s的API,而不需要我们自己写代码去调用k8s提供的API

k8s部署服务的过程

  • 首先编写YAML文件,在里面定义Pod里用到了哪些镜像容器,占用了多少内存和CPU等信息
  • 再使用kubectl命令行工具执行
    kubectl apply -f xx.yaml,kubectl就会读取和解析YAML文件,将解析后的对象通过API请求发送给Kubenetes控制平面内的API Server。
  • API Server会根据要求,去世Scheduler通过etcd提供的数据寻找合适的Node。
  • Controller Manager会通过API Server控制Node创建服务,Node内部的kubelet在收到命令后会开始基于Container runtime 组件去拉去镜像创建容器,最终完成Pod的创建
如何调用服务?

外部请求会先到达k8s集群的ingress控制器,然后请求会被转发到k8s内部的某个Node的Kube Proxy上,再找到对应的Pod,然后才是转发到内部容器中,处理结果原路返回。到此完成一次服务调用

参考:小白debug

MIT6.824(6.5840)lab2A个人实现记录

终于来到了最难的lab3,我做的是2024 版,新增了一个KVServer为lab2,原来的raft就变成lab3了
首先阅读论文:
Raft是一种基于日志复制的一致性算法,比paxos更加简单易学且易于实现
Raft技术特点:

  • 将问题分解为独立的易于理解和解决的子问题
  • 通过减少需要考虑的状态来简化状态空间。这使得系统更加一致并尽可能消除不确定的状态

具体的论文细节就不赘述了,网上有很多写的很好的总结,本文主要记录我的个人实现过程和细节

lab3A是实现leader的选举

  1. 首先想着把论文中Figure2中的state写进去,这一步简单地按照论文中的Figure2中写就行了
  2. 用自带的debug函数Dprintf函数探了探路,启动go test -run 3A后发现创建了3个raft。这下目标明确了:为Raft添加状态,leader、follower、candidate。make函数创建raft时当然是follower状态啦
  3. 这个时候就没什么思路了,到处看了看发现getstate这个函数比较好写,就写了
  4. 论文中提到了选取Leader时出现多个Leader的情况,设置一个随机的选取时间避免选取出多个Leader的情况 random
  5. 重新看了看论文的实现思路并参考了大量文章,决定使用Timer定时器和ticker循环定时器分别作为选举和心跳的定时器
  6. 实现ticker(),框架中给了for rf.killed() == false{},使用select case 调用心跳或者选举
  7. 重点实现函数electLeader,electTime到期时调用,Leader变成candidate,currentTerm++,给自己投票(voteFor=me)然后遍历rf.peers请求所有peer(类型为Candidate)为其投票,其中记录投票的票数。如果过半则当选Leader,当选后立刻给其他peer广播心跳heartBeat()
    注意:若其他peer的Term大于currentTerm则本rf退化为Follwer,currentTerm也更新为该Term
  8. 再实现心跳函数heartBeat,心跳函数用time.ticker调用,循环定时器完美满足此应用场景,只需要在心跳函数中增加一个是否为Leader的判断就行

细节

多多注意锁的使用,本人就是在锁的使用上犯了糊涂,妄图使用一把大锁来包平安,但是在并发的条件下似乎不太行得通,必须减少锁的粒度(也就是被锁住的操作)
另外还要注意锁的lock与unlock的搭配,上锁后必须解锁!!

debug

  • 多利用raft/util.go中的DPrintf函数进行分析
  • 在实现的过程中出现了warning: term changed even though there were no failures的问题,经过大量查阅资料和DPrintf来检查,先后发现了三个错误,一是重置rf的electTime的时机,二是原来心跳的定时器使用的是Timer单次定时器而不是Ticker循环定时器,三是在调用heartBeat时对它加上了锁,在heartBeat内部也加了锁,导致卡在heartBeat函数内部
  1. 有四个重置electTime的时机
    1. 给别的peer投票
    2. 收到了符合要求的heartbeat
    3. 自己发起了选举
    4. 自己是Leader,给别的Follower发送heartBeat。遍历到自己时,不需要给自己发送heartbeat,但要记得重置electTime
  2. 改用循环定时器Ticker来触发正常的心跳以便维持一个未出错的Leader任期(Term)
  3. 调用heartBeat时不需要加锁

[操作系统]常见面试题--无序版

操作系统64位与32位的区别

内存寻址能力:64位操作系统通常最大可支持16EB的物理内存,32位由于地址空间的限制,最多只有4GB的物理内存
49aa9e63bf46602b175f49747ad27018.png
运算性能:64位CPU有更宽的通用寄存器和更大的指令集,一次可以处理更多数据

进程和线程的区别

  • 进程是系统资源分配和调度的最小单元,线程是CPU调度和分配的最小单位
  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
  • 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
  • 资源分配给进程,同一进程的所有线程共享该进程的所有资源
  • 进程的创建、销毁、切换的开销大于线程
  • 线程不能独立执行,必须依存在进程中

线程快在哪?

  • 线程创建时有些资源不需要自己管理,直接从进程取用,线程只需要管理寄存器和栈的声明周期
  • 同一进程内多个线程共享数据,所以进程数据传输可以用零拷贝技术,不需要经过内核
  • 进程使用一个虚拟内存跟页表,然后多个线程共用这些虚拟内存,如果同进程内两个线程进行上下文切换比进程快很多

线程分为用户态线程和内核态线程,二者有什么区别?

用户态线程工作在用户空间,内核态线程工作在内核空间。用户态线程调度完全由进程负责,通常就是由进程的主线程负责。相当于进程主线程的延展,使用的是操作系统分配给进程主线程的时间片段。内核线程由内核维护,由操作系统调度。

用户态线程无法跨核心,一个进程的多个用户态线程不能并发,阻塞一个用户态线程会导致进程的主线程阻塞,直接交出执行权限。这些都是用户态线程的劣势。内核线程可以独立执行,操作系统会分配时间片段。因此内核态线程更完整,也称作轻量级进程。内核态线程创建成本高,切换成本高,创建太多还会给调度算法增加压力,因此不会太多。

实际操作中,往往结合两者优势,将用户态线程附着在内核态线程中执行。

说说协程

为了处理高并发、多连接下的数据读写,以往有两种解决方案。

  • 多进程:存在频繁调度切换的问题,同时HIA存在每个进程资源不共享的问题,需要额外引入进程间通信机制来解决。
  • 多线程:高并发场景的大量IO等待会导致多线程被频繁挂起和切换,非常消耗系统资源,同时多线程访问共享资源存在竞争问题

协程是一种比线程更加轻量级的微线程,一个线程可以拥有多个协程
协程运行在线程之上,当一个协程执行完成之后,可以选择主动出让,让另一个协程运行在当前线程之上。

协程并没有增加线程 数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。

因此,使用协程替换线程适用于有大量IO操作业务的情况下。一是降低了系统内存,二是减少了系统切换开销,因此系统的性能也会提升。
由于在协程中调用阻塞IO的方法会导致在该线程之上的所有协程都陷入阻塞。因此协程只有和异步IO结合起来才能发挥出最大的威力

进程通信

进程的用户地址空间是相互独立的,不可以互相访问,但内核空间是进程都共享的,所以进程之间要通信必须通过内核。进程间通信主要有管道、消息队列、共享内存、信号量、信号、Socket编程

  • 管道分为匿名管道和有名管道,管道是半双工通信的。管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区的操作。

    • 匿名管道只能用于父子进程间的通信,有名管道只要可以访问路径就可以通过有名
      信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程。通过发送指定信号来通知进程某个异步事件的发送,以迫使进程执行信号处理程序。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成和发送信号。
      信号的来源有硬件来源和软件来源,常见的有Ctrl+9 1111
  • Socket
    用于跨网络与不同主机上的进程进行通信,当然也可以完成同主机上的进程通信
    Socket的本质是一个编程接口(API)
    是应用层与TCP/IP协议的网络通信的抽象层。它对TCP/IP进行了封装,它把复杂的TCP/IP协议簇隐藏在Socket接口后面。对于用户来说,只需要进行一组简单的API就可以实现网络的连接C产生SIGINT信号,表示终止该进程;软件来源如kill -管道进行通信

    • 管道这种进程通信方式虽然使用简单,但是效率比较低,不适合进程间频繁地交换数据,并且管道只能传输无格式的字节流
  • 消息队列的本质就是存放在内存中的消息的链表,而消息本质上是用户自定义的数据结构。如果进程从消息队列中读取了某个消息,这个消息就会从消息队列中删除

    • 消息队列可以实现消息的随机查询,不一定要以先进先出的次序读取消息,也可以按消息类型读取,比有名管道的先进先出更有优势
    • 用户进程写入数据到消息队列时,会发生从用户态拷贝数据到内核态,用户进程读也会发生拷贝。如果数据量较大,,使用消息队列会造成频繁系统调用,会降低性能
  • 共享内存可以避免消息队列的拷贝消息、进行系统调用,允许不相干的进程将同一段物理内存连接到它们各自的地址空间中,使得这些进程可以访问同一个物理内存,这个物理内存就成为共享内存。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

    • 共享内存仅在建立共享内存区域时需要系统调用,一旦建立共享内存,所有的访问都可作为常规内存访问,无需借助内核。这样,数据就不需要在进程之间来回拷贝,所以这是最快的一种进程通信方式。但是却容易造成数据冲突
  • 信号量,信号量是 一个整型计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据,保证共享内存在任何时刻只有一个进程在访问(保证互斥),并使得进程们能够按照某个特定的程序访问共享内存(同步)

    • 利用PV操作实现
    • P操作:将信号量值减一,表示申请占用一个资源。如果结果小于 0,表示已经没有可用资源,则执行 P 操作的进程被阻塞。如果结果大于等于 0,表示现有的资源足够你使用,则执行 P 操作的进程继续执行。
    • V操作:将信号量值加一,表示释放一个资源,即使用完资源后归还资源。
  • 信号

信号信号量完全不同!!!

信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程。通过发送指定信号来通知进程某个异步事件的发送,以迫使进程执行信号处理程序。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成和发送信号。
信号的来源有硬件来源和软件来源,常见的有Ctrl+C产生SIGINT信号,表示终止该进程;软件来源如kill -9 1111

  • Socket
    用于跨网络与不同主机上的进程进行通信,当然也可以完成同主机上的进程通信
    Socket的本质是一个编程接口(API)
    是应用层与TCP/IP协议的网络通信的抽象层。它对TCP/IP进行了封装,它把复杂的TCP/IP协议簇隐藏在Socket接口后面。对于用户来说,只需要进行一组简单的API就可以实现网络的连接

信号量的值 大于 0 表示有共享资源可供使用,这个时候为什么不需要唤醒进程?

所谓唤醒进程是从就绪队列(阻塞队列)中唤醒进程,而信号量的值大于 0 表示有共享资源可供使用,也就是说这个时候没有进程被阻塞在这个资源上,所以不需要唤醒,正常运行即可。

信号量的值 等于 0 的时候表示没有共享资源可供使用,为什么还要唤醒进程?

V 操作是先执行信号量值加 1 的,也就是说,把信号量的值加 1 后才变成了 0,在此之前,信号量的值是 -1,即有一个进程正在等待这个共享资源,我们需要唤醒它。

使用信号量和 PV 操作实现进程的同步也非常方便,三步走:

  • 定义一个同步信号量,并初始化为当前可用资源的数量
  • 在优先级较的操作的后面执行 V 操作,释放资源
  • 在优先级较的操作的前面执行 P 操作,申请占用资源

虚拟内存的布局

49aa9e63bf46602b175f49747ad27018.png

虚拟内存是如何实现的

虚拟内存技术的实现是建立在离散分配的内存管理的基础上的

目前最常用的三种实现虚拟内存技术的方法:

  • 请求分页存储管理

  • 请求分段存储管理

  • 请求段页式存储管理
    以上三种方式,无论哪种,都需要以下三个条件:

  • 一定容量的内存和外存
    程序执行时,只需要将程序的一部分装入内存,就可以运行了

  • 缺页中断
    若需要执行的程序未在内存中(即“缺页/段”),则处理器会通知操作系统将相应的页/段调入到内存中,与此同时也会将不常用的页/段调出到外外存中

  • 虚拟地址空间
    逻辑地址转化为物理地址

用什么命令查看内存使用情况

top
这个命令会动态显示系统中各个进程的资源占用状况,包括CPU使用率和内存使用情况。按Shift + M可以按照内存使用量进行排序。

ps aux
该命令可以显示所有进程的详细信息,包括进程ID(PID)、用户、CPU和内存使用百分比等

  • top
  • pidstat
  • ps
  • pmap

select poll epoll

IO多路复用是用一个进程来维护多个Socket
而select poll epoll就是内核提供给用户态的多路复用系统调用,进程可以通过一个系统调用函数从内核获取多个事件
这三者都是在获取事件时,先把所有连接(文件描述符fd)传给内核,再由内核返回产生了事件的连接,然后在用户态中再处理这些连接对应的请求即可

  • select
    将已连接的 Socket 都放到一个文件描述符集合,然后调用 select 函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生。检查的方式就是暴力的遍历
    当经检查到有事件产生后,将次Socket标记为可读或者可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。
    所以,对于select这种方式,需要进行2次遍历文件描述符集合,一次在内核态、一次在用户态。还要发生2次拷贝文件描述符集合,先从用户空间传入内核空间中,再由内核修改后,再传出到用户空间中
    select 使用固定长度的 BitsMap,表示文件描述符集合,而且所支持的文件描述符的个数是有限制的,在 Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最大值为 1024,只能监听 0~1023 的文件描述符。

  • poll
    poll 不再用 BitsMap 来存储所关注的文件描述符,取而代之用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制。
    但是 poll 和 select 并没有太大的本质区别,都是使用「线性结构」存储进程关注的 Socket 集合,因此都需要遍历文件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n),而且也需要在用户态与内核态之间拷贝文件描述符集合,这种方式随着并发数上来,性能的损耗会呈指数级增长。

  • epoll

    • epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字,红黑树的增删改一般时间复杂度是O(logn),由于有了红黑树来保存所有待检测的Socket,所有epoll机制不必要每次操作都传入整个Socket集合给内核,只需要传入一个待检测的Socket,减少了内核和用户空间大量数据拷贝和内存分配
    • epoll使用事件驱动的机制,其内核维护了一个链表来记录就绪事件,当某个Socket有事件发生时,通过回调函数,内核会将这个就绪事件加入到就绪时间列表当中,当用户调用epoll_wait函数时,只会返回有事件发生的文件描述符的个数,不需要轮询整个Socket集合,大大提高可检测效率

计算机网络之输入网址按下回车后发生了什么

TCP/IP四层模型
应用层
传输层
网络层
网络接口层

物理层:连接不同的物理设备,传输比特流。在物理设备上传输数据。为上层协议提供了一个传输数据的可靠的物理媒介

  • 中继器(Repeater 也叫放大器)
  • 集线器 同一局域网的再生、放大信号(多端口的中继器) 半双工,不能隔离冲突域也不能隔离广播域
    单工通信信道 只能一个方向通信,没有反方向反馈的信道
    半双工通信信道 双方都可以发送接收信息,但是不能同时发送,不能同时接收
    全双工通信信道:双方都可以同时发送和接收

数据链路层
向上层网络层提供服务,最基本的服务是将来自网络层的数据可靠地传输到相邻结点的目标机网络层。数据链路层在不可靠的物理介质上提供可靠的传输

数据链路主要作用:物理地址寻址、数据的成帧、流量控制、数据检错、重发

帧是数据链路层数据的基本单位 帧首部和尾部是特定的控制字符

透明传输:“透明”是指即使控制字符在帧数据中,但是要当做不存在去处理。即在控制字符前加上转义字符ESC

最大传输单元MTU
路径MTU:即链路中MTU的最小值

以太网协议
MAC地址:每个设备都有唯一的MAC地址,共48位,使用十六进制表示
以太网协议完成相邻设备的数据帧传输,解决子网内部点对点的通信
以太网协议只能解决单个局域网内点对点通信,多个局域网互通需要IP协议来解决

网络层
实现两个端系统之间的数据透明传输,具体包括寻址、路由选择、连接的建立、保持、终止。数据交换技术是报文交换:采用储存转发方式,数据交换单位是报文
网络层主要协议:
IP协议(Internet Protocol,因特网互联协议);
ICMP协议(Internet Control Message Protocol,因特网控制报文协议);
ARP协议(Address Resolution Protocol,地址解析协议);
RARP协议(Reverse Address Resolution Protocol,逆地址解析协议)。
IP协议
提供不可靠、无连接的端到端的数据包传输服务,主要实现:数据传输 数据分片
IP协议主要功能:无连接数据报传输、数据包路由选择和差错控制
ICMP协议详解
网际控制报文协议(Internet Control Message Protocol),可以报告错误信息或者异常情况,ICMP报文封装在IP数据报当中
ICMP协议的应用:

  • Ping应用:网络故障的排查;
  • Traceroute应用:可以探测IP数据报在网络中走过的路径。
    地址解析协议 ARP(Address Resolution Protocol):为网卡(网络适配器)的IP地址到对应的硬件地址提供动态映射。可以把网络层32位地址转化为数据链路层MAC48位地址。
    ARP是一个独立的三层协议,所以ARP报文在向数据链路层传输时不需要经过IP协议的封装,而是直接生成自己的报文,然后再到数据链路层封装成帧

RARP(Reverse Address Resolution Protocol)协议指逆地址解析协议,可以把数据链路层MAC48位地址转化为网络层32位地址。

网络地址转换NAT技术
用于多个主机通过一个公有IP访问访问互联网的私有网络中,减缓了IP地址的消耗,但是增加了网络通信的复杂度。

NAT 工作原理:

从内网出去的IP数据报,将其IP地址替换为NAT服务器拥有的合法的公共IP地址,并将替换关系记录到NAT转换表中;
从公共互联网返回的IP数据报,依据其目的的IP地址检索NAT转换表,并利用检索到的内部私有IP地址替换目的IP地址,然后将IP数据报转发到内部网络。

ARP协议与RARP协议
地址解析协议ARP(Address Resolution Protocol):为网卡(网络适配器)的IP地址到对应的硬件地址提供动态映射。把网络层32位地址转化为数据链路层MAC48位地址
ARP是即插即用的,一个ARp表是自动建立的,不需要系统管理员来配置

RARP(Reverse Address Resolution Protocol)协议指逆地址解析协议,可以把数据链路层MAC48位地址转化为网络层32位地址。

输入网址后回车,之后发生了什么?

  • URL 解析,解析 http 协议、端口、资源地址。
  • DNS 查询:首先查看本地DNS缓存,再查询本地 host文件,再访问 DNS 服务器将 域名解析成 ip 地址等等。在每一步如果查到了都会直接访问
  • 建立 TCP 连接。
  • 服务器收到请求后处理,并且构造响应返回给客户端。
  • 客户端接收 HTTP 报文响应。
  • 渲染页面,最后有可能会四次挥手断开连接,也可能不会而是复用连接。
    URL(同一资源定位符)
    scheme://host.domain:port/path/filename
  • scheme 定义应用层协议类型,比如 http、https、 ftp 等;
  • host 定义域主机(http 的默认主机是 www);
  • domain 定义因特网域名,比如 segmentfault.com;
  • port 主机的端口,http 默认是 80, https 默认是 443;
  • path 服务器上的资源路径;
  • filename - 定义文档/资源的名称;
    DNS解析过程:
  • 本地电脑检查浏览器缓存中有没有该域名对应的解析过的IP地址。域名被缓存的时间由TTL来设置,通常要求时间长度适中,太长IP地址可能会发生变化而导致无法解析到变化后的IP地址,太短会导致用户每次访问网站都要重新解析域名
  • 浏览器会查找操作系统缓存中是否有这个域名对应的DNS解析结果。
  • 需要用到网络配置中的“DNS服务器地址”。操作系统会把这个域名发送给这个本地DNS服务器。 每个完整的内网通常都会配置本地DNS服务器,例如用户是在学校或工作单位接入互联网,那么用户的本地DNS服务器肯定在学校或工作单位里面。它们一般都会缓存域名解析结果,当然缓存时间是受到域名的失效时间控制的。后续的DNS迭代和递归也是由本地DNS服务器负责。
  • 如果本地DNS服务器仍然没有命中,就直接到根DNS服务器请求解析
  • 根DNS服务器返回给本地DNS域名服务器一个顶级DNS服务器地址,它是国际顶级域名服务器,如.com .cn等
  • 本地DNS服务器再向上一步获得的顶级DNS服务器发送解析请求。
  • 接受请求的顶级DNS服务器查找并且返回此域名对应的Name Server域名服务器的地址。 这个Name Server服务器就是要访问的网站域名提供商的服务器,其实该域名的解析任务就是由域名提供商的服务器来完成。
  • Name Server服务器会查询储存的域名和IP的映射关系表,再把查询出来的域名和IP地址等信息,连同一个TTL值返回给本地DNS服务器
  • 本地DNS服务器返回给浏览器对应的IP和TTL值,本地DNS服务器会缓存在这个域名和IP的对应关系,缓存时间由TTL的值控制。
  • 把解析的结果返回给本地电脑,本地电脑根据TTL值缓存在本地系统缓存中,域名解析过程结束在实际的DNS解析过程中,可能还不止这10步,如Name Server可能有很多级,或者有一个GTM来负载均衡控制,这都有可能会影响域名解析过程。

递归查询和迭代查询的区别:递归查询直接返回一个准确的查询结果,迭代查询会返回一个其他能够解析查询请求的DNS服务器,直到查询到结果。

建立TCP/IP链接
建立连接

应用层:发送HTTP请求
浏览器从地址栏得到服务器IP地址,接着构造一个HTTP报文,其中包括:

  • 请求行包含请求方法、URL、协议版本
  • 请求报头由键值对组成,每行一对,关键字与值使用英文“:”分割
  • 请求体:请求参数,并不是所有的请求都有请求参数。也可以将参数放在body里面

传输层:TCP传输报文
建立TCP/IP连接,在传输层解决了数据的可靠传输、流量控制、拥塞控制

  • TCP的可靠传输服务是通过确认和超时重传的机制来实现的,而确认和超时重传的具体实现是通过以字节为单位的滑动窗口机制来完成
  • TPC拥塞控制:TCP通过慢启动、拥塞避免、加速递减、快重传和快恢复等机制来共同实现拥塞控制
  • 流量控制:采用通知窗口实现对发送端的流量控制,通知窗口大小的单位是字节。TCP通过在TCP数据段首部的窗口字段中填入当前设定的接收窗口(即通知窗口)的大小,用来告知对方’我放当前的接收窗口的大小’,以实现流量控制。发送窗口大小在建立连接时商定,在通信过程,双方可以动态地根据自己的情况调整对方的发送窗口大小

网络层:IP协议查询与MAC地址
将数据段打包,并加入源和目标的IP地址,并且负责寻找传输路线。判断目标地址是否与当前地址处于同一网络中,是的话直接根据MAC地址发送,否则使用路由表查找下一跳地址,以及使用ARP(地址解析协议)查询它的MAC地址

链路层:以太网协议
根据以太网协议将数据分为以“帧”为单位的数据包,每一帧分为两个部分:

  • 标头:数据包的发送者、接受者、数据类型
  • 数据:数据包具体内容

MAC地址
以太网规定了连入网络的所有设备都必须具备“网卡”接口,数据包都是从一块网卡传递到另一块网卡,网卡的地址就是 Mac 地址。每一个 Mac 地址都是独一无二的,具备了一对一的能力

三次握手与四次挥手
硬不硬你说了算!全图解被问千百遍的TCP三次握手和四次挥手面试题 (qq.com)