操作系统三大核心:虚拟性,并发,持久性
虚拟:
关键概念:引入进程
正在运行的c程序
想要构建的系统:
虚拟CPU(极短的CPU完成任务切换),安全问题引出受限制的系统,即内核与用户级,内核拥有全部资源trap table 进入内核等级的系统调用
虚拟化CPU考虑的问题,进程之间调度
1.切换线程:由系统完成切换 引出问题
如何完成切换?OS如何获得控制权?
CPU完成调度,切换是根据进程表,包含有进入地址(具体调度策略后面再讲),通过时钟中断(时间片是心脏),CPU如何保存进程信息,执行到那个指令和入口地址呢???关键点 保存和恢复上下文
调度策略
不说了
地址空间
核心:空闲空间管理以及快速地址转化
围绕了虚拟化内存保护系统,以及程序运行(无须指定加载和运行地址)。
并发
讲了进程和线程之间的通信与同步(以后再说,这个偏实践和用的)
持久性
NFS 文件系统
一、 核心思想:协议之上的虚拟文件系统
NFS 的本质是一个分布式文件系统协议。它的目标是让用户能够像访问本地文件一样,通过网络访问远程服务器上的文件,而对用户和应用程序来说,这个过程是透明的。
-
实现方式:
-
客户端: 在 Linux 内核中实现为一个虚拟文件系统 (VFS) 的客户端。当应用程序发起 open, read, write 等系统调用时,VFS 会判断目标路径是否为 NFS 挂载点。如果是,VFS 不会将操作传递给本地的磁盘驱动,而是将其转化为一系列 NFS RPC (远程过程调用) 请求。
-
服务端: 运行一个 NFS 服务进程,负责监听并处理来自客户端的 RPC 请求,执行真正的本地文件系统操作(如 ext4 的读写),然后将结果返回给客户端。
-
没有源码 没有图,只是基于目的 等等进行一个猜测 !!!!
look up协议
mount -t nfs -o vrer=3 nolock 192.168.6.12 :/home/book/nfs_rootfs /mnt
IP地址 192.168.6.12 |本地挂载点 | 本地挂载点 | 目标挂载点
返回文件句柄等
write协议[前提已经打开了文件]
客户 操作请求 | 文件句柄 | 操作内容
服务器 操作请求--> (open,write,close) message -->协议规定了如何操作
二、 关键基石:无状态协议
这是 NFS (尤其是 NFSv2/v3) 设计哲学的核心,也是它与许多其他网络协议的根本区别。
-
概念: 服务器不保留任何关于客户端连接状态的信息。服务器处理的每一个请求,都必须包含完成该操作所需的全部信息。
-
为什么无状态?: 为了健壮性 (Robustness)。
-
服务端崩溃恢复: 如果服务器突然崩溃重启,它不需要恢复任何连接状态。当客户端再次发送请求时,服务器可以像处理第一个请求一样处理它,因为所有信息都在请求里。
-
客户端崩溃无影响: 如果客户端崩溃,它没有在服务器上“占用”任何资源(比如打开的文件句柄)。服务器端不会因此产生任何资源泄漏。
-
三、 核心抽象:文件句柄 (File Handle)
既然服务器是无状态的,它不记录“哪个客户端打开了哪个文件”,那么客户端如何持续地对同一个文件进行操作呢?答案就是文件句柄。
-
概念: 文件句柄是服务器为文件系统中的每一个文件或目录生成的一个唯一的、持久的标识符。它就像是文件的“身份证号码”。
-
构成 (通常):
-
文件系统标识 (Filesystem ID): 区分服务器上不同的分区或文件系统。
-
Inode 号 (Inode Number): 文件在文件系统内的唯一编号。
-
世代号 (Generation Number): 一个随机数。当一个 Inode 号被重新使用时(例如,删除一个文件后,又创建了一个新文件恰好用了同一个 Inode 号),世代号会改变。
-
-
作用:
-
唯一标识: 文件系统ID + Inode号 + 世代号 的组合,可以在服务器的整个生命周期内唯一地标识一个文件,完美地解决了 Inode 复用带来的歧义问题。
-
替代状态: 客户端的每一个 read 或 write 请求,都会带上这个文件句柄,告诉服务器:“我要操作的是拥有这个‘身份证号’的文件”。服务器不需要记住你之前做过什么,只需要根据这个句柄去找到对应的文件即可。
-
四、 应对网络不可靠:操作的幂等性 (Idempotency)
网络是不可靠的,客户端发送一个请求后,可能因为网络超时而无法确定服务器是否已处理。
-
概念: 幂等性指一个操作无论执行一次还是执行多次,产生的结果都是相同的。
-
NFS 如何实现:
-
/ : 这些只读操作天然是幂等的。
-
WRITE: WRITE 请求中包含了文件句柄、固定的偏移地址 (offset) 和数据。客户端如果超时,可以无脑地重发同一个 WRITE 请求。因为每次写入的位置和内容都完全一样,即使服务器收到了两次,也只是把同一块数据在同一个位置覆盖了一遍,文件最终的状态是一致的。
-
非幂等操作: CREATE (创建文件) 和 REMOVE (删除文件) 不是幂等的。NFS 客户端需要更复杂的机制(如事务ID)来确保这类操作只被成功执行一次。
-
五、 提高性能:客户端缓冲 (Client-Side Caching)
无状态协议的每次操作都需要通过网络,效率低下。因此,客户端缓冲是提升 NFS 性能的关键手段。
-
机制:
-
写缓冲 (Write Caching): 当应用程序 write 数据时,NFS 客户端通常先把数据缓存在本地内存的“页缓存 (Page Cache)”中,并立即向上层应用返回成功。内核会在稍后的某个时刻(或缓冲区满时)将多个小的写操作合并成一个大的 WRITE RPC,一次性地发给服务器。
-
读缓冲 (Read Caching): 当应用程序 read 文件时,客户端会一次性从服务器读取一个较大的数据块(预读),并缓存在本地页缓存中。后续的 read 请求如果命中缓存,就可以直接从内存返回,无需网络交互。
-
六、 缓冲带来的挑战:数据一致性 (Cache Consistency)
缓冲极大地提升了性能,但也引入了经典的一致性问题:
-
场景:
-
客户端 A write 了一个文件,数据还停留在 A 的本地缓存中。
-
客户端 B 此时去 read 同一个文件,它会从服务器读到旧的数据,因为它不知道 A 已经做了修改。
-
-
解决方案 (以 NFSv3 为例):
-
关闭时刷新 : NFS 提供了一种弱一致性保证。当客户端 A 修改完文件并调用 时,NFS 客户端必须将所有写缓存刷新 (flush) 到服务器。当客户端 B 调用 打开该文件时,它会向服务器发起一个 GETATTR 请求,获取文件的最新属性(如修改时间)。
-
属性校验: 客户端 B 会比较自己缓存的文件的属性和从服务器获取的最新属性。如果发现不一致(比如修改时间变了),B 就会主动使其本地缓存失效 (invalidate),确保下一次 read 会去服务器重新拉取最新的数据。
-