协程服务器常问问题
1️⃣ 面经一 什么是协程(用户态线程,用户栈,用户态切换) 协程和线程相比有什么优势(轻量级、切换快、开销小,用户管理,配合非阻塞 IO 更好地实现异步并发) 更好地实现异步并发是怎么理解的(IO 操作时检测到需要等待缓冲时切换协程) 线程也可以在等待时切换,协程的优势是什么(用户自己操作) 轻量级怎么理解(线程的栈是 MB 级别的,协程的栈是 KB 级别的,线程在内核中切换,协程在用户态中切换) 怎么设置非阻塞(fctnl) 返回EAGAIN是什么意思(缓冲区没准备好) 互斥锁怎么实现的(访问锁时如果锁被占用就阻塞,加入阻塞队列,锁被释放时唤醒阻塞队列的中的线程进入就绪队列) http协议怎么解析的(引入了其他项目的解析器) http 是什么格式(消息行 消息头 消息体) N:M 的协程调度器是什么(N线程处理M协程) 如何调度(先来先服务,线程依次去协程队列取任务执行,如果没有任务就执行空闲协程,陷入epoll_wait,有任务时再唤醒空闲线程去执行任务) 如果所有线程都不空闲,其他协程是不是就不调度了...
IO 多路复用
1️⃣ 同步阻塞 IO造成的问题 两处阻塞: 1. 进程刚调用 recv ; 2. 等待内核将 数据 拷贝到 用户缓冲区 两处进程切换: 1. 连接持续没有数据到达; 2. 网卡将数据从 内核 复制到 socket 的 等待队列,进程会被唤醒 单对单连接:一个进程只能等待一条连接 2️⃣ 同步非阻塞 IO优点将数据从 网卡 拷贝到 socket 的内核空间 这一阶段变成 非阻塞模式。 用户进程调用 recvfrom() 会重复发出请求,检查数据是否到达 socket 的 等待队列。如果没有到,会立即返回。 缺点没有解决:当数据到达 socket 的 等待队列,用户进程需要将数据从 内核空间 拷贝到 用户空间。 3️⃣ 同步阻塞 IO 的数据接收流程 服务端使用系统调用 socket 会陷入到内核态,内核就会创建 socket 内核对象,其主要包含两个重要结构体: (进程)等待队列: 存放了进程的 进程描述符 和 回调函数。 (数据)接收队列: 存放了网卡接收到的需要该 socket 的数据 服务端当通过 socket 调用 recv 函数时,会执行...
零拷贝
1️⃣ 传统 I/O 过程在没有 DMA 技术之前,I/O 过程如下所述 (以 read 举例): 用户执行系统调用 read:将控制权从 用户态 转换到 内核态,此时进程阻塞在这里。 CPU 向磁盘发送 I/O 请求:磁盘接收到 I/O 请求后,就需要的数据填充到自己的磁盘缓冲区,然后产生中断信号。 磁盘向 CPU 发送 I/O 中断信号: CPU 先就把磁盘缓冲区的数据一次一个字节的读进到自己的 寄存器。 再把 寄存器的数据 写入到 内存 中,但是传输过程中 CPU 无法执行其他任务。 系统调用 read 返回:将控制权从 内核态 转换到 用户态。 2️⃣ DMA 技术定义: 在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。 用户执行系统调用 read:将控制权从 用户态 转换到 内核态,此时进程还是会阻塞在这里。 CPU 向 DMA 发送 I/O 请求:此时 CPU 就可以执行其他任务,搬运工作就交给 DMA。 DMA...
进程虚拟内存管理
1️⃣ 进程的虚拟地址空间 2️⃣ 内核如何管理进程?内核通过 task_strcut 来对进程进行管理 因为在进程描述符 task_struct 结构中,有一个专门描述 进程虚拟地址空间 的内存描述符 mm_struct。由于每个进程都有唯一的 mm_struct 结构体,因此每个进程的虚拟地址空间都是 独立的。 12345678910struct task_struct { // 进程id pid_t pid; // 用于标识线程所属的进程 pid pid_t tgid; // 用于标识线程所属的进程 pid pid_t tgid; // 内存描述符表示进程虚拟地址空间 struct mm_struct *mm;}; 子进程是如何被创建的? 调用 fork() 函数创建进程的时候, 子进程地址空间 的 mm_struct 结构会随着子进程描述符 task_struct 的创建而创建。 copy_process 函数中创建 task_struct...
wxg
1️⃣ Linux 是怎么实现并发的?有了进程和线程就可以实现并发了吗?第一层:任务抽象Linux 把 程序执行流 抽象成 “任务”,常见表现为: 进程: 资源分配的基本单位,拥有独立地址空间 线程: CPU 调度的基本单位,同一进程内线程共享地址空间、文件描述符等资源 第二层:调度器Linux 通过 调度器 把 CPU 时间切给不同任务。 即使只有一个 CPU 核,也可以通过 时间片轮转 + 上下文切换,让多个任务 “看起来同时在运行”,这叫 并发。 第三层:中断与系统调用用户程序一旦发生: 时钟中断 缺页中断 系统调用CPU 会陷入内核,内核就有机会切换任务等。 第四层:阻塞/非阻塞 + 多路复用2️⃣ 单核 CPU 可以实现多线程吗? 单核 CPU 上只能做到:多线程并发,不能做到真正的并行。 3️⃣ 虚拟地址 虚拟地址 是程序看到的地址,不是物理内存条上的真实地址。 4️⃣ 程序的地址空间 .text 段 .rodata 段 .data 段 .bss 段 堆 heap 内存映射区 栈...
操作系统常问问题
虚拟内存1️⃣ 什么是虚拟地址?操作系统 为每个进程都分配了独立的 虚拟地址。并且,操作系统提供一种机制,将不同进程的虚拟地址和不同的物理内存地址映射起来。如果程序要访问虚拟地址,就由操作系统转换成不同的物理内存地址。 之后,进程持有的虚拟内存地址会通过 CPU 芯片中的 MMU 的映射关系,将其转换成物理内存地址。 作用: 虚拟内存可以使得进程对运行内存超过物理内存大小: 因为程序运行符合局部性原理,CPU 访问内存会有很明显的重复访问的倾向性 对于那些没有被经常使用到的内存,我们可以把它换出到物理内存之外,比如硬盘上的 swap 区域。 由于每个进程都有自己的页表,所以每个进程的虚拟内存空间就是相互独立的 页表里的页表项中除了物理地址之外,还有对页的标志位 2️⃣ 操作系统是如何管理虚拟地址与物理地址之间的关系?主要有两种方式,分别是 内存分段 和 内存分页 3️⃣ 分段机制下,虚拟地址和物理地址是如何映射的?分段机制下的虚拟地址由两部分组成,段选择因子 和 段内偏移量。 段选择因子 最重要的就是 段号,用作 段表 的索引。其中 段表 保存了 段的基地址 以及...
数据库常问问题
1️⃣ 索引1️⃣ 什么是索引? 索引的定义就是 帮助存储引擎快速获取数据的一种数据结构 2️⃣ 索引的种类我们可以按照 四个角度 来分类索引。 按 「数据结构」 分类:B+tree 索引、Hash 索引、Full-text 索引。 按 「物理存储」 分类:聚簇索引(主键索引)、二级索引(辅助索引)。 按 「字段特性」 分类:主键索引、唯一索引、普通索引、前缀索引。 按 「字段个数」 分类:单列索引、联合索引。 3️⃣ 联合索引的最左匹配原则 按照 最左优先 的方式进行索引的匹配。如果不遵循「最左匹配原则」,联合索引会失效。 4️⃣ 索引下推 针对联合索引(a, b),在执行 select * from table where a > 1 and b = 2 语句的时候,只有 a 字段能用到索引。 那在联合索引的 B+Tree 已经找到第一个满足条件的主键值(ID 为 2)后,还需要判断其他条件是否满足(看 b 是否等于 2),那是在 联合索引里判断?还是回 主键索引去判断...
了解 Linux 防火墙
1️⃣ Netfilter提到 Linux 防火墙,很多人会先想到 iptables、nftables、firewalld、ufw,它们本质上都只是 用户态 的 配置工具。 真正负责 “拦包、改包、放行 /丢弃” 的核心,是 Linux 内核里的 Netfilter。 从上图可以看出:流量流动 是先从网卡,再到 linux 内核,最后抵达到网络应用。 流量过滤 指的是先让流量从网卡进来,然后在 linux 内核里进行过滤处理,最后进入网络应用。这样网络应用前面就有一道防火墙,防火墙就位于 linux 内核的实现中。 挂载点Netfilter 向 内核协议栈 中 不同的位置 注册 钩子函数 HOOK 来对数据包进行过滤或者修改操作,这些位置称为 挂载点。 Netlfilter 通常有 5 个 HOOK 点: PREROUTING:数据包进入路由表之前 INPUT:通过路由表后目的地为本机 FORWARD:通过路由表后,目的地不为本机 OUTPUT:由本机产生,向外发送 POSTROUTIONG:发送到网卡接口之前。 2️⃣ iptablesiptables...
