一、操纵体系
0.内存管理
01.什么是虚拟内存?为什么必要虚拟内存?
虚拟内存为程序提供比现实物理内存更大的内存空间,同时进步内存管理的灵活性和体系的多任务处理能力。虚拟地点空间就是进程所能看到的内存空间,这段空间是一连的、独立的,现实地点空间则是内存上的空间,这段是所有进程共享的、有限的空间。虚拟内存就是把现实地点空间映射到虚拟地点空间的技术,这样就实现了内存隔离、内存扩展、物理内存管理、页面交换等技术。内存隔离就是每个进程都有自己的虚拟地点空间,因此一个进程无法访问另一个进程的内存。内存扩展就是虚拟内存让每个进程拥有比现实大的内存空间地点,可以处理更多的数据、更大的进程。物理内存管理,内存空间不足时把不常用的数据转移到硬盘上,释放内存,以助于更多进程使用。页面交换,进程大概会造成外部内存碎片,大概会导致内存空间不足,这时把不常用的数据交换到硬盘上,再交换返来,就能消除内存碎片,之前技术是内存分段,现在都是内存分页,一页或几页的内存交换就能解决内存不足的问题,而且效率高,内存分段的大数据在硬盘上读取速度慢。
02.什么是内存分段和分页?作用是什么?
内存分段是将一个程序的内存空间分为差别的逻辑段 segments ,每个段代表程序的一个功能模块
或数据范例,如代码段、数据段、堆栈段等。每个段都有其自己的巨细和权限。内存分页是把整个虚拟和物理内存空间分成固定巨细的页(如4KB)。这样一个一连并且尺寸固定的内存空间,我们叫页Page。内存分段容易产生外部碎片,内存分页容易产生内部碎片。
作用:逻辑隔离、内存保护、虚拟内存、共享内存、内存管理。(以是说这些技术都是相辅相成的)
03.表明一下内核态和用户态
操纵体系中的两种实验模式,用来控制计算机对硬件资源的访问权限和操纵范围。处理器硬件根据状态位决定当前可以实验哪些指令、访问哪些内存区域,操纵体系依赖处理器的实验模式来实现安全和稳定性,确保应用程序在用户态实验,而特权操纵(体系调用、非常处理、停止处理)以及直接访问操纵体系的核心部门只能在内核态实验,占用CPU时不能被抢占。
04.停止和非常?区别?
停止和非常是两种差别的事件,二者都会导致CPU停息当前的程序实验,转而去实验特定的处理程序。停止一般是由于外部装备或其他处理器导致的,一般是异步的,也就是说可以在任何时间发生,不会由当前的指令造成。比如键盘输入、鼠标输入、网络数据到达,来提示CPU去处理这些事件。非常则是在当前CPU内部发生的,一般是同步的,由当前的指令造成。比如除数非常、访问非法内存地点、实验非法指令等,来提示CPU去处理这些错误。
05.数据布局
数组、链表、栈stack、队列、哈希表hash table、树、图、集合set、字典map。每种数据布局有自己适合解决的问题。
1. 进程管理
11.进程和线程的区别
四个方面:定义、资源开销、独立安全性、通信方式
进程是运行中的程序,是体系举行资源分配的基本单元,而线程是进程的子任务,是体系可以或许举行CPU调度的最小单元,是进程内的实验单元。一个进程可以有多个线程,这些线程共享同一块内存空间。进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈。因为进程都有独立的内存空间,以是创建和烧毁的开销比较大;当切换进程时,要保存和恢复整个进程的状态,以是上下文切换的花销较大。而线程共享同一块内存空间,以是创建和烧毁开销比较小;线程间切换只必要保存和恢复少数的线程上下文,因此线程上下文切换开销较小。由于共享内存空间,以是线程之间可以访问共享数据,可以直接通信;而进程是独立的内存空间,只能通过进程间通信方式来举行通信,比如管道、消息队列、信号、信号量、共享内存、socket。进程间是相互隔离的,具有独立安全性,一个进程崩溃不会影响其他进程;而线程共享内存空间,一个线程崩溃,整个进程都会受影响。
线程共享内存空间就会导致创建、烧毁、切换开销小,直接通信,非独立安全性;进程独立内存空间就会导致创建、烧毁、切换开销大,进程间通信方式,独立安全性。
线程之间可以并发运行且共享雷同的地点空间。
110.什么是协程?
协程是一种比线程更加轻量级的并发实验单元,通常由程序本身而不是操纵体系内核来调度。轻量级、协作式调度、不必要锁机制、适合高并发。
协程与并发问题
协程通常运行在同一个线程内,因此所有协程共享雷同的内存空间和资源。由于协程在同一线程中按顺序实验(固然看起来是并发的),它们不会像线程那样同时访问共享资源,因此减少了许多并发问题,如竞态条件和死锁。
协程的上风:
无需锁机制:由于协程在同一线程中切换(按顺序切换),协程之间不会发生现实的并发竞争,因此不必要像线程那样使用锁来同步数据访问。
简化编程:协程通过让出实验权的方式实现多任务处理,避免了多线程编程中的复杂性(如锁和条件变量),使得异步编程更加直观。
12.调度原则
为了进步 CPU 使用率,在这种发送 I/O 事件致使 CPU 空闲的情况下,调度程序必要从就绪队列中选择一个进程来运行。要进步体系的吞吐率,调度程序要权衡长任务和短任务进程的运行完成数量。如果进程的期待时间很长而运行时间很短,那周转时间就很长,这不是我们所期望的,调度程序应该避免这种情况发生。就绪队列中进程的期待时间也是调度程序所必要考虑的原则。对于交互式比较强的应用,相应时间也是调度程序必要考虑的原则。
CPU 使用率、体系吞吐量、周转时间、期待时间、相应时间。
13.调度算法
先来先服务调度算法、 最短作业优先调度算法、高相应比优先调度算法、时间片轮转调度算法、最高优先级调度算法、多级反馈队列调度算法。
14.进程间通信
每个进程的用户地点空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,以是进程之间要通信必须通过内核。
管道:单向,匿名管道,命名管道,mkfifo,通信效率低,但简朴,实质是内核中的一段缓存,一端写入一端读取。
消息队列:消息队列是保存在内核中的消息链表,一是通信不及时,二是附件也有巨细限定,不适合比较大数据的传输。存在用户态与内核态之间的数据拷贝开销。
共享内存:共享内存的机制,就是拿出一块虚拟地点空间来,映射到雷同的物理内存中。不必要拷贝来拷贝去,传来传去,大大进步了进程间通信的速度。
信号量:信号量着实是一个整型的计数器,紧张用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。
信号:对于非常情况下的工作模式,就必要用「信号」的方式来通知进程。信号是进程间通信机制中唯一的异步通信机制。
Socket :跨网络与差别主机上的进程之间通信,就必要 Socket 通信了。
15.互斥与同步
由于多线程实验操纵共享变量的这段代码大概会导致竞争状态,因此我们将此段代码称为临界区,它是访问共享资源的代码片段,肯定不能给多线程同时实验。我们盼望这段代码是互斥的,也就说包管一个线程在临界区实验时,其他线程应该被制止进入临界区。
同步,就是并发进程/线程在一些关键点上大概必要互相称候与互通消息,这种相互制约的期待与互通信息称为进程/线程同步。
同步就比如:「操纵 A 应在操纵 B 之前实验」,「操纵 C 必须在操纵 A 和操纵 B 都完成之后才能实验」等;互斥就比如:「操纵 A 和操纵 B 不能在同一时间实验」;
为了实现进程/线程间正确的协作,操纵体系必须提供实现进程协作的措施和方法,紧张的方法有两种:锁:加锁、解锁操纵;信号量:P、V 操纵;
假设有两个线程A和B,线程B必要在线程A实验完某个操纵之后再继续实验。我们可以使用信号量来实现这个同步:初始时,信号量的值设为0。线程A在完成操纵后,对信号量实验V操纵(信号量加1)。线程B在实验之前,对信号量实验P操纵(信号量减1)。由于初始时信号量为0,线程B会被阻塞,直到线程A完成操纵并实验V操纵,释放信号量。
16.线程同步的方式有哪些?
线程同步机制是指在多线程编程中,为了包管线程之间的互不干扰,而采用的一种机制。常见的线程同步机制有以下几种:
1. 互斥锁:互斥锁是最常见的线程同步机制。它允许只有一个线程同时访问被保护的临界区(共享
资源)
2. 条件变量:条件变量用于线程间通信,允许一个线程期待某个条件满足,而其他线程可以发出信
号通知期待线程。通常与互斥锁一起使用。
3. 读写锁:读写锁允许多个线程同时读取共享资源,但只允许一个线程写⼊资源。
4. 信号量:用于控制多个线程对共享资源举行访问的工具。
17.生产者消耗者模型
锁实现了互斥,信号量实现了同步,生产者消耗者模型实现了同步和互斥。生消模型让生产者和消耗者解耦,让两个线程独立工作、并行实验,这种并行工作机制充实使用了体系资源,提拔了程序的并发效率。生产者-消耗者模型通过锁、条件变量或信号量来包管同步,避免竞态条件。同步的紧张目的是协调多个线程或进程之间的实验顺序,互斥的紧张目的是防止多个线程或进程在同一时间访问共享资源。
18.先容一下几种典范的锁
忙期待锁(自旋锁):线程在尝试获取锁时会不绝轮询,直到锁被释放。在单处理器上,必要抢占式的调度器。
互斥锁:互斥锁是一种最常见的锁范例,用于实现互斥访问共享资源。在任何时间,只有一个线
程可以持有互斥锁,其他线程必须期待直到锁被释放。这确保了同一时间只有一个线程可以或许访问
被保护的资源。
读写锁:允许多个线程同时读共享资源,只允许一个线程举行写操纵。分为读(共享)和写(排他)两种状态。
悲观锁:认为多线程同时修改共享资源的概率比较高,以是访问共享资源时间要上锁。互斥锁、自旋锁、读写锁,都是属于悲观锁。
乐观锁:先不管,修改了共享资源再说,如果出现同时修改的情况,再放弃本次操纵。
19.死锁?如何避免?
死锁是指两个或多个进程在争取体系资源时,由于互相称候对方释放资源而无法继续实验的状态。
死锁只有同时满足以下四个条件才会发生:互斥条件、持有并期待条件、不可剥夺条件、环路期待条件。最常见的并且可行的就是使用资源有序分配法,来破环环路期待条件。
2.进程
在一个进程的运动期间至少具备三种基本状态,即运行状态、就绪状态、阻塞状态。
21.孤儿进程和僵尸进程
僵尸进程是指一个子进程已经实验完毕并退出,但其父进程还没有读取该子进程的退出状态信息(即通过调用 wait() 或 waitpid() 体系调用获取子进程的停止状态)。在这种情况下,子进程的进程表项仍然保存在体系中,固然子进程已经停止,但它的进程号(PID)和退出状态信息还占用着体系资源,这种进程称为僵尸进程。
关键点:
- 僵尸进程并不占用体系的CPU和内存资源,只占用一个进程号和一些内核数据布局。
- 僵尸进程会在父进程读取其退出状态后被完全清理掉。
- 如果父进程在子进程停止后不及时调用 wait() 函数处理其退出状态,大概会导致体系中的僵尸进程过多,耗尽体系的进程号资源。
孤儿进程是指一个父进程停止了,但它的子进程还在继续运行。这种情况下,这些子进程将变为孤儿进程。为了防止这些孤儿进程无人管理,操纵体系会将它们的父进程重新指定为 init 进程(PID为1的进程,在当代体系中大概是 systemd 进程)。init 进程会自动接管这些孤儿进程,并在它们停止时清理它们的资源。
关键点:
- 孤儿进程会被体系的 init 进程接管,确保它们的资源可以或许被正确回收。
- 孤儿进程继续运行,不会对体系产生负面影响,体系会妥善管理它们。
22.守护进程
一种在后台运行的特殊范例的进程,通常不与用户直接交互,而是实验体系级的任务或服务,如网络服务、打印服务、日志记录等。守护进程在体系启动时启动,并在后台连续运行,直到体系关闭。它们紧张负责体系的维护和服务,包管体系的某些功能或服务连续可用。
3.网络体系
31.什么是零拷贝
要想进步文件传输的性能,就必要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数。要想减少上下文切换到次数,就要减少体系调用的次数。
DMA 技术,也就是直接内存访问。
没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来举行传输的。零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只必要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不必要通过 CPU,2 次都是由 DMA 来搬运。零拷贝技术可以把文件传输的性能进步至少一倍以上。
- 传输大文件的时间,使用「异步 I/O + 直接 I/O」;
- 传输小文件的时间,则使用「零拷贝技术」;「内核缓冲区」现实上是磁盘高速缓存(PageCache)的优点紧张是两个:缓存最近被访问的数据;预读功能;
在传统的文件传输过程中(如通过网络发送文件),数据的拷贝过程大抵如下:
- 从磁盘到内核缓冲区(第一次拷贝):数据从磁盘读入内核空间的缓冲区。
- 从内核缓冲区到用户空间缓冲区(第二次拷贝):数据从内核缓冲区复制到用户空间缓冲区。
- 从用户空间缓冲区回到内核缓冲区(第三次拷贝):数据从用户空间缓冲区复制回内核缓冲区,预备通过网络发送。
- 通过网络发送(大概有 DMA,但涉及体系总线传输):数据从内核缓冲区传输到网络接口卡(NIC),并通过网络发送。
零拷贝的目标是减少或消除步骤 2 和 3 中的数据拷贝。零拷贝就是在以上的流动途径中,避免一些用户空间和内核缓冲区的拷贝。
32.I/O多路复用
一个单一的线程或进程中同时监视多个文件描述符(如套接字、文件、管道等),以确定这些文件描述符中的哪些已经预备好举行I/O操纵(如读、写、或发生非常)。比如一个服务器程序,它必要处理多个客户端的网络哀求。每个客户端连接到服务器的一个套接字。可以用多路复用技术(如 epoll)来“监视”所有这些套接字。为每个哀求分配一个进程/线程的方式不符合,以是使用一个进程来维护多个 Socket。进程可以通过一个体系调用函数(select、poll、epoll)从内核中获取多个事件。
select 和 poll 都是内核通过轮询(遍历)的方式来检查多个文件描述符是否有 I/O 操纵就绪(如可读、可写、非常情况等)。poll 没有文件描述符数量的限定,因为它采用的是动态数组的方式来存储文件描述符和事件。epoll 使用事件通知机制,一旦某个文件描述符的状态发生变化,内核会将这个事件通知给 epoll,使得程序不必要反复轮询所有文件描述符。
epoll实现的数据布局是红黑树和双向链表,红黑树用于存储和管理所有被监视的文件描述符(文件描述符通常是 socket)。当你向 epoll 实例添加、删除或修改一个文件描述符时,epoll 会将这个文件描述符插入或移除红黑树中。红黑树是一种自平衡的二叉搜刮树,确保了插入、删除和查找操纵的时间复杂度为 O(log n),这使得 epoll 可以或许高效地管理大量的文件描述符。双向链表用于存储就绪事件(即有 I/O 操纵预备好的文件描述符)。当某个文件描述符就绪时,它会被加入到这个双向链表中。双向链表的插入和删除操纵非常高效,时间复杂度为 O(1),这对于 epoll 处理大量并发连接时的性能至关紧张。
33.epoll支持两种时间触发模式
边缘触发(ET)和水平触发(LT),ET: 当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中清醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只清醒一次,因此我们程序要包管一次性将内核缓冲区的数据读取完;LT: 当被监控的 Socket 上有可读事件发生时,服务器端不绝地从 epoll_wait 中清醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据必要读取;你的快递被放到了一个快递箱里,如果快递箱只会通过短信通知你一次,即使你不绝没有去取,它也不会再发送第二条短信提示你,这个方式就是边缘触发;如果快递箱发现你的快递没有被取出,它就会不绝地发短信通知你,直到你取出了快递,它才消停,这个就是水平触发的方式。
33.Reactor
「对事件反应」,也就是来了一个事件,Reactor 就有相对应的反应/相应。收到事件后,根据事件范例分配(Dispatch)给某个进程 / 线程。
二、计算机网络
0.OSI七层模型
自己的理解:应用层:生成HTTP哀求报文-----表现层:将哀求报文转换成适合网络传输的数据格式,加密压缩编码等-----会话层:管理两个应用程序之间的会话,包罗连接停止等------传输层:实现端到端通信(主机到主机),但它的职责不仅仅是主机到主机之间的通信,还必要确保数据可以或许被正确的应用程序接收。以是将数据分成更小的数据段(
- 适应MTU限定:分段可以确保数据可以或许在网络中传输,而不会因为过大而被拒绝传输。
- 进步可靠性:分段减少了重传的开销,进步了错误处理的效率。
- 流量与拥塞控制:分段有助于动态调整传输速度,避免网络拥塞。
- 网络兼容性:分段进步了数据在差别范例网络中的传输兼容性。)
,并分别加上端口号,以使其到达正确的应用程序------网络层:给数据段加上网络IP地点,并且选择最佳路由------数据链路层:可靠传输、不对检测、封装成帧-----物理层:将数据转换成适合在网线中传输的电信号。
另外,数据链路层也会和传输层一样举行校验、流量控制,但是针对的对象、作用是不一样的。传输层实现的是端到端的通信,数据链路层实现的则是点对点的通信。点对点一般指装备相连,是局部的,而端到端则大概是跨越了全局网络,中间会经历多次路由器和交换机。
另外,物理层是用什么传输介质、什么物理接口、什么信号表现0和1,解决了两台计算机可以通过信号来传输比特0或1。数据链路层是如何标识MAC地点,如何从比特流中区分地点、数据,如何协调主机争用主线,实现了分组在一个网络上传输。网络层如何标识IP地点,如何路由选择,解决了在多个网络上传输的问题。传输层确定哪个进程通信,解决传输错误问题。应用层制定网络协议,编写网络应用,来实现特定的网络功能。
通过IP地点确定目标主机所在的局域网,然后通过ARP协议把IP地点对应的MAC地点找到,然后在同一片网络中找到目标主机。IP地点的前三个数标识网络,后一个数标识主机。
OSI七层模型的功能概述
- 物理层:负责物理装备之间的原始比特流的传输,包罗电缆、网卡等硬件。它定义了接口范例、电压、电流等物理特性。
- 数据链路层:负责节点之间的可靠传输,包罗错误检测与改正、帧的创建与辨认、流量控制等。数据链路层将数据封装成帧并通过物理层传输。
- 网络层:负责数据包的路由与转发,决定数据如何从源节点到达目标节点。典范的协议如IP(Internet Protocol)。
- 传输层:提供端到端的通佩服务,确保数据的完整性和可靠性。紧张协议包罗TCP(传输控制协议)和UDP(用户数据报协议)。
- 会话层:管剖析话,创建、维持和停止通信会话,确保数据交换的有序性。
- 表现层:处理数据格式的转换,确保发送端和接收端可以或许理解数据的格式。它涉及数据的加密解密、压缩解压等。
- 应用层:直接为用户或应用程序提供网络服务,如电子邮件、文件传输等。应用层是用户与网络的接口。
通过例子说明七层模型的作用
假设你在计算机上使用浏览器访问一个网站(比如打开一个网页),从输入网址到网页显示在屏幕上的过程,可以说明OSI模型各层的作用:
- 应用层:你在浏览器中输入网址并点击“回车”,浏览器(作为应用层)生成一个HTTP哀求,这个哀求包含你想要访问的网页地点。
- 表现层:在发送HTTP哀求之前,表现层负责将哀求数据转换为可以被网络传输的格式,大概还会举行数据的压缩和加密。
- 会话层:表现层之后,会话层创建一个通信会话,这个会话包管哀求和相应之间的数据交换有序且同步。
- 传输层:会话层之后,传输层将数据分成更小的数据段(如TCP段),并为每个数据段加上端口号,以确保数据可以或许传输到正确的应用程序。
- 网络层:传输层之后,网络层根据目标网址的IP地点(通过DNS解析获取)为每个数据段加上源和目标IP地点,并选择最优路径将数据段发送到目标服务器。
- 数据链路层:网络层之后,数据链路层将数据段封装成帧,并通过物理介质(如网线)传输。数据链路层还负责检测和改正物理层传输中大概出现的错误。
- 物理层:终极,物理层将数据帧转化为电信号,通过网络电缆或无线信号发送到目标服务器的物理装备。
目标服务器接收到这些信号后,会逆向处理这些层,从物理层到应用层,将终极的HTTP相应发送回你的浏览器,浏览器再将网页显示在屏幕上。
1.UDP头部格式
UDP的头部比较简朴,只有8个字节,这也是为什么UDP不能像TCP那样实现可靠传输的缘故原由。源端口和目标端口表现数据传输的来源和去向,包长度表现数据报文的总长度(包含了头部和数据部门),方便接收方正确地处理数据。查验和则是用于验证UDP数据报在传输过程中是否发生了错误。它帮助确保数据的完整性。
2.TCP头部格式
TCP的头部一般是20个字节,复杂的头部决定了它的可靠传输。校验和包管了数据的完整性和错误检测;序列号举行了数据的顺序控制;ACK实现了重传机制,确认和重传;滑动窗口举行流量控制;拥塞控制;三次挥手和四次握手举行连接管理。
序列号解决网络乱序问题,确认应答号解决丢包问题,窗口巨细用来举行流量控制,控制位(ACK确认和重传、FIN断开连接、SYN哀求连接)。
3.IP地点
IPV4地点,四位,主机号全为0的是网络地点,全为1的是广播地点。A类,第一位范围1-126,127是当地环回测试地点。后三位范围是1-2^24-1,全1表现广播地点。
网络号是IP地点中的一部门,用于标识某个特定的网络。雷同网络号的装备处于同一网络中。主机号是IP地点中的另一部门,用于标识网络内的具体装备(主机)。网络地点是指IP地点中主机号部门全为0的地点,它标识的是整个网络,而不是网络中的具体装备。广播地点是指IP地点中主机号部门全为1的地点,用于向网络中的所有装备发送信息。
4.流量控制
滑动窗口机制中的流量控制紧张依赖接收方的接收窗口巨细来调节数据传输速率。
- 接收窗口巨细的动态调整:
- 接收方在接收到数据包后,会根据当前缓冲区的可用空间和处理能力来决定是否调整接收窗口的巨细。如果接收方的缓冲区空间富足且处理能力良好,它大概会增大接收窗口的巨细,允许发送方发送更多的数据包。反之,如果接收方的缓冲区接近满载,它会缩小接收窗口,以减缓发送方的数据传输速度。
- 通过ACK通知窗口巨细的变化:
- 每当接收方收到数据包并处理完毕后,它会发送一个ACK(Acknowledgment,确认)消息回给发送方。这个ACK消息不仅确认了已乐成接收的数据包,还携带了一个紧张的字段:接收窗口巨细(Receive Window Size)。
- 这个字段明确告知发送方,接收方当前还能接收的数据量是多少。比如,如果接收窗口巨细是500字节,发送方就知道它最多还能发送500字节的数据而不必期待进一步的ACK。
- 如果接收方的缓冲区快要满了,它会在ACK消息中报告一个较小的接收窗口巨细,通知发送方降低数据传输速率,避免缓冲区溢出。
5.拥塞控制
慢开始、拥塞避免、快重传、快恢复。
TCP发送方一开始使用慢开始算法,让拥塞窗口值从1开始按指数规律增大,当拥塞窗口值增大到慢开始门限值时,实验拥塞避免算法,让拥塞窗口值按线性加1的规律增大,当发生超时重传时,就判断网络很大概出现了拥塞,这时将慢开始门限值更新为发生拥塞时拥塞窗口值的一半,并将拥塞窗口值减少为1,并重新实验慢开始算法,拥塞窗口值又从1开始按指数规律增大,当增大到了新的慢开始门限值时,停止使用慢开始算法,实验拥塞避免算法。
后来又加入了快重传和快恢复,快重传是指收到三个重复确认。快恢复是指快重传之后门限值更新发生拥塞时拥塞窗口值的一半,并将拥塞窗口值也更新为发生拥塞时拥塞窗口值的一半,而不是更新为1。
6.三次握手
第一次握手发送端向接收端发送哀求连接SYN,接收端收到,并且得知发送端具有发送能力。第二次握手接收端向发送端发送确认连接ACK,发送端得知接收端具有接受能力,并且向发送端发送哀求连接,发送端收到,得知接收端具有发送能力。第三次握手,发送端向接收端发送确认连接,接收端得知发送端具有接收能力。这样一来,两端都知道对方具有发送和接收能力,两端创建连接可以正常的传送数据。三次握手才能确认双方的接收和发送能力是否正常。
如果是两次握手,如果某次发送的报文因为网络延误了,又重新发送了一次连接,延误的发送在重新的连接释放之后才到达服务端,这时间服务端会认为发送端又发送了一次连接哀求,于是向发送端发送确认哀求,同意创建连接,但客户端现实并未发送,以是忽略哀求,于是服务端不绝期待,浪费资源。
不采用两次大概四次:避免汗青连接、避免资源浪费、确认对方收发能力。
7.四次挥手
通过四次挥手的过程,TCP协议确保了双方都可以或许正常地关闭连接,并且所有未完成的数据传输都能顺利结束。第一次挥手:客户端发送FIN,表现没有数据要发送了。第二次挥手:服务器发送ACK,确认收到FIN哀求。第三次挥手:服务器发送FIN,表现没有数据要发送了。第四次挥手:客户端发送ACK,确认收到服务器的FIN哀求,连接关闭。
8.HTTP哀求方法
应用层产生的哀求报文里面会含有哀求行、哀求头、哀求体(post会有,get没有),
- 哀求行:包罗哀求方法、哀求 URI 和 HTTP 版本。
- 哀求头:提供关于哀求的附加信息,比方主机名、用户代理、接受的内容范例等。
- 哀求体:包含要发送给服务器的数据,适用于必要提交数据的哀求方法如 POST 和 PUT。
GET POST PUT PATCH TRACE OPTIONS CONNECT HEAD DELETE
9.HTTP状态码
1XX 信息性状态码 接收的哀求正在处理,正常,继续;
2XX 乐成状态码 哀求正常处理完毕; 200 204 206
3XX 重定向状态码 资源位置发生变化,必要新的URL; 301 302 304
4XX 客户端错误状态码 服务端无法处理客户端的哀求;400 403 404
5XX 服务端错误状态码 服务端在处理哀求时自身错误; 500 501 502 503
10.HTTP协议的几个版本
HTTP1.0 短连接,哀求相应模型,多媒体 (支持文本、音视频等),简朴易用,扩展性,但是短连接导致效率低、延长高、浪费资源,无长期连接导致没法在同一个连接中处理多个哀求;
HTTP1.1 长期连接,哀求管道化,缓存控制,性能提拔,带宽使用率高,更灵活的哀求处理,但是管道化局限,队头阻塞;
HTTP2 二进制格式,头部压缩,多路复用(流),服务器推送,但复杂性增长,基于TCP(仍受到握手、丢包重传等限定);
HTTP3 基于QUIC协议,更快的连接创建,改进的流量控制,内建的加密,性能杰出,但是依赖基础办法,实现复杂。QUIC允许对每个流单独举行流量控制,而不仅仅是针对整个连接举行流量控制。这样可以更好地适应差别流的数据传输需求,进步传输效率。
11.GET和POST的区别
1. 用途:GET用来哀求数据,POST修改/提交数据;
2. 数据传输方式:URL通报,哀求体通报;
3. 安全性:URL上数据可见,哀求体内稍微安全一些,但是都不安全,HTTP明文;
4. 幂等性:GET每次哀求都会得到雷同的数据,POST每次创建则会产生差别的资源;
5. 数据巨细限定:URL长度限定,哀求体可以大数据;
6. 缓存:GET每次哀求可以缓存下来,方便下次哀求,POST每次创建差别,不缓存;
7. 语义安全:GET修改服务器数据,POST不修改。
12.HTTP缓存方式
1. 逼迫缓存(HTTP1.0 Expires 头部字段,绝对时间,HTTP1.1 Cache-Control 头部字段,更灵活)
优点是在缓存有效期内,浏览器无需与服务器通信,直接使用当地缓存资源,提拔加载速度。缺点是如果资源在缓存期间发生了变化,用户大概无法及时获取到最新的内容。
2. 协商缓存是指浏览器每次哀求资源时,都会先向服务器扣问资源是否已经更新,如果没有更新,则继续使用缓存。如果更新了,则下载新的资源。
优点是既能减少不必要的数据传输,又能包管获取最新的资源。缺点是相比逼迫缓存,每次哀求都必要与服务器举行验证,带来了肯定的延长。
13.HTTP和HTTPS
区别:安全、连接、端口、证书
1. HTTP超文本传输协议,明文,不安全。HTTPS在TCP和HTTP之间加入了SSL/TLS安全协议,使得报文可以或许加密安全传输。
2. HTTP只必要三次握手就能创建连接,HTTPS则还必要SSL/TLS握手。
3. 端口号80与443。
4. HTTPS必要向CA申请身份证书,来包管服务器是安全可靠的。
14.HTTPS能解决什么问题
信息加密解决安全秘密,校验机制解决篡改信息,身份证书解决不可佩服务器。
15.为什么每次创建 TCP 连接,初始化的序列号要求不一样呢?
紧张缘故原由有两个方面:
- 为了防止汗青报文被下一个雷同四元组的连接接收(紧张方面);
- 为了安全性,防止黑客伪造的雷同序列号的 TCP 报文被对方接收;
客户端和服务端创建一个 TCP 连接,在客户端发送数据包被网络阻塞了,然后超时重传了这个数据包,而此时服务端装备断电重启了,之前与客户端创建的连接就消失了,于是在收到客户端的数据包的时间就会发送 RST 报文。紧接着,客户端又与服务端创建了与上一个连接雷同四元组的连接;在新连接创建完成后,上一个连接中被网络阻塞的数据包正好抵达了服务端,刚好该数据包的序列号正好是在服务端的接收窗口内,以是该数据包会被服务端正常接收,就会造成数据错乱。可以看到,如果每次创建连接,客户端和服务端的初始化序列号都是一样的话,很容易出现汗青报文被下一个雷同四元组的连接接收的问题。
16.第一次、第二次、第三次握手丢失了分别会发生什么?
第一次握手丢失:超时重传,而且重传的 SYN 报文的序列号都是一样的。每次期待几秒,下一次重传的期待时间是这次的两倍,直至重传上限次数,断开连接。
第二次握手丢失:客户端和服务端都会重传,客户端会重传 SYN 报文,也就是第一次握手,最大重传次数由 tcp_syn_retries内核参数决定;服务端会重传 SYN-ACK 报文,也就是第二次握手,最大重传次数由 tcp_synack_retries 内核参数决定。
第三次握手丢失:ACK 报文是不会有重传的,当 ACK 丢失了,就由对方重传对应的报文。因为这个第三次握手的 ACK 是对第二次握手的 SYN 简直认报文,以是当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手,大概达到最大重传次数。
17.什么是 SYN 攻击?如何避免 SYN 攻击?
半连接队列:服务器第一次收到客户端的SYN之后,就会处于SYN_RCVD状态,此时双方还没有完全创建连接,服务器会把这种状态下的哀求连接放在一个队列里,称为半连接队列。完成三次握手创建起连接的就会放入全连接队列中。
SYN攻击是客户端短时间内伪造大量不存在的IP地点,并向服务器不绝发送SYN包,服务器回复确认包,并且期待客户端确认,由于源地点不存在,因此服务器不绝重发直至超时,这些伪造的SYN包将长时间占用半连接队列,导致正常的SYN哀求因队列满而扬弃,从而引起网络拥塞乃至瘫痪。
防御方法:收缩超时时间,增泰半连接队列,防火墙过滤,SYN Cookies(是一种在服务器接收到 SYN 哀求时,不立即为其分配资源,而是将哀求信息编码到 TCP 序列号中的技术。只有当客户端发送 ACK 确认时,服务器才会验证这个序列号并为连接分配资源。),SYN 速率限定。
18.四次挥手丢失分别会发生什么?
第一次挥手丢失:客户端迟迟收不到被动方的 ACK 的话,触发超时重传机制,重传 FIN 报文,重发次数由 tcp_orphan_retries 参数控制。如果还是没能收到服务端的第二次挥手(ACK报文),那么客户端就会断开连接。
第二次挥手丢失:ACK 报文是不会重传的,以是如果服务端的第二次挥手丢失了,客户端就会触发超时重传机制,重传 FIN 报文,直到收到服务端的第二次挥手,大概达到最大的重传次数。
第三次挥手丢失:如果迟迟收不到这个 ACK,服务端就会重发 FIN 报文,重发次数仍然由 tcp_orphan_retries 参数控制,这与客户端重发 FIN 报文的重传次数控制方式是一样的。
第四次挥手丢失:如果第四次挥手的 ACK 报文没有到达服务端,服务端就会重发 FIN 报文,重发次数仍然由前面先容过的 tcp_orphan_retries 参数控制。
也就是说,四次丢失导致的结果都是FIN重传。
19.为什么 TIME_WAIT 期待的时间是 2MSL?
四次挥手开始时,客户端和服务器都是连接已创建状态,客户端向服务器发送一个停止信号FIN,进入停止期待1,服务器收到后发送一个确认信号ACK,进入关闭期待状态,客户端收到后进入停止期待2,整个体系进入半连接状态,服务器向客户端发送FIN和ACK,ACK是对第一次挥手的重复确认,进入最后确认状态,客户端收到后发送ACK,进入时间期待状态(2MSL),服务器收到后进入关闭状态,2MSL之后客户端也进入关闭状态。至于为什么是2MSL,2倍的最大报文生存时间,是为了确保ACK可以或许到达服务器 ,以使其进入关闭状态,如果丢失可以或许重传,时间重新计时。
必要 TIME-WAIT 状态,紧张是两个缘故原由:
- 防止汗青连接中的数据,被反面雷同四元组的连接错误的接收;(这个时间足以让两个方向上的数据包都被扬弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包肯定都是新创建连接所产生的。)
- 包管「被动关闭连接」的一方,能被正确的关闭。
20.一些连接问题
服务器出现大量 TIME_WAIT 状态的缘故原由有哪些?说明服务器自动断开了很多 TCP 连接,什么场景下服务端会自动断开连接呢?第一个场景:HTTP 没有使用长连接;第二个场景:HTTP 长连接超时;第三个场景:HTTP 长连接的哀求数量达到上限。
服务器出现大量 CLOSE_WAIT 状态的缘故原由有哪些?
如果已经创建了连接,但是客户端突然出现故障了怎么办?保活机制:定义一个时间段,在这个时间段内,如果没有任何连接相关的运动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果一连几个探测报文都没有得到相应,则认为当前的 TCP 连接已经死亡,体系内核将错误信息通知给上层应用程序。
如果已经创建了连接,但是服务端的进程崩溃会发生什么?TCP 的连接信息是由内核维护的,以是当服务端的进程崩溃后,内核必要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不必要进程的参与,以是即使服务端的进程退出了,还是能与客户端完成 TCP 四次挥手的过程。
保活机制根本上是断开空闲的TCP连接的。如果两端的 TCP 连接不绝没有数据交互,达到了触发 TCP 保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文。
TCP 连接,一端断电和进程崩溃有什么区别?一端断电触发保活机制,进程崩溃差别。TCP 的连接信息是由内核维护的,以是当服务端的进程崩溃后,内核必要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不必要进程的参与,以是即使服务端的进程退出了,还是能与客户端完成 TCP四次挥手的过程。
拔掉网线几秒,再插回去,本来的 TCP 连接还存在吗?如果有数据传输,只要及时就会赶上超时重传。如果没有就触发保活机制,没有及时的话会断开连接。
HTTPS 中 TLS 和 TCP 能同时握手吗?不管 TLS 握手次数如何,都得先颠末 TCP 三次握手后才能举行,因为 HTTPS 都是基于 TCP 传输协议实现的,得先创建完可靠的 TCP 连接才能做 TLS 握手的事情。前两次握手并不能携带数据,第三次可以。
TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?
- HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
- TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制;
TCP 协议有哪些缺陷?紧张有四个方面:升级 TCP 的工作很困难;TCP 创建连接的延长;TCP 存在队头阻塞问题;网络迁移必要重新创建 TCP 连接。
服务端没有 listen,客户端发起连接创建,会发生什么?服务端如果只 bind 了 IP 地点和端口,而没有调用 listen 的话,然后客户端对服务端发起了连接创建,服务端会返回 RST 报文。
不使用 listen ,可以创建 TCP 连接吗?可以的,客户端是可以自己连自己的形成连接(TCP自连接),也可以两个客户端同时向对方发出哀求创建连接(TCP同时打开),这两个情况都有个共同点,就是没有服务端参与,也就是没有listen,就能创建连接。
没有 accept,能创建 TCP 连接吗?就算不实验accept()方法,三次握手照常举行,并顺利创建连接。半连接队列(SYN队列),服务端收到第一次握手后,会将sock加入到这个队列中,队列内的sock都处于SYN_RECV 状态。全连接队列(ACCEPT队列),在服务端收到第三次握手后,会将半连接队列的sock取出,放到全连接队列中。队列里的sock都处于 ESTABLISHED状态。这里面的连接,就等着服务端实验accept()后被取出了。创建连接的过程中根本不必要accept()参与,实验accept()只是为了从全连接队列里取出一条连接。全连接队列(icsk_accept_queue)是个链表,而半连接队列(syn_table)是个哈希表。出于效率考虑操持的,复杂度尽量低。全连接队列:服务端取走连接的过程中,并不关心具体是哪个连接,只要是个连接就行,以是直接从队列头取就行了。这个过程算法复杂度为O(1)。半连接队列:有一个第三次握手来了,则必要从队列里把相应IP端口的连接取出,哈希表,那么查找半连接的算法复杂度就回到O(1)了。
总结:
- 每一个socket实验listen时,内核都会自动创建一个半连接队列和全连接队列。
- 第三次握手前,TCP连接会放在半连接队列中,直到第三次握手到来,才会被放到全连接队列中。
- accept方法只是为了从全连接队列中拿出一条连接,本身跟三次握手几乎毫无关系。
- 出于效率考虑,固然都叫队列,但半连接队列着实被操持成了哈希表,而全连接队列本质是链表。
- 全连接队列满了,再来第三次握手也会扬弃,此时如果tcp_abort_on_overflow=1,还会直接发RST给客户端。
- 半连接队列满了,大概是因为受到了SYN Flood攻击,可以设置tcp_syncookies,绕开半连接队列。
- 客户端没有半连接队列和全连接队列,但有一个全局hash,可以通过它实现自连接或TCP同时打开。
TCP 是一个可靠的传输协议,那它肯定能包管数据不丢失吗?数据从发送端到接收端,链路很长,任何一个地方都大概发生丢包,几乎可以说丢包不可避免。TCP只包管传输层的消息可靠性,并不包管应用层的消息可靠性。
21.针对 TCP 应该如何 Socket 编程?
没有 accept,能创建 TCP 连接吗?accpet 体系调用并不参与 TCP 三次握手过程,它只是负责从 TCP 全连接队列取出一个已经创建连接的 socket,用户层通过 accpet 体系调用拿到了已经创建连接的socket,就可以对该 socket 举行读写操纵了。
22.TCP的一些点
超时重传时间RTO要略微大于报文来回时间RTT.
三次同样的ACK就会触发快速重传。
窗口巨细就是指无需期待确认应答,而可以继续发送数据的最大值。
SYN 报文什么时间情况下会被扬弃?1. 如果发现收到的数据包中时间戳不是递增的,则表现该数据包是过期的,就会直接扬弃这个数据包。2. 当服务器造成syn攻击,就有大概导致 TCP 半连接队列满了,这时反面来的 syn 包都会被扬弃。但是,如果开启了syncookies 功能,即使半连接队列满了,也不会扬弃syn 包。3. 在服务端并发处理大量哀求时,如果 TCP accpet 队列过小,大概应用程序调用 accept() 不及时,就会造成 accpet 队列满了 ,这时后续的连接就会被扬弃,这样就会出现服务端哀求数量上不去的现象。
在 TCP 正常挥手过程中,处于 TIME_WAIT 状态的连接,收到雷同四元组的 SYN 后会发生什么?如果处于 TIME_WAIT 状态的连接收到「正当的 SYN 」后,就会重用此四元组连接,跳过 2MSL 而变化为 SYN_RECV 状态,接着就能举行创建连接过程。如果处于 TIME_WAIT 状态的连接收到「非法的 SYN 」后,就会再回复一个第四次挥手的 ACK 报文,客户端收到后,发现并不是自己期望收到确认号,就回 RST 报文给服务端。RST标志用于逼迫关闭一个TCP连接。
23.TCP面向字节省,粘包和拆包
TCP 是面向字节省的协议,UDP 是面向报文的协议。是因为操纵体系对 TCP 和 UDP 协议的发送方的机制差别。当用户消息通过 UDP 协议传输时,操纵体系不会对消息举行拆分,每个 UDP 报文就是一个用户消息的边界。当用户消息通过 TCP 协议传输时,消息大概会被操纵体系分组成多个的 TCP 报文。因此,我们不能认为一个用户消息对应一个 TCP 报文,正因为这样,以是 TCP 是面向字节省的协议。当两个消息的某个部门内容被分到同一个 TCP 报文时,就是我们常说的 TCP 粘包问题,这时接收方不知道消息的边界的话,是无法读出有效的消息。粘包的问题出现是因为不知道一个用户消息的边界在哪,以是解决办法是:固定长度的消息、特殊字符作为边界、长度前缀、自定义协议来明确数据包的布局和边界。
24. 如何基于 UDP 协议实现可靠传输?
TCP 可靠传输的特性(序列号、确认应答、超时重传、流量控制、拥塞控制)
QUIC 是如何实现可靠传输的?
QUIC 通过单向递增的 Packet Number,配合 Stream ID 与 Offset字段信息,可以支持乱序确认而不影响数据包的正确组装,摆脱了TCP 必须按顺序确认应答 ACK 的限定,解决了 TCP 因某个数据包重传而阻塞后续所有待发送数据包的问题。
QUIC 是如何解决 TCP 队头阻塞问题的?
QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。
QUIC 是如何做流量控制的?
Stream 级别的流量控制:Stream 可以认为就是一条 HTTP 哀求,每个 Stream 都有独立的滑动窗口,以是每个 Stream 都可以做流量控制,防止单个 Stream 消耗连接(Connection)的全部接收缓冲。Connection 流量控制:限定连接中所有 Stream 相加起来的总字节数,防止发送方超过连接的缓冲容量。
QUIC 对拥塞控制改进
QUIC 是处于应用层的,应用程序层面就能实现差别的拥塞控制算法,不必要操纵体系,不必要内核支持。这是一个飞跃,因为传统的 TCP 拥塞控制,必须要端到端的网络协议栈支持,才能实现控制结果。而内核和操纵体系的部署本钱非常高,升级周期很长,以是 TCP 拥塞控制算法迭代速度是很慢的。而 QUIC 可以随浏览器更新,QUIC 的拥塞控制算法就可以有较快的迭代速度。TCP 更改拥塞控制算法是对体系中所有应用都见效,无法根据差别应用设定差别的拥塞控制策略。但是因为 QUIC 处于应用层,以是就可以针对差别的应用设置差别的拥塞控制算法,这样灵活性就很高了。
QUIC 更快的连接创建
HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成创建连接与密钥协商,乃至在第二次连接的时间,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的结果。
QUIC 是如何迁移连接的?
基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。那么当移动装备的网络从 4G 切换到 WIFI 时,意味着 IP 地点变化了,那么就必须要断开连接,然后重新创建 TCP 连接。QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标志通信的两个端点,客户端和服务器可以各自选择一组 ID 来标志自己,因此即使移动装备的网络变化后,导致 IP 地点变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的本钱,没有丝毫卡顿感,达到了连接迁移的功能。
三、数据库
1.MySQL部门
10.关系型数据库、非关系型数据库
关系型数据库一般将数据存储在表格中,核心思想是数据之间的关系可以通过表格中的键(如主键和外键)来表现和管理。如:MySQL。
非关系型数据库通常不使用表格布局,而是采用其他模型,如键值对、文档、图、列族等。如:Redis。NoSQL数据库在处理海量、快速变化的数据时表现出色。
11.基本写法
列出数据库:show databases;创建数据库:create database mysql_test;切换数据库:use mysql_test;列出表:show tables;创建表:create table student(s_id int,s_name varchar(8),s_birth date);表的列名在前,数据范例在后。在表中插入数据:insert into student values (1,'赵雷','1990-01-01'), (8,'王菊','1990-01-20');
12.实验一条 SQL 查询语句,期间发生了什么?
- 连接器:创建连接,管理连接、校验用户身份;
- 查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下实验。
- 解析 SQL,通过解析器对 SQL 查询语句举行词法分析、语法分析,然后构建语法树,方便后续模块读取表名、字段、语句范例;
- 实验 SQL:实验 SQL 共有三个阶段:1. 预处理阶段:检查表或字段是否存在;将 select * 中的 * 符号扩展为表上的所有列。2. 优化阶段:基于查询本钱的考虑, 选择查询本钱最小的实验操持。3. 实验阶段:根据实验操持实验 SQL 查询语句,从存储引擎读取记录,返回给客户端。
13.索引部门
131.索引的定义
索引是数据的目录,就是帮助存储引擎快速获取数据的一种数据布局。存储引擎,说白了就是如何存储数据、如作甚存储的数据创建索引和如何更新、查询数据等技术的实现方法。MySQL 存储引擎有 MyISAM 、InnoDB、Memory,其中 InnoDB 是在 MySQL 5.5 之后成为默认的存储引擎。索引和数据就是位于存储引擎中。
132.索引的分类
- 按「数据布局」分类:B+tree索引、Hash索引、Full-text索引。
- 按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)。
- 按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引。
- 按「字段个数」分类:单列索引、团结索引。
为什么 MySQL InnoDB 选择 B+tree 作为索引的数据布局?这是因为:B+树和B树相比,B+Tree 只在叶子节点存储数据,而 B 树 的非叶子节点也要存储数据,以是 B+Tree 的单个节点的数据量更小,在雷同的磁盘 I/O 次数下,就能查询更多的节点。另外,B+Tree 叶子节点采用的是双链表连接,适合 MySQL 中常见的基于范围的顺序查找,而 B 树无法做到这一点。B+树和二叉树相比,对于有 N 个叶子节点的 B+Tree,其搜刮复杂度为O(logdN),其中 d 表现节点允许的最大子节点个数为 d 个。而二叉树的每个父节点的儿子节点个数只能是 2 个,意味着其搜刮复杂度为 O(logN),这已经比 B+Tree 高出不少,因此二叉树检索到目标数据所经历的磁盘 I/O 次数要更多。B+树和Hash表相比, Hash 表不适合做范围查询,它更适合做等值的查询。
从物理存储的角度来看,索引分为聚簇索引(主键索引)、二级索引(辅助索引)。
- 主键索引的 B+Tree 的叶子节点存放的是现实数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;
- 二级索引的 B+Tree 的叶子节点存放的是主键值,而不是现实数据。
主键索引就是去用一个B+树去查主键字段,叶子节点存储的是整行数据,通过主键就可以获知全部信息,而二级索引则是去查其他字段,比如学生表中的姓名、结果等列的字段,叶子节点存储的是该二级字段以及主键,通过二级字段可以获知主键,然后通过回表去查该主键对应的整行数据,以是这种方式大概必要两个B+树才能查到数据。
133.为什么索引会加快查询的速度?
134.什么时间必要索引?什么时间不必要索引?
135.优化索引的办法
- 前缀索引优化;
- 覆盖索引优化;
- 主键索引最好是自增的;
- 防止索引失效;
136.为什么 MySQL 采用 B+ 树作为索引?
要操持一个适合 MySQL 索引的数据布局,至少满足以下要求:能在尽大概少的磁盘的 I/O 操纵中完成查询工作;要能高效地查询某一个记录,也要能高效地实验范围查找。
1361.什么是二分查找?
索引数据最好能按顺序排列,这样可以使用「二分查找法」高效定位数据。
1362.什么是二分查找树?
用数组来实现线性排序的数据固然简朴好用,但是插入新元素的时间性能太低。二叉查找树的特点是一个节点的左子树的所有节点都小于这个节点,右子树的所有节点都大于这个节点。当每次插入的元素都是二叉查找树中最大的元素,二叉查找树就会退化成了一条链表,查找数据的时间复杂度变成了 O(n)。由于树是存储在磁盘中的,访问每个节点,都对应一次磁盘 I/O 操纵(假设一个节点的巨细「小于」操纵体系的最小读写单元块的巨细),也就是说树的高度就等于每次查询数据时磁盘 IO 操纵的次数,以是树的高度越高,就会影响查询性能。
1363.什么是自平衡二叉树?
紧张是在二叉查找树的基础上增长了一些条件束缚:每个节点的左子树和右子树的高度差不能超过 1。不管平衡二叉查找树还是红黑树,都会随着插入的元素增多,而导致树的高度变高,这就意味着磁盘 I/O 操纵次数多,会影响团体数据查询的效率。当树的节点越多的时间,并且树的分叉数 M 越大的时间,M 叉树的高度会远小于二叉树的高度。
1364.什么是 B 树
为了解决降低树的高度的问题,反面就出来了 B 树,它不再限定一个节点就只能有 2 个子节点,而是允许 M 个子节点 (M>2),从而降低树的高度。但是 B 树的每个节点都包含数据(索引+记录),而用户的记录数据的巨细很有大概远远超过了索引数据,这就必要花费更多的磁盘 I/O 操纵次数来读到「有用的索引数据」。
1365.什么是 B+ 树?
B+ 树与 B 树差异的点,紧张是以下这几点:
- 叶子节点(最底部的节点)才会存放现实数据(索引+记录),非叶子节点只会存放索引;
- 所有索引都会在叶子节点出现,叶子节点之间构成一个有序链表;
- 非叶子节点的索引也会同时存在在子节点中,并且是在子节点中所有索引的最大(或最小);
- 非叶子节点中有多少个子节点,就有多少个索引;
以是,性能差距如下:
B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
B+ 树的插入和删除效率更高。
B+ 树所有叶子节点间还有一个链表举行连接,这种操持对范围查找非常有帮助。
14.事务部门
141.什么是事务?事务的特性?
事务是数据库操纵的基本单元,事务内的语句具有一致性,要么全部实验乐成,要么全部实验失败。事务的四个特性ACID:原子性,一致性,隔离性,长期性。原子性要么全乐成,要么全失败。一致性数据库状态要保持一致性。隔离性并发进程不会互相影响。长期性事务结束操纵之后数据库的修改永世保存。
142.并行事务会引发什么问题?
在同时处理多个事务的时间,就大概出现脏读、不可重复读、幻读的问题。
如果在上面这种情况事务 A 发生了回滚,那么事务 B 刚才得到的数据就是过期的数据,这种现象就被称为脏读。
脏读:读到其他事务未提交的数据;不可重复读:前后读取的数据不一致;幻读:前后读取的记录数量不一致。
143.事务的隔离级别有哪些?
SQL 标准提出了四种隔离级别来规避这些现象,隔离级别越高,性能效率就越低,这四个隔离级别如下:
- 读未提交(read uncommitted),指一个事务还没提交时,它做的变更就能被其他事务看到;
- 读提交(read committed),指一个事务提交之后,它做的变更才能被其他事务看到;
- 可重复读(repeatable read),指一个事务实验过程中看到的数据,不绝跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别;
- 串行化(serializable );会对记录加上读写锁,在多个事务对这条记录举行读写操纵时,如果发生了读写辩论的时间,后访问的事务必须等前一个事务实验完成,才能继续实验;
15.锁部门
151.MySQL 有哪些锁?
全局锁、表级锁(表锁、元数据锁、意向锁、AUTO-INC 锁)和行锁(Record Lock,记录锁、Gap Lock,间隙锁、Next-Key Lock,两锁组合)
16.MySQL如何调优?
- 创建索引:加速数据访问和操纵。
- 索引优化
- 查询优化
- 事务和锁
- 覆盖查询:减少数据读取,进步查询效率。
- 避免索引失效:确保索引可以或许被有效使用,避免性能下降。
2.Redis部门
四、C++、数据布局与算法
1.内存基础
11.内存分区
代码区:存储可实验代码(程序指令)。
全局区:存储全局变量和静态变量(已初始化和未初始化)。
堆区:用于动态内存分配,由程序员管理。
栈区:存储函数调用中的局部数据(局部变量、参数、返回地点)。
12.堆和栈有什么区别
堆和栈是用来内存分配和释放的两种差别的内存区域,内存管理就是内存分配和释放。栈的存储空间比较小,用于存储局部变量、函数参数、返回值,适合小数据布局的存储,内存分配和释放速度快,自动管理(自动分配、自动烧毁)。堆的存储空间较大,用于动态内存分配,适合大型数据布局存储,内存分配和释放速度较慢,手动管理(malloc、new、free、delete)。
2.指针
21.智能指针
智能指针是C++标准库中的一种工具,用于自动管理动态内存,避免内存泄漏和指针悬挂问题。智能指针紧张有以下几种范例:
1. std::unique_ptr
- 独占所有权:unique_ptr表现独占的所有权,即一个指针对象在任何时间只有一个所有者。
- 不可复制:unique_ptr不能被复制,只有通过std::move转移所有权。
- 场景:适合用于必要严格的所有权语义的场所,如资源管理。
2. std::shared_ptr
- 共享所有权:shared_ptr允许多个智能指针共享同一块内存。当最后一个shared_ptr释放时,内存才会被释放。
- 引用计数:每个shared_ptr都有一个引用计数,用于记录有多少shared_ptr共享该内存块。
- 场景:适用于必要在多个地方共享资源的情况。
3. std::weak_ptr
- 弱引用:weak_ptr不会影响引用计数,不能直接访问资源,必要先提拔为shared_ptr。
- 防止循环引用:常用于打破shared_ptr之间的循环引用,避免内存泄漏。
- 场景:适用于必要观察但不拥有资源的场景,如缓存或观察者模式中。
智能指针的作用
- 自动内存管理:智能指针在离开作用域时自动释放资源,避免了手动释放内存的贫苦和错误。
- 防止内存泄漏:通过智能指针的自动内存管理机制,减少了忘记释放内存导致的内存泄漏问题。
- 简化代码:智能指针封装了内存管理细节,简化了资源管理的代码。
22.常量指针和指针常量有什么区别?
看const反面跟的什么,跟的int就是修饰数据,数据不可变,指针指向可变,称为指针变量const int *p。跟的p就是修饰指针,指针指向不可变,数据可变,称为变量指针int * const p。
23.define 和 const 的区别?
作用:用于记录程序中不可更改的数据
C++定义常量两种方式
1. #define 宏常量: #define 常量名 常量值
==通常在文件上方定义==,表现一个常量
2. const修饰的变量 const 数据范例 常量名 = 常量值
==通常在变量定义前加关键字const==,修饰该变量为常量,不可修改
24.static的作用
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员,可以通过对象和类名两种方式访问。静态成员分为:
静态成员变量:1.所有对象共享同一份数据;2.在编译阶段分配内存;3.类内声明,类外初始化;
静态成员函数:1.所有对象共享同一个函数;2.静态成员函数只能访问静态成员变量。(因为静态属于类,非静态属于对象 ,静态成员变量是由类调用的,不用区分是类中的哪个对象调用,但是非静态成员变量是由对象调用的,这时间用静态成员函数去调用非静态成员变量,无法区分到底是哪个对象调用的变量)
静态成员是指属于类本身而不是类的实例的成员。静态成员有以下意义:
共享性:静态成员被所有类的实例共享,可以在不创建类的实例的情况下访问和修改静态成员。
保存状态:静态成员可以用来保存类的状态信息,比方计数器、设置信息等,这些信息可被所有实例共享和访问。
简化访问:可以通过类名直接访问静态成员,无需创建类的实例。这样可以简化代码并进步代码的可读性。
与类相关联:静态成员通常与类本身相关联,而不是与类的实例相关联。这样可以更好地表达类的特性和行为。
3.虚函数
31.什么是虚函数?什么是纯虚函数?
- 虚函数 用于在基类中声明,并允许在派生类中重写,以实现多态性。
- 纯虚函数 是没有实现的虚函数,存在于抽象类中,必须在派生类中实现,否则派生类也将成为抽象类。纯虚函数常用于定义接口,逼迫派生类提供特定的功能。
析构函数可以是虚函数吗?
4.vector容器
std::vector 是 C++ 标准库中的动态数组,它会根据必要自动调整其容量以容纳更多的元素。std::vector 会在内部维护一个存储空间的容量(capacity),这个容量通常会大于或等于当前元素的数量(size)。当向 std::vector 中添加元素并且元素的数量超过当前容量时,vector 会重新分配更大的内存空间来容纳这些元素。这个过程包罗:
- 分配新的内存块:vector 会分配一个更大的内存块以容纳更多的元素。
- 复制现有元素:将旧内存块中的元素复制到新的内存块中。
- 释放旧内存块:释放旧的内存块以释放内存。
std::vector 的初始容量和扩容策略取决于具体的实现,但一般来说,std::vector 的初始容量为 0。也就是说,当你创建一个空的 vector 对象时,它通常没有分配任何内存用于存储元素。
初次扩容
std::vector 的初次扩容通常发生在以下几种情况:
- 添加元素:当你向一个空的 vector 中添加第一个元素时,vector 会举行初次扩容。此时,它会分配一个富足容纳至少一个元素的内存块。许多实现将初始容量设置为较小的值,比如 1 或 4,以进步性能。
- 构造函数:如果你使用特定构造函数创建 vector,比如 vector(size_type count, const T& value) 或 vector(std::initializer_list<T> init),vector 会根据提供的初始元素数量预分配内存,以减少后续的扩容次数。
扩容策略
在添加更多元素并超过当前容量时,std::vector 会举行扩容。扩容通常遵照以下策略:
- 容量增长:每次扩容时,vector 的容量通常会增长到当前容量的两倍,这样可以减少扩容的次数和内存分配的开销。(2倍策略通常在性能和内存使用之间提供了一个好的折衷)
- 策略实现:差别的标准库实现大概会有差别的策略,但大多数都遵照类似的增量规则以确保高效的内存管理。
扩容过程中,std::vector 必要重新分配内存,复制现有元素到新的内存块中,并释放旧的内存块。这个过程是自动举行的,用户不必要手动处理。
5.先容几种常用的排序算法
冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |