两种算法
SanLock的实现基于两种算法,这两种算法都是在多个节点可以同时访问的共享存储(iSCSI、FCoE等)、或者分布式文件系统(NFS、GlusterFS)上建立的。
Light-Weight Leases
向一个数据块中写入一个数据,然后等待一段时间,如果发现没有被改变,则获取该数据块的所有权。该算法很简单,空间占用小,但是速度慢。
Disk Paxos
是Paxos算法在存储上的变种,每个节点占用一个数据块,可以写自己的数据块,但只能读其他节点的数据块。当需要获取所有权时,向自己的数据块写入提案号和提案者唯一ID,然后读取其他节点的数据块并进行冲突检测,如果没有冲突则成功。该算法相对复杂,空间占用大,但是速度快。
两种对象
使用者必须首先加入一个Lockspace,然后再请求或释放Resources。
Lockspace
- 使用Light-Weight Leases算法实现Delta Leases租约,当sanlock获取一个Delta Leases后,会定时(默认为20秒)使用自己的CPU时间更新其时间戳。
- 每个Lockspace由多个Delta Leases租约实现,默认有2000个,每个512字节,总共1M。
- 一个Lockspace最多支持2000个节点,每个节点使用不同的Delta Leases,使用从1到2000的序号标识。
- 一个Lockspace代表一个集群,每个Delta Leases代表一个节点,使用其序号标识节点的Host ID。
- 节点使用唯一的主机名,通过Lockspace获取其节点的Host ID,如果没有指定主机名,则sanlock会自动生成一个UUID来替代(每次重新获取时,这个UUID会变)。
- 一个Delta Leases保证Lockspace中的Host ID只能被一个节点使用。
- 当一个节点获取Delta Leases成功后,就相当于加入到这个Lockspace(集群)中,然后就可以使用与之关联的Resources了。
- 因为使用的是“等待”和“观察”算法,检测Delta Leases的冲突是非常耗时的。如果多个节点竞争同一个Delta Leases,延迟会继续增加。
Resources
- 使用Disk Paxos算法实现Paxos Leases租约,使用一个Paxos Leases租约实现一个Resources。
- Resources必须以Lockspace为加锁解锁的上下文环境,因此每个Resources必须属于一个Lockspace。
- 一个Resources至少占用1M空间,包含唯一的Resource名字和所属的Lockspace。
- 在一个Resources中,每个节点有一个扇区(默认512字节)空间可以写自己的投票,也可以读取其他节点的投票情况。
- 每个Resources的第一个扇区被称为“Leader Record”,其中包含最后一次投票的结果,每次竞争的获胜者把投票结果写进“Leader Record”(获胜者也可以把其他竞争者选为所有者)。
- 当获胜者被选出后,对这个Resources所在的磁盘区域就不需要任何的IO操作了。
- 当释放Resources时,只需清除“Leader Recorder”中的当前所有者既可。
- sanlock不会定时更新Paxos Leases的租约,是否过期主要看其所属的Lockspace的时间戳,以减少磁盘读写量。
- 当获得Resources所有权的节点失效时,Resources中的所有者依旧指向这个失效节点。当其他节点试图获取其所有权时,发现他已经由所有者了,然后就根据其Host ID检查其所属Lockspace的对应Delta Leases是否过时。如果未过时,则所有者不变;如果过时,则获取这个Resources的所有权。
- 两个节点之间的交互仅限于试图获取相同的Resources时,或者检查对方的Delta Leases是否超的时候,除此之外相互之间没有任何相互影响。
- 使用者必须自己记住Lockspace和Resources租约的位置,sanlock不会保存其位置。
过期与失效
每个节点的sanlock守护进程会定期更新本节点已获得Host ID的Lockspace中的时间戳,以确保自己是该Host ID的唯一所有者。
-
当获取Host ID的节点无法正常更新其时间戳时,将会失去对应资源的访问权,所拥有的Host ID就会因超时而过期,其他节点就可以获取其Host ID以及所属的Resources。
-
当一个节点的sanlock无法周期更新自己Host ID的时间戳时,应主动停止所有使用与该Lockspace有关联的Resources的进程,同时sanlock会进入“Recovery Mode”,以防止与其他节点访问冲突。
-
当一个进程崩溃或退出时没有释放自己已获取所有权的Resources,sanlock会自动(sanlock会收到终止进程的套接字POLLIN和POLLHUP事件)释放其所有权(使用持久化的Resources租约除外,这个我没研究过怎么用以及如何实现)。
-
如果sanlock崩溃,且使用了看门狗,系统会由于没有喂狗而被看门狗复位。
问题思考:
1. 假设节点X获取了某个Locspace的Host ID为1,资源A,此时资源A属于Host ID 1。
2. 当节点X失效后,另外一个节点Y获取其Host ID 1成功,但并没有去试图获取资源A的所有权。
3. 此时资源A所属的Host ID依旧为1,而实际上并没有节点拥有该资源的所有权。
4. 这时节点Z使用Host ID 2获取资源A,然后通过其所属的Host ID为1,没有失效,因此获取所有权失败。
5. 所有节点都将无法获得资源A的所有权,会陷入死锁。
规避方法:
所有节点都永远不要使用相同的Host ID(至少在一个同一个Lockspac中不要有多个节点竞争相同的Host ID)。
失效处理:
- 正常终止(Graceful Shutdown) - sanlock会通知其他进程处理此种情况,如果在规定时间(-g选项设置)没有处理或者终止,则会使用SIGTERM信号强制其退出。
- 强制终止(Forced Shutdown) - 如果进程在规定时间没有处理或者终止,使用SIGKILL信号强制终止。
- 主机复位(Host Reset) - 在以上两种情况都失败时,sanlock会停止喂狗,由看门狗复位主机。
也可以通过设置force_mode和killpath参数来修改处理方式。
看门狗与隔离
被动隔离
- sanlock通过wdmd服务间接访问/dev/watchdog设备,实现一个硬件(软件)设备的复用。
- Watchdog可以使用专用硬件,也可以使用软件实现的softdog,但软件实现的效果会差一些。
- 当sanlock出现异常或因为某个Lockspace超时而停止喂狗时,系统就会复位,防止脑裂。
主动隔离
sanlock中使用fence_sanlock功能实现主动隔离。为每个节点创建一个Resources租约,fence_sanlock获取该节点所属Resources的所有权。如果其他节点获取该Resources,则会被该节点发现,然后主动停止向wdmd喂狗,最后被看门狗复位。