面试知识点
Created at 2019-05-16 Updated at 2020-07-29 Category 基础 views
根据 cyc2018 的 一文帮你理清面试知识点 和 博客 以及其他资料整理而成。
💻操作系统
基础
★★★ 进程与线程的本质区别、以及各自的使用场景
- 拥有资源:进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。
- 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
- 系统开销:由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。
- 通信方面:线程间通信可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC。
★☆☆ 进程状态。
- 就绪状态:等待被调度
- 运行状态
- 阻塞状态:等待资源
- 只有就绪和运行态可以相互转换,其他的都是单项转换。就绪状态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完以后就会转为就绪状态,等待下一次调度
- 阻塞状态是缺少需要的资源从运行状态转换而来的,但是该资源不包括 CPU 时间,缺少 CPU 时间会从运行态转换为就绪态
★★★ 进程调度算法的特点以及使用场景。
- 先来先服务:有利于长作业不利于短作业
- 短作业优先:长作业可能会饿死
- 最短剩于时间优先:按估计剩于时间最短的顺序进行调度
- 时间片轮转:时间片轮转算法的效率和时间片大小有很大关系
- 优先级调度:
- 多级反馈队列:
★☆☆ 线程实现的方式。
★★☆ 协程的作用。
★★☆ 常见进程同步问题。
★★★ 进程通信方法的特点以及使用场景。
- 管道:无名管道是一种特殊的文件,只存在于内存中,只支持半双工通信,只能在父子进程中使用。
- FIFO:命名管道,是 FIFO 文件,存在于文件系统中,去除了管道只能在父子进程中使用的限制。FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
- 消息队列:相比于 FIFO,消息队列具有以下优点:
- 消息队列可以独立于读写进程存在,从而避免了FIFO 中同步管道的打开和关闭时可能产生的困难。
- 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法
- 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收
- 共享数据:允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是最快的一种 IPC。需要使用信号量用来同步对共享存储的访问。多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。另外 XSI 共享内存不是使用文件,而是使用使用内存的匿名段。
- 信号量:它是一个计数器,用于为多个进程提供共享数据对象的访问。
- 套接字:与其它通信机制不同的是,它可用于不同机器间的进程通信。
★★★ 死锁必要条件、解决死锁策略,能写出和分析死锁的代码,能说明在数据库管理系统或者 Java 中如何解决死锁。
- 互斥
- 占有和等待
- 环路等待
- 不可抢占
★★★ 虚拟内存的作用,分页系统实现虚拟内存原理。
虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。
操作系统将内存抽象成为地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。
★★★ 页面置换算法的原理,特别是 LRU 的实现原理,最好能手写,再说明它在 Redis 等作为缓存置换算法。
- 最佳
- 最近最久未使用 LRU:基于双向链表 + HashMap 的算法实现
- 访问某个节点,将其从原来位置删除,并重新插入到链表头部。这样就能保证链表尾部存储的就是最近最久未使用的节点,当节点数量大于缓存最大空间时就淘汰链表尾部的节点
- 为了使删除操作的时间复杂度为 O(1),就不能采用遍历的方式找到某个节点。HashMap 存储着 Key 到节点的映射,通过 Key 就能以 O(1) 的时间得到节点,然后再以 O(1) 的时间将其从双向队列中删除。
- 最近未使用 NRU
- 先进先出 FIFO
- 第二次机会算法
- 时钟 CLOCK
★★★ 比较分页与分段的区别。
- 对程序员的透明性:分页透明,但是分段需要程序员显示划分每个段
- 地址空间的维度:分页是一维地址,分段是二维的
- 大小是否可以改变:页的大小不可变,段的大小可以动态改变
- 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
★★★ 分析静态链接的不足,以及动态链接的特点。
- 静态链接有两个问题:
- 当静态库更新时那么整个程序都要重新进行链接
- 对于 printf 这种标准函数库,如果每个程序都要有代码,这会造成极大浪费资源
- 动态链接的特点:
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用他们的可执行文件中
- 在内存中,一个共享库的 .text 节(以编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。
Linux
★★☆ 文件系统的原理,特别是 inode 和 block。数据恢复原理。
- 对分区进行格式化是为了在分区上建立文件系统。一个分区通常只能格式化为一个文件系统,但是磁盘阵列等技术可以将一个分区格式化为多个文件系统
- inode:一个文件占用一个inode,记录文件属性,同时记录此文件的内容所在的block编号
- block:记录文件的内容,文件太大时,会产生多个block
- 对于 Ext2 文件系统,当药读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有block,然后把所有的 block 内容读取出来
- 对于 FAT 文件系统,它没有 inode ,每个 block 中存储着下一个 block 的编号
- ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件系统
- 目录:建立一个目录时,会分配一个 inode 与至少一个 block。block 记录的是目录下所有文件的 inode 编号以及文件名。文件的 inode 本身不记录文件名,文件名记录在目录中。因此,拥有文件的 w 权限并不能对文件名进行修改
★★★ 硬链接与软链接的区别。
- 硬链接:在目录下创建一个条目,记录着文件名与 inode编号,这个 inode 就是源文件的 inode。不能跨越文件系统,不能对目录链接
- 软链接:软链接文件保存着原文件所在的绝对路径,在读取时会定位到源文件上。可以为目录链接
★★☆ 能够使用常用的命令,比如 cat 文件内容查看、find 搜索文件,以及 cut、sort 等管线命令。了解 grep 和 awk 的作用。
- cat 取得文件内容
- find 文件搜索。可以使用文件的属性和权限进行搜索
- cut 对数据进行切分,取出想要的部分
- sort 用于排序
- grep 使用正则表达式进行全局查找并打印
- awk 是一门模式匹配的编程语言,主要功能是用于匹配文本并处理。
★★★ 僵尸进程与孤儿进程的区别,从 SIGCHLD 分析产生僵尸进程的原因。
- 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将会成为孤儿进程。孤儿进程将会被 init 进程(进程号为1)所收养,并由 init 进程对他们完成状态收集工作。由于孤儿进程会被 init 所收养,所以孤儿进程不会对系统造成危害
- 僵尸进程:如果子进程退出,而父进程并没有调用 wait() 或 waitpid(),那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵尸进程。系统所能使用的进程号是有限的,如果产生大量僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。要消灭系统中大量的僵尸进程,只需要将其父进程杀死,此时僵尸进程就会变成孤儿进程,从而被 init 所收养,这样 init 就会释放所有的僵尸进程所占有的资源,从而结束僵尸进程。
- SIGCHLD:当一个子进程改变了他的状态时,父进程会得到 SIGCHLD 信号,waitpid() 或者 wait()调用会返回。其中子进程发送的 SIGCHLD 信号包含了子进程的信息,比如进程 ID、进程状态、进程使用 CPU 的时间等。在子进程退出时,他的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
☁️网络
基础
★★★ 各层协议的作用,以及 TCP/IP 协议的特点。
- 应用层:为特定应用程序提供数据传输服务。 HTTP、DNS。
- 传输层:为进程提供通用数据传输服务。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。
- 网络层:为主机提供数据传输服务。而传输层协议是为主机中的进程提供数据传输服务。网络层把传输层传递下来的报文段或者用户数据报封装成分组。
- 数据链路层:为同一链路的主机提供数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧。
- 物理层:考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。
- TCP/IP:只有四层,相当于五层协议中数据链路层和物理层合并为网络接口层。TCP/IP 协议体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。
★★☆ 以太网的特点,以及帧结构。
- 以太网是一种星型拓扑结构局域网。
- 以太网帧格式
- 类型:标记上层使用的协议;
- 数据:长度在 46-1500 之间秒如果太小则需要填充;
- FCS:帧检验序列,使用的是 CRC 检验方法;
★★☆ 集线器、交换机、路由器的作用,以及所属的网络层。(https://www.tianmaying.com/tutorial/NetWorkInstrument)
- 集线器:物理层设备。作用于比特而不是帧,当一个比特到达接口时,集线器重新生成这个比特,并将其能量强度放大,从而扩大网络的传输距离,之后再将这个比特发送到其他所有接口。如果集线器同时收到两个不同接口的帧,那么就发生了碰撞。
- 交换机:链路层设备。是一种基于 MAC 识别,能完成封装转发数据包功能的网络设备。它不会发生碰撞,能根据 MAC 地址进行存储转发。
- 路由器:网络层设备。是一种连接多个网络或网段的网络设备,根据 IP 进行转发。
★★☆ IP 数据数据报常见字段的作用。
- 版本:有 4(IPv4)和 6(IPv6)两个值;
- 首部长度 : 占 4 位,因此最大值为 15。值为 1 表示的是 1 个 32 位字的长度,也就是 4 字节。因为首部固定长度为 20 字节,因此该值最小为 5。如果可选字段的长度不是 4 字节的整数倍,就用尾部的填充部分来填充。
- 区分服务 : 用来获得更好的服务,一般情况下不使用。
- 总长度 : 包括首部长度和数据部分长度。
- 生存时间 :TTL,它的存在是为了防止无法交付的数据报在互联网中不断兜圈子。以路由器跳数为单位,当 TTL 为 0 时就丢弃数据报。
- 协议 :指出携带的数据应该上交给哪个协议进行处理,例如 ICMP、TCP、UDP 等。
- 首部检验和 :因为数据报每经过一个路由器,都要重新计算检验和,因此检验和不包含数据部分可以减少计算的工作量。
- 标识 : 在数据报长度过长从而发生分片的情况下,相同数据报的不同分片具有相同的标识符。
- 片偏移 : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。
★☆☆ ARP 协议的作用,以及维护 ARP 缓存的过程。
- ARP 实现由 IP 地址得到 MAC 地址
- 如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到MAC 地址的映射。
★★☆ ICMP 报文种类以及作用;和 IP 数据报的关系;Ping 和 Traceroute 的具体原理。
- ICMP 报文分为差错报告报文和询问报文
- ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中,但不属于高层协议
- Ping 的原理是通过向目的主机发送 ICMP Echo 请求报文,目的主机收到之后会发送 Echo 回答报文。Ping 会根据时间和成功相应次数估算出数据包往返时间以及丢包率
- Traceroute 发送的 IP 数据报封装的是无法交付的 UDP 用户数据报,并由目的主机发送终点不可达差错报告报文。
- 源主机向目的主机发送一连串的 IP 数据报。第一个数据报 P1 的生存时间 TTL 设置为 1,当 P1 到达路径上的第一个路由器 R1 时,R1 收下它并把 TTL 减 1,此时 TTL 等于 0,R1 就把 P1 丢弃,并向源主机发送一个 ICMP 时间超过差错报告报文;
- 源主机接着发送第二个数据报 P2,并把 TTL 设置为 2。P2 先到达 R1,R1 收下后把 TTL 减 1 再转发给 R2,R2 收下后也把 TTL 减 1,由于此时 TTL 等于 0,R2 就丢弃 P2,并向源主机发送一个 ICMP 时间超过差错报文。
- 不断执行这样的步骤,直到最后一个数据报刚刚到达目的主机,主机不转发数据报,也不把 TTL 值减 1。但是因为数据报封装的是无法交付的 UDP,因此目的主机要向源主机发送 ICMP 终点不可达差错报告报文。
- 之后源主机知道了到达目的主机所经过的路由器 IP 地址以及到达每个路由器的往返时间。
★★★ UDP 与 TCP 比较,分析上层协议应该使用 UDP 还是 TCP。
- 传输控制协议 TCP:是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。TCP 主要提供完整性服务。
- 用户数据报协议 UDP:是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。。主要提供及时性服务。
★★★ 理解三次握手以及四次挥手具体过程,三次握手的原因(https://www.jianshu.com/p/7d0f91345483)、四次挥手原因、TIME_WAIT 的作用。
https://www.zhihu.com/question/24853633
- 三次握手:
- 服务器处于 LISTEN 状态,等待来自客户端的连接请求
- 客户端向服务器发送连接请求报文 SYN=1
- 服务器收到客服端发来的 SYN,如果同意建立连接,则向客户端发送确认报文 SYN=1,ACK=1
- 客户端收到 SYN ACK 后,还要向服务器发出确认报文 ACK
- 服务器收到 ACK 后,连接建立
- 连接建立以后,ACK 都置为 1
- 第三次握手可以携带数据,如果不携带数据则不消耗序号
- 三次握手的原因
对于握手:握手只需要确认双方通信时的初始化序号,保证通信不会乱序。(第三次握手必要性:假设服务端的确认丢失,连接并未断开,客户机超时重发连接请求,这样服务器会对同一个客户机保持多个连接,造成资源浪费。) - 四次挥手:
- 客户端发送释放报文 FIN
- 服务器收到 FIN 后发出确认 ACK,此时 TCP 属于半关闭状态(CLOSED_WAIT),服务器能向客户端发送数据但是客户端不能向服务器发送数据
- 当服务器不再需要连接时,发送连接释放报文 FIN
- 客户端收到 FIN 后发出确认 ACK,进入 TIME-WAIT 状态,等待 2 倍的 MSL(最大报文存活时间)后释放连接
- 服务器收到 ACK 后释放连接
- 四次挥手的原因:客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器发送还为传送完毕的数据,传送完毕后,服务器会发送 FIN 连接释放报文。
- TIME_WAIT:客户端收到服务端的 FIN 报文址后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
- 确保最后一个报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,是的下一个连接不会出现九的连接请求报文。
★★★ 可靠传输原理,并设计可靠 UDP 协议。
- 建立连接(标志位):通信前确认通信实体存在
- 序号机制(序号、确认号):确保了数据是按序、完整到达
- 数据校验(校验和):CRC 校验全部数据,校验包出错,丢弃报文段,不给出响应,超时重发
- 超时重传(定时器):保证因链路故障未能到达数据能够被多次重发。
- RTT:数据从发送到接收到对方响应之间的时间间隔,即数据报在网络中一个往返用时。大小不稳定。
- RTO:重传间隔,通常每次重传 RTO 是前一次重传间隔的两倍,重传次数达到上限后停止重传。RTO = RTTs + 4*RTTd
- 流量控制(流量窗口):避免发送过量
- 目的是接收方通过 TCP 头窗口字段告知发送方本方可接收的最大数据量,用以解决发送速率过快导致接收方不能接收的问题。
- 发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段来告诉发送方自己的窗口大小,发送方根据这个值来设置自己窗口大小。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态,接收窗口类似。
- TCP 是流数据,发送出去的数据流可以被分为以下四部分:已发送且被确认部分 | 已发送未被确认部分 | 未发送但可发送部分 | 不可发送部分,其中发送窗 = 已发送未确认部分 + 未发但可发送部分。接收到的数据流可分为:已接收 | 未接收但准备接收 | 未接收不准备接收。接收窗 = 未接收但准备接收部分。
- 发送窗内的数据只有当收到接收端某段发送数据的 ACK 响应时才移动发送窗。接收窗口只会对窗口最后一个按序到达的字节进行确认。
- 拥塞控制(拥塞窗口)
★★☆ TCP 拥塞控制的作用,理解具体原理。
- 为了降低整个网络的拥塞程度。
- 拥塞控制使用拥塞窗口。TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
- 慢开始:发送的最初执行慢开始,令 cwnd = 1,发送方只能发送一个报文段,当收到确认后,将 cwnd 加倍。
- 拥塞避免:设置一个慢开始门限 ssthresh ,当cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
- 快重传:在发送方,如果收到 3 个重复确认,那么知道下一个报文段丢失,此时执行快重传,立刻重传下一个报文段。
- 快恢复:快重传之后执行快恢复,令 ssthresh = cwnd / 2,cwnd = ssthresh,此时直接进入拥塞避免。
- 慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
- 流量控制和拥塞控制:
- 流量控制属于通信双方协商,拥塞控制涉及通信链路全局
- 实际最终发送窗口 = min{流量控制发送窗口,拥塞窗口}
★★☆ DNS 的端口号;TCP 还是 UDP;作为缓存、负载均衡。
- DNS可以使用 UDP 和 TCP 进行传输,使用的端口号都为53.大多数情况下 DNS 使用 UDP 进行传输,这就要求域名解析器和域名服务器都必须自己处理超市和重传来保证可靠性。在两种情况下会使用 TCP 进行传输:
- 如果返回的响应超过 512 字节(UDP 最大只支持 512 字节的数据)。
- 区域传送(区域传送是主域名服务器向辅助域名服务器传送变化的那部分数据)。
HTTP
★★★ GET 与 POST 比较:作用、参数、安全性、幂等性、可缓存。
- 作用:GET 用于获取资源,而 POST 用于传输实体主体。
- 参数:GET 和 POST 的请求都能使用额外的参数,但是 GET 的 参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如
中文会转换为%E4%B8%AD%E6%96%87,而空格会转换为%20。POST 参考支持标准字符集。 - 安全性:安全的 HTTP 方法不会改变服务器状态,也就是说他只是可读的。GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。安全的方法除了 GET 之外还有:HEAD、OPTIONS。不安全的方法除了 POST 之外还有 PUT、DELETE。
- 幂等性:幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。所有的安全方法也都是幂等的。在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
- 可缓存:如果要对响应进行缓存,需要满足以下条件:
- 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
- 响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。
- 响应报文的 Cache-Control 首部字段没有指定不进行缓存。
★★☆ HTTP 状态码。
| 状态码 | 类别 | 含义 |
|---|---|---|
| 1XX | Informational(信息性状态码) | 接受的请求正在处理 |
| 2XX | Successful(成功状态码) | 请求正常处理完毕 |
| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
| 5XX | Server Error(服务器错误状态码) | 服务器请求处理出错 |
- 100 Continue:表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
- 200 Ok
- 204 No Content:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
- 206 Partial Content:表示客户端进行了范围请求,响应报文包含由 Conent-Range 指定范围的实体内容。
- 301 Moved Permanently:永久重定向
- 302 Found:临时性重定向
- 303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
- 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
- 304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
- 307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
- 400 Bad Request:请求报文中存在语法错误
- 401 Unauthorized:该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
- 403 Fobidden:请求被拒绝
- 404 Not Found
- 500 Internal Server Error :服务器正在执行请求时发生错误。
- 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
★★★ Cookie 作用、安全性问题、和 Session 的比较。
- 用途:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
- 标记为 HttpOnly 的 Cookie 不能被 Javascript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的
document.cookieAPI 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。 - 标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。
- Cookie 与 Session 选择
- Cookie 只能存储 ASCII 码字符串,而 Session 则可以存取任何类型的数据,因此在考虑数据复杂性时首选 Session;
- Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
- 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。
★★☆ 缓存的 Cache-Control 字段,特别是 Expires 和 max-age 的区别。ETag 验证原理。
- HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。
- no-store 指令规定不能对请求或响应的任何一部分进行缓存
Cache-Control:no-store - no-cache 指令规定缓存服务器需要先向源服务器验证缓存的有效性,只有当缓存服务器有效才将能使用该缓存对客户端的请求进行相应
- private 指令规定了将资源作为私有缓存,只能被单独用户所使用,一般存储在用户浏览器中。public 指令规定了将资源作为公共缓存,可以被多个用户所使用,一般存储在代理服务器中。
- max-age 指令出现在请求报文中,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。max-age 指令出现在响应报文中,表示缓存资源在缓存服务器中保存的时间。Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。在 HTTP/1.1 中,会优先处理 max-age 指令;在 HTTP/1.0 中,max-age 指令会被忽略掉。
- ETag:它是资源的唯一标识。URL 不能唯一表示资源,例如
http://www.google.com/有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。ETag: "82e22293907ce725faf67773957acd12"可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。If-None-Match: "82e22293907ce725faf67773957acd12"
★★★ 长连接与短连接原理以及使用场景,流水线。
- 当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。
- 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用
Connection : close; - 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用
Connection : Keep-Alive。
★★★ HTTP 存在的安全性问题,以及 HTTPs 的加密、认证和完整性保护作用。
- 安全性问题:
- 使用明文进行通信,内容可能会被窃听
- 不验证通信方身份,通信方的身份可能遭遇伪装
- 无法验证报文的完整性,报文有可能遭篡改
- HTTPs:让 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是说 HTTPs 使用了隧道进行通信。通过使用 SSL,HTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
★★☆ HTTP/1.x 的缺陷,以及 HTTP/2 的特点。
- HTTP/1.X 缺陷:
- 客户端需要使用多个连接才能实现并发和缩短延迟
- 不会压缩请求和响应首部,从而导致不必要的网络流量
- 不支持有效的资源优先级,导致底层 TCP 连接的利用率低下
- HTTP/2:
- 二进制分帧层:HTTP/2.0将报文分成 HEADERS 帧和 DATA 帧,它们嗾使二进制格式的。在通信过程中,只会有一个 TCP 连接存在,它承载力任意数量的数据流。
- 服务器推送:HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
- 首部压缩:HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
★★★ HTTP/1.1 的特性。
- 默认是长连接
- 支持流水线
- 支持同时打开多个 TCP 连接
- 支持虚拟主机
- 新增状态码 100
- 支持分块传输编码
- 新增缓存处理指令 max-age
★★☆ HTTP 与 FTP 的比较。
- FTP 使用 TCP 进行连接,它需要两个连接来传送一个文件
- 控制连接:服务器打开端口号 21 等待客户端的连接,客户端主动建立连接后,使用这个连接将客户端的命令传送给服务器,并传回服务器的应答
- 数据连接:用来传送一个文件数据
Socket 网络 I/O模型
★★☆ 五种 IO 模型的特点以及比较。
- 阻塞式 I/O:应用进程被阻塞,直到数据复制到应用进程缓冲池中才被返回。
- 非阻塞式 I/O:应用进程执行系统调用后,内核返回一个错误码。应用进程可以继续执行,但是需要不断地执行系统调用来获知 I/O是否完成,这种方式成为轮询(polling)。
- I/O 复用:使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvform 把数据从内核复制到进程中。它可以让单个进程具有处理多个 I/O事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。
- 信号驱动 I/O:应用进程使用 sigaction 系统调用,内核立即返回,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用程序中。
- 异步 I/O:应用进程执行 aio_read 系统调用会立即返回,应用程序可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
比较:
- 同步 I/O:将数据从内核缓冲区复制到应用进程缓冲区的阶段,应用进程会阻塞。
- 异步 I/O:不会阻塞。
- 阻塞式 I/O、非阻塞式 I/O、I/O 复用和信号驱动 I/O 都是同步 I/O,它们的主要区别在第一个阶段。
- 非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
★★★ select、poll、epoll 的原理、比较、以及使用场景;epoll 的水平触发与边缘触发。
select:
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
有三种类型的描述符类型:readset、writeset、execptset,分别对应读、写、异常条件的描述符集合。fd_set使用数组实现,数组大小使用 FD_SETSIZE 定义。timeout 为超时参数,调用 select 会一直阻塞直到有描述符事件到达或者等待时间超过 timeout。成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。
poll:
int poll(struct pollfd*fds,unsigned int fds, int timeout)
pollfd使用链表实现
select 和 poll 比较:
- select 会修改描述符,poll不会。
- select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此只能监听 1024 个描述符。如果要监听更多描述符,需要修改 FD_SETSIZE 之后重新编译。而 poll 的描述符类型使用链表实现,没有描述符数量的限制。
- poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高
- 如果一个线程对某个描述符调用了 select 或者 poll,另一个线程关闭了该描述符,会导致调用结果不确定。
- 速度:select 和 poll速度都比较慢
- select 和 poll 每次调用都需要将 全部描述符从应用进程缓冲池区复制到内核缓冲区
- select 和 poll 的返回结果中没有声明哪些描述符已经准备好,所以如果返回值大于等于 0 时,应用程序需要使用轮询的方式来找到 I/O 完成的描述符。
- 可移植性:几乎所有的系统都支持 select。但是只有比较新的系统支持 poll。
epoll:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数会将 I/O 准备好的描述符加入到另一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。
从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得时间完成的描述符。
epoll 仅适用于 Liunx OS。
epoll 比 select 和 poll 更加灵活而且没有描述符数量限制
epoll 对多线程编程更加友好,一个线程调用了 epoll_wait() 另一个线程关闭了同一个描述符也不会产生像 select 和 poll的不确定情况
工作模式:
epoll 的描述符事件有两种触发模式:LT(level trigger)水平触发 和 ET(edge trigger)边缘触发
- LT 模式:当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程,进程可以不立即处理该事件,下次调用 epoll_wait() 会再次通知进程。是默认的一种模式,并且同时支持 Blocking 和 No-Blocking。
- ET 模式:和 LT 模式不同的是,通知之后进程必须立即处理事件,下次再调用 epoll_wait() 时不会再得到事件到达的通知。很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。只支持 No-Blocking ,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
应用场景
- select:select 的 timeout 参数精度为 1ns,而 poll 和 epoll 为 1ms,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。select 可移植性更好,几乎被所有主流平台所支持。
- poll:poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。
- epoll:只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。
需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。
需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。
💾数据库
SQL
★★☆ 手写 SQL 语句,特别是连接查询与分组查询。
★★☆ 连接查询与子查询的比较。
- 连接可以替换子查询,并且比子查询的效率一般会更快。
★★☆ drop、delete、truncate 比较。
- DELETE 删除表中 WHERE 语句指定的数据
- TRUNCATE 清空表,相当于删除表中所有数据
- DROP 删除表结构
- DELETE 会被放到日志中以便进行回滚,THUNCATE 和 DROP 立即生效,不会放到日志中,也不支持回滚
★★☆ 视图的作用,以及何时能更新视图。
- 简化复杂的查询,比如复杂的连接查询
- 只使用实际表的一部分数据
- 通过只给用户访问视图的权限,保证数据的安全性
- 更改数据格式和表示。
- 因为视图不存储数据,所以更新视图需要去更新原始表。如果视图定义只依赖于一个原始表,就很容易进行更新操作。但如果视图定义中有以下操作,那么就不能进行视图的更新:
- 分组查询
- 连接查询
- 子查询
- Union
- 聚集函数
- DISTINCT
- 计算字段
★☆☆ 理解存储过程、触发器等作用。
- 存储过程可以看成是对一系列 SQL 操作的批处理。
- 触发器会在某个表执行以下语句时自动执行:DELETE、INSERT、UPDATE。
系统原理
★★★ ACID 的作用以及实现原理。
- 只有满足一致性,事务的执行结果才是正确的。
- 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
- 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对数据库崩溃的情况。
★★★ 四大隔离级别,以及不可重复读和幻影读的出现原因。
- 未提交读(READ UNCOMMITTED):事务中的修改,即使没有提交,对其它事务也是可见的。脏读
- 提交读(READ COMMITTED):一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。重复读
- 可重复读(REPEATABLE READ):保证在同一个事务中多次读取同样数据的结果是一样的。幻影读
- 可串行化(SERIALIZABLE):强制事务串行执行。
- 不可重复读:T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
- 幻影读:T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
★★☆ 封锁的类型以及粒度,两段锁协议,隐式和显示锁定。
- 封锁类型:
- 1.读写锁
- 排他锁(Exclusive),简写为 X 锁,又称写锁。
- 共享锁(Shared),简写为 S 锁,又称读锁。
- 一个事务对数据对象 A 加了 X 锁,就可以对 A 进行读取和更新。加锁期间其他事务不能对 A 加任何锁。
- 一个事务对数据对象 A 加了 S 锁,就可以对 A 进行读取操作,但是不能进行更新操作。加锁期间其它事务能对 A 加 S 锁,但是不能加 X 锁。
- 2.意向锁
- 使用意向锁可以更容易地支持多粒度封锁。
- 一个事务在获得某个数据行对象的 S 锁之前,必须先获得表的 IS 锁或者更强的锁
- 一个事务在获得某个数据行对象的 X 锁之前,必须先获得表的 IX 锁。
- 通过引入意向锁,事务 T 想要对表 A 加 X 锁,只需要先检测是否有其它事务对表 A 加了 X/IX/S/IS 锁,如果加了就表示有其它事务正在使用这个表或者表中某一行的锁,因此事务 T 加 X 锁失败。
- 封锁粒度:行级锁和表级锁
- 应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
- 但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。
- 在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。
- 两段锁协议:
- 加锁和解锁分为两个阶段进行
- MySQL 隐式与显示锁定:MySQL 的 InnoDB 存储引擎采用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有的锁都是在同一时刻被释放,这被称为隐式锁定。InnoDB 也可以使用特定的语句进行显示锁定
★★★ 乐观锁与悲观锁。SELECT ... LOCK In SHARE MODE; SELECT ... FOR UPDATE;
★★★ MVCC 原理,当前读以及快照读,Next-Key Locks 解决幻影读。
★★☆ 范式理论。
★★★ SQL 与 NoSQL 的比较。
MySQL
★★★ B+ Tree 原理,与其它查找树的比较。
- B+ 树是一颗查找树,并且所有叶子节点位于同一层
- B+ Tree 是基于 B Tree 和叶子节点顺寻访问指针进行实现,它具有 B Tree 的平衡性,并且通过顺序访问指针来提高区间查询的性能。
- 在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1。
- 与红黑树的比较
- 更少的查找次数:平衡树查找操作的时间复杂度和树高 h 相关,O(h)=O(logdN),其中 d 为每个节点的出度。红黑树的出度为 2,而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。
- 利用磁盘预读特性:为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,速度会非常快。操作系统一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。并且可以利用预读特性,相邻的节点也能够被预先载入.
- 为什么MySQL数据库要用B+树存储索引?
★★★ MySQL 索引以及优化。
- 从结构层:web 服务器采用负载均衡服务器,MySQL 服务器采用主从复制,读写分离。
- 从储存层:采用合适的存储引擎,采用三范式。
- 从设计层:采用分区分表,表的字段采用合适的字段属性,适当的采用逆范式,开启 MySQL 缓存。
- sql 语句层:结果一样的情况下,采用效率高,速度快节省资源的 sql 语句执行。
★★★ 查询优化。
★★★ InnoDB 与 MyISAM 比较。
- 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句
- 并发:MyISAM 只支持表锁,而 InnoDB 还支持行级锁
- 外键:InnoDB 支持外键
- 备份:InnoDB 支持在线热备份
- 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢
- 其他特性:MyISAM 支持压缩表和空间数据索引
★★☆ 水平切分与垂直切分。
★★☆ 主从复制原理、作用、实现。
- 原理
- Master 主库将数据变更 DataChanges 记录 binlog 日志中
- Slave 起一个 I/O 线程连接到 Master,dump 读取 Master 的 binlog 日志并写入到 Slave 的中继日志 Relay log 中
- Slave 中的 SQL 线程读取中继日志 Relay log 进行 SQL 回放执行操作,完成主从复制,保证主从最终一致性
- 作用:可以实现读写分离,也可以在主库挂掉后从备用库中恢复,实时灾备的故障切换
★☆☆ redo、undo、binlog 日志的作用。
- redo log(重做日志)
- 确保事务的持久性,防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
- 内容:物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
- undo log(回滚日志)
- 保存了事务发生之前的数据的一个版本,可以用于回滚,同事可以提供多版本并发控制下的读
- 内容:逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
- binlog(二进制日志):
- 用于复制,在主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步
- 用于数据库的基于时间点的还原
- 内容:逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。但又不完全是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息,也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。
- redo log 和 binlog:
- 作用不同:redo log 是保证事务的持久性的,是事务层面的,binlog 作为还原的功能,是数据库层面的(当然也可以精确到事务层 面的),虽然都有还原的意思,但是其保护数据的层次是不一样的。
- 内容不同:redo log 是物理日志,是数据页面的修改之后的物理记录,binlog 是逻辑日志,可以简单认为记录的就是 sql 语句
- 另外,两者日志产生的时间,可以释放的时间,在可释放的情况下清理机制,都是完全不同的。
- 恢复数据时候的效率,基于物理日志的 redo log 恢复数据的效率要高于语句逻辑日志的 binlog
Redis
★★☆ 字典和跳跃表原理分析。
★★★ 使用场景。
- 计数器
- 缓存
- 查找表
- 消息队列
- 会话缓存
- 分布式锁实现
★★★ 与 Memchached 的比较。
- 数据类型:Memcached 仅支持字符串类型,而 Redis 支持五种不同的数据类型
- 数据持久化:Redis 支持两种持久化策略:RDB 快照和 AOF 日志,而 Memcached 不支持持久化
- 分布式:Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。Redis Cluster 实现了分布式的支持。
- 内存管理机制:
- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘,而 Memcached 的数据则会一直在内存中。
- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
★☆☆ 数据淘汰机制。
- 可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
- Reids 具体有 6 种淘汰策略。
- 使用 Redis 缓存数据时,为了提高缓存命中率,需要保证缓存数据都是热点数据。可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。
- Redis 4.0 引入了 volatile-lfu 和 allkeys-lfu 淘汰策略,LFU 策略通过统计访问频率,将访问频率最少的键值对淘汰。
★★☆ RDB 和 AOF 持久化机制。
- RDB:将某个时间点的所有数据放到硬盘上。可以将快照复制到其他服务器从而创建具有相同服务器副本如果系统发生故障,将会丢失最后一次创建快照直接后的数据。如果数据量很大,保存快照的时间会很长
- AOF:将写命令添加到 AOF 文件的末尾。使用 AOF 持久化需要设置同步选项,从而确保写命令什么时候会同步到磁盘文件上。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:
- always 每个命令都同步:会严重减低服务器的性能。
- everysec 每秒同步一次:这个选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Reids 每秒执行一次对同步服务器性能几乎没有任何影响。
- no 让操作系统来决定何时同步:并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。
- 随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
★★☆ 事件驱动模型。
★☆☆ 主从复制原理。
★★★ 集群与分布式。
★★☆ 事务原理。
★★★ 线程安全问题。
🎨面向对象
思想
★★★ 面向对象三大特性
- 封装
- 继承
- 多态
★☆☆ 设计原则
设计模式
★★☆ 设计模式的作用。
★★★ 手写单例模式,特别是双重检验锁以及静态内部类。
★★★ 手写工厂模式。
★★★ 理解 MVC,结合 SpringMVC 回答。
★★★ 理解代理模式,结合 Spring 中的 AOP 回答。
★★★ 分析 JDK 中常用的设计模式,例如装饰者模式、适配器模式、迭代器模式等。