1 命名空间
不同服务的锁用不同的namespace来区分,不同元数据服务上锁namespace的名字不同,元数据锁和数据锁的namespace也不同,客户端理论上会向所有的服务发请求,所以客户端的锁分布在不同的namespace下,锁客户端用namespace来组织不同的锁链表.
分布式锁模块跟元数据服务器中其他模块比较独立,它保存了系统中所有已经向该元数据服务器申请的锁。当有新的锁请求到来时,会直接进入锁申请模块。锁模块会检查该资源上是否已经有锁,并检查锁是否存在冲突,以决定申请的锁是否会被授权。客户端上有专门的锁客户端缓存该客户端已经申请的分布式锁。
2 锁资源
锁资源,就是锁保护的对象。除了文件,还可以对象id等等。一个锁资源对应于一个实际的实体,比如一个文件、一段数据、一个数据库等等,锁资源的对象也决定锁粒度,比如你可以对整个inode加锁,也可以对inode中一个属性加锁,前者的粒度显然比后者粒度粗。
一个锁资源可以拥有多个锁持有它,但是一个锁只能被一个锁资源持有。因此在DLM中,锁资源和锁是1:M关系。
2.1 资源所属命名空间
2.2 锁状态
每个锁资源有三个潜在的锁状态:
- 已批准:锁请求成功获得其所要求的模式
- 转换中:client尝试改变的锁模式和新请求的模式与已存在的锁不兼容
- 阻塞的:由于冲突的锁已存在,新请求的锁无法被批准
锁的状态取决于它请求的锁模式和对应锁资源已存在的其他锁模式
对应三个链表对它们的状态进行归类:
批准链表: 已经准许在该资源上使用的所有锁
等待链表:正在请求该资源的所有锁
转换链表:处于转换状态的所有锁
2.3 转换状态机
已批准
锁被批准的条件(其中之一满足即可):
- 对应锁资源目前无锁持有者
- 请求的锁模式与最近已批准的锁兼容,且转化链表为空
转换中
锁转换即改变已持有锁的模式,只有批准锁可以转化,有两种转换方式:
up_conversion: a less restrictive to a more restrictive mode
down-conversion: a more restrictive to a less restrictive mode
锁管理器会将需要转换的lock从批准链表移动到转换链表的尾部。
离开转换中状态的条件(满足任一即可):
- 请求锁的线程终止
- 锁持有者取消转换请求
- 请求的模式最严格的批准锁匹配
锁管理者对down-conversion的请求执行本地转换,即无需将请求转移到转移中链表就可以直接转换成功
等待链表
如果请求的锁与最严格的批准锁不兼容,则锁被阻塞,锁请求会被添加到等待链表。
离开block状态的条件(满足任一即可):
- 请求锁的线程终止
- 锁请求者取消请求
- 锁请求与资源上最严格的锁兼容,并且在锁请求前面没有转换锁或者block锁
3 锁类型
元数据锁(比特锁)
索引节点比特锁,用来保护文件系统的元数据。元数据就是对关于数据的数据的总称,它可以分为很多种类。我们将元数据分为六类:
- 其中目录项被归为一类,对应索引节点比特锁的一个比特
INODELOCK_LOOKUP
; - 文件模式、所有者、组被归为一类,对应索引节点比特锁的
INODELOCK_PERM
; - 文件长度,引用数,时间戳被归为一类,对应
INODELOCK_UPDATE
比特; - 打开文件对应
INODELOCK_OPEN
比特; - 分条布局信息对应
INODELOCK_LAYOUT
比特; - 除ACL之外的扩展属性对应
INODELOCK_XATTR
。
这六个比特共同构成了索引比特锁的各个部分,也是它被称为索引比特锁的原因。相比于传统的平凡锁方式,这种细分方式有助于提高目录访问的并发度。客户端在要读取某文件的元数据信息时,会对该文件加上索引节点比特锁。
flock
flock锁为客户端提供flock和fcntl接口,协助用户空间请求文件锁。flock锁作为单独的命名空间,专门记录客户端申请的flock和fcntl锁。Flock锁也是对文件的某个范围上锁,这点与对象锁类似,但与之不同的是,flock锁请求会被发送到MDS而不是OSD
对象锁
对象锁保护文件系统对象的数据,客户端可以对不同的对象分别加锁,在同一对象中,只能支持一写多读的模式。系统中数据对象的大小是4M,文件超过4M后会创建一个新对象继续写入。同一文件的不同对象可以同时被写,即使这些对象属于同一文件。对象锁的resource id是对象oid。对象锁保护文件的数据,对对象加锁,对象锁服务器位于数据服务器上,每个数据服务器上的锁服务器负责该数据服务器上保存的主份对象的锁。
对象锁被用在三种情形下,一是在读写时,二是在计算文件大小时,三是在文件截断时。
- 在第一种情况下,在对文件的某个范围内的数据进行实际读写前,计算数据属于哪个对象,对该对象加锁。
- 第二种是获得文件size时,如果多个客户端在同时写一个文件的不同对象,文件size更新依赖于各对象写的汇总信息。
- 在第三种情况下,会计算文件截断后保留的size大小及要截断的对象,分别对对象加写锁。
意图锁
客户端在访问数据或者元数据资源时,需要先向锁服务器申请锁,然后再发送相应的请求。为了减少交互频率,在请求锁的同时将锁的意图数据发给锁服务器,如果请求的锁可以被授权,锁服务器根据客户端发的意图调用元数据服务注册的意图函数进行相应的操作,完成后把操作结果和锁一起返回给客户端。
数据的意图锁主要跟文件size更新有关,当系统中多个客户端同时在写同一文件的不同对象时,元数据服务上记录的文件size不准确,所以会发一个意图锁召回各对象上的数据锁,各对象收到锁召回请求后会上报各自的size以及modify time等相关信息,元数据服务汇总之后确定文件的相关属性。
4 锁模式
锁模式决定锁持有者是否与其他人共享锁资源的访问或者是否阻止其他人访问自身正在访问的资源。
锁模式说明
锁模式 | 请求进程 | 其他进程 | 说明 |
---|---|---|---|
EX | 读或写访问 | 不许访问 | 允许锁client安全的读取或者写锁资源,其他人在此期间不允许访问锁资源,EX是一种传统的独占锁 |
PW | 读或写访问 | 只允许读 | 允许锁client安全的读取或者写锁资源,其他人在此期间不允许写锁资源,PW锁是一种传统的更新锁 |
PR | 读访问 | 只允许读 | 允许锁client安全的读取锁资源,其他人在此期间不允许写锁资源,PR锁是一种传统的共享锁 |
CW | 读或写访问 | 读或写访问 | 允许没有保护的读或者写操作 |
CR | 读访问 | 读或写访问 | 允许没有保护的读操作,因为在CR锁持有者读取锁资源时,其他人可以读或者写对应的锁资源,因此CR锁的读操作是不受保护的 |
NL | 无请求 | 可以读或写访问 | 未授予所持有者任何权限,通常使用NL作为后续转换请求的占位符 |
限制级别(高-->低):
EX --> PW --> CW/PR --> CR --> NL
锁兼容性
锁兼容性决定两种锁是否可以同时被批准对同一个锁资源加锁,比如,EX锁不允许其他人访问对应的锁资源,它与除去NL之外的锁均不兼容,CR锁限制性较小,它与除了EX之外的所有其他锁均兼容,以下是兼容性二维矩阵
EX | PW | PR | CW | CR | NL | |
---|---|---|---|---|---|---|
EX | 0 | 0 | 0 | 0 | 0 | 1 |
PW | 0 | 0 | 0 | 0 | 1 | 1 |
PR | 0 | 0 | 1 | 0 | 1 | 1 |
CW | 0 | 0 | 0 | 1 | 1 | 1 |
CR | 0 | 1 | 1 | 1 | 1 | 1 |
NL | 1 | 1 | 1 | 1 | 1 | 1 |
它们的关系矩阵是一个对称矩阵,因此我们知道它们之间的兼容关系是对称关系。对于锁兼容关系的对称性,我们可以这样理解:如果A模式的锁与B模式的锁兼容,则意味着,如果某资源已被A模式的锁保护,则请求对该资源加上B模式的新锁会被批准;同时也意味着,如果资源已被B模式的锁保护,则请求对该资源加上A模式的新锁也会被批准;反之亦然。
系是对称关系。对于锁兼容关系的对称性,我们可以这样理解:如果A模式的锁与B模式的锁兼容,则意味着,如果某资源已被A模式的锁保护,则请求对该资源加上B模式的新锁会被批准;同时也意味着,如果资源已被B模式的锁保护,则请求对该资源加上A模式的新锁也会被批准;反之亦然。