概述
很久之前对nfs4.0 rfc文档分析的笔记,笔记不是很完善,后来工作变化了也懒得补充了。
共享出来供大家分享吧,有些地方的理解可能会有偏差。
以后阅读rfc的时候还是把原文翻一下比较好,笔记的方式容易引起误解,别人看了不方便考证。
参考资料标准的rfc文档:rfc3530
NFSV4
1. V4变化
1.1. operation的变化
V4的RPC的Procedure number只有null和compound两个,compound procedure由多个operation组成;例如open、setattr和read 可以组成一个compound procedure。一个RPC消息中可以做多个操作。Server对一个Compound RPC请求中的多个operation顺序执行,遇到一个错误,后面的operation不再执行,server直接返回前面所有的结果给Client;
通过compound组合的方式,可以有效减少RPC调用的次数。
NFS3的操作中,filehandle一般是做为operation的显示式入参;NFS4中,filehandle不再作为显示入参,而是作为一个隐式入参,类似shell中的环境变量。
作为环境变量的filehandle有两个:Current filehandle和Saved filehanle。如果一个operation只涉及到一个文件(例如open、lock),那么只会用到Current filehandle;
如果涉及两个文件(例如link),就会用到Current filehandle+Savedfilehanle。
Currentfilehandle一般是隐式变化的。例如lookup操作之前current filehanle应该是当前目录的filehandle,如果lookup操作成功,那么current filehandle就变为lookup操作所查找的文件的filehandle。NFS4也提供专门的操作用来查询和修改current fd和saved fd,例如GETFH(查询current fd)和SETFH(设置current fd)、SAVEDFH(将saved fd设置为current fd)、RESTOREFH(将current fd设置为saved fd)。
1.2. file handle的变化
不再需要额外的mount协议。client通过PUTROOTFD的操作,将root fd设置为current fd,后面client只需要进行lookup操作,就可以遍历整个文件树。
2. 锁和共享保护
2.1. 基本操作
4.0中增加了share reservation的概念。这个概念是针对windows API的文件接口引入的。
Windows API中CreateFile(即打开文件)时必须制定文件的share mode,即deny other:none,read,write,both。Posix语义跟windows不同, open file的时候不需要关心是否上锁。
通过SetClientID、setClientID_Conform操作,client跟server之间协商clientID。
Lock_owner包括clientID+threadid
StateID是lock_owner的缩写,由server产生,server负责维护lock_owner与stateID的对应关系。
Linux NFS4 实现:stateid由ownerid+fileid+时间戳组成
seqID for lock:由于RPC可能基于不可靠的UDP协议,NFSclient可能多次调用rpc发送同一个消息;即使基于tcp的rpc,也可能存在多个tcp链路,同一个lock-owner的rpc消息可能并行发送。因此,对于涉及状态的rpc消息(open closelock locku等),每个operation都增加一个流水号即seqid。同一个lockowner的seqid从0开始。
open_conform 用来确认open请求,用于open_owner第一次打开文件。
2.2. 锁的粒度
Nfs4 支持字节级别的锁。
如果需要缩小锁的范围,可以通过unlock操作实现。当然server可以不支持这种细粒度的锁。锁的级别可通过lock操作降低或者提升,server也可以不支持。
阻塞锁:
增加了新的锁类型:READW和WRITEW
具体两种实现方式,采用哪种未明确:
1. server发现锁有冲突,立刻回复client失败,client收到失败结果后,只能向server poll方式再请求锁;
2. server发现有冲突的锁,并不立刻返回client消息,而是等释放了冲突的锁之后,回复client lock 请求成功。
2.3. 租约
租约主要是为了防止发生重启或者网络中断的客户端,长时间占有锁,并不是为了缓存一致性。
NFS提供专门针对租约的操作 :renew(租约更新,即续租)。对于sever来说,一个client具有一个租约,而不是一个state具有一个租约。
出于性能的考虑,client任何一个涉及到stateid的操作,例如lock locku open close readwrite等,都相当于进行一次隐式的租约renew,避免client经常要发送renew消息带来的消耗。如果open时候stateid字段为空(即不对文件进行共享保护),那么这种open或者close或者后面的read write不会renew 租约。
租约时间nfs4代码中固定的是60s。
2.4. Crash Recovery
如果client崩溃,重启后,client会重新向server申请自己的clientID。Client向server发送的SetClientID消息的clientID结构中有一个verifier字段,该字段client每次启动都会赋新值,因此server可以根据该字段发现client是否重启过。如果server发现client重启,则释放原client申请的全部锁。
Client通过server返回几类错误码来发现server重启,例如clientID陈旧,stateID陈旧等。Server重启后,进入一个所谓的grace period。grace period的时长等于lease time。友好期主要目的是给客户端时间来恢复server重启前client的锁的状态。友好期内,client通过lock操作的reclaim字段或者open操作的claimtype字段来表示自己本次锁操作是恢复原来的锁状态。友好期内,Server的处理分两种情况:
1. server将锁的状态存在持久化存储中,server可以知道重启前文件是否上锁,锁的拥有者是谁,因此也可以判断非回收锁是否跟回收锁有冲突,允许无冲突的非回收锁操作或读写操作。
2. server没有持久化存储,无法判断非回收锁是否引起冲突,因此简单的拒绝一切非回收锁操作和读写操作。
对于回收锁的处理,有两种特殊的边界情况,第一种:
1. clientA申请锁之后跟server网络发生中断,一直无法renew锁的租约。
2. server在clientA的租约超期后把付给了clientB,B又释放了锁。
3. server发生重启,A跟server的链路通了,A去server申请回收锁。
第二种:
1. client A申请锁,之后server重启
2. server重启后由于A与server断链,一直无法申请回收锁
3. A的锁被server释放,Client B又向server申请了锁,成功后B释放锁
4. Server重启后,A跟server链路通,A重新向server申请回收锁。
这两种情况下,server都不应该答应A申请回收锁的请求。简单的做法是让server拒绝一切回收锁的请求。另一种做法是server需要在持久化存储中记录一些信息,以判断上述情况是否发生,包括:
a. Client lease是否超期
b. Client 时间戳,该时间戳在server启动后,client第一次申请锁、共享保护或客户端代理时被更新,后面 server再次重启这个时间戳不会被更新。
c. Server时间戳,记录最近两次server启动的时间。
有了上面的值,server就可以判断出申请回收锁的client的租约是否超期,是否是server上次启动前申请的锁。如果是,都将拒绝client申请。
2.5. Lock请求的超时处理
如果client一直没有收到lock请求的响应消息,client可能放弃重新尝试。但是,同一个lock-owner下一次申请另一个锁操作之前,必须同步上一次lock的状态。同步的方法就是lock-owner将最近一次未收到响应的lock请求从cache中取出,重新发送给server。当然,重新发送的lock请求的seqid是不变的。
2.6. 锁的召回
分三种情况:
1. server重启
2. 租约到期是client没能及时renew
3. server的管理员人为强制收回某个锁
2.7. close
close前是否需要释放所有的锁,跟server的实现有关系。有些server需要client主动释放所有锁之后才能close,有些server允许client直接发送close消息。
对于close消息的重传,server有两种方式处理:
1. 简单的回复close成功,自己打一个错误日志。
2. 每次收到close时候并不释放state,而是只是将state标记为pending-close,直到clientID或者seqID被释放。这样server就可以判断close消息是否重发。
3. 客户端缓存
NFS4.0并不提供一种分布式缓存一致性的机制,仅仅定义一种有限的客户端cache保护机制,使得锁与共享保护机制与客户端缓存机制能够共存。
3.1. 委托(delegation)和回调(callback)
Delegation涉及三个方面:client,server,file。某个文件的open_owner打开文件时,可以申请delegation。授权分类型。Client取到某个file的delegation之后,该client上对该文件的访问(在授权范围内)都由client来做判断。Server如果发现其他client请求访问该文件,且访问模式跟server对取到delegation的client的委托类型有冲突,那么server需要召回delegation。Server召回delegation通过callback rpc实现。Callback rpc可能受防火墙的影响无法执行,所以server在将delegation赋予一个client之前,需要用一个空的rpc callback操作来测试下callback rpc是否可行。
每个delegation也具有一个stateid,也具有一个lease(租期)。
委托召回时,client需要将本地缓存的数据、元数据全部刷新到server之后才能回复server委托召回成功。Server需要设定一个委托召回的超时时间,如果时间间隔内没收到client的回复,则认为委托失效。
3.2. Cache与lock
客户端申请锁之前,必须将锁对应的file region的cache 重新生效。如果client发现change字段为真,则需要flush该缓存,或者释放掉缓存块。客户端释放写锁之前,必须将cache全部flush到server。
客户端对于cache的管理可能是基于内存页。但是同一个页内的字节可能属于两个不同的锁的范围。因此客户端的cache刷新需要以字节为单位而不是以页为单位。
客户端在读写时,如果发现读写的范围内具有相应的锁类型,客户端可以直接在本地cache操作,后面在flush到server。如果没有锁,则不能使用cache。
3.3. Cache一致性和文件ID
NFS4中,FileHandle是根据pathname生成的,不同的filehandle可能指向同一个文件。以下原则可以用来区分不同的FileHandle是否同一个文件:
1. File attribute里面的fsid属性不同,则肯定不是同一个文件。
2. 文件属性里的unique_handles为true,则不同的filehandle肯定是不同的文件。
3. 文件属性里的fileid字段不同,则不同的filehandle肯定是不同的文件。
3.4. Open delegation
客户端向server申请授权时,server从以下几个方面考虑是否允许授权:
1. 客户端的状态时良好的,可以执行callback rpc,上次对该客户端的授权可以成功收回。
2. 一致性判断:当前该文件所有的open mode跟授权类型不冲突,所有的授权状态跟本次申请的授权类型也不冲突。
3. 基于性能的考虑:从最近的访问历史看授权冲突的可能性较低。
授权的类型:读授权和写授权。读授权可以多个同时存在。同一个文件,同一时刻,写授权只能存在一个,且不允许读授权存在。授权也具有一个stateid,授权的stateid跟open的stateid互相独立。当授权被召回,授权的stateid无效时,同一个文件上file lock的stateid仍然有效。
Server决定授予client delegation,那么server对于open的result中不能要求client对本次open做confirm。如果要求confirm,那么对于协议本身过于复杂,因为如果server要求client对delegation做confirm的话,server后面还要判断client的对应confirm消息是否超时了,这样就太复杂了。索性server认为只要对open的结果中包含了delegation,那么这次授权就成功了。
最后
以上就是沉静皮卡丘为你收集整理的NFSv 4.0 的变化1. V4变化1.1. operation的变化1.2. file handle的变化2. 锁和共享保护2.1. 基本操作2.2. 锁的粒度2.3. 租约2.4. Crash Recovery2.5. Lock请求的超时处理2.6. 锁的召回2.7. close 3. 客户端缓存3.1. 委托(delegation)和回调(callback)3.2. Cache与lock3.3的全部内容,希望文章能够帮你解决NFSv 4.0 的变化1. V4变化1.1. operation的变化1.2. file handle的变化2. 锁和共享保护2.1. 基本操作2.2. 锁的粒度2.3. 租约2.4. Crash Recovery2.5. Lock请求的超时处理2.6. 锁的召回2.7. close 3. 客户端缓存3.1. 委托(delegation)和回调(callback)3.2. Cache与lock3.3所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复