Ceph RBD:exclusive-lock代码详解 + 使用方法

背景

exclusive-lock为rbd image的一个feature,是一个分布式锁,主要用于防止多个客户端同时写入image导致数据不一致问题。基本概念介绍见Ceph官方文档即可。

本文主要结论

  • exclusive-lock有两种policy
    • StandardPolicy:需要对接librbd的应用程序手动进行加锁、抢锁动作。
    • AutomaticPolicy:librbd客户端自动进行加锁、抢锁等动作。
  • exclusive-lock的时间是基于ceph osd的watcher/notify机制,每个rbd client注册一个watcher,某个client进行锁操作时通过watcher通知其他client锁的变化情况,其通知包括
    • RequestLockPayload:通知lock owner的client释放锁
    • AcquiredLockPayload:通知其他client,本client已经在本次争抢中拿到锁
    • ReleasedLockPayload:通知其他client,本client已经释放锁
  • 抢锁流程概述
    • 写IO在出队时抢锁
    • 查看锁的是否有其他client拿着,如果有,通知其释放锁,接收通知的client进行释放锁动作
    • 若其他client没有及时释放,进行重试
    • 其他client释放后,本client加锁
    • 加锁成功后,通知其他client加锁成功
  • exclusive-lock的使用
    • AutomaticPolicy
      • rbd_open拿到image的ctx,包括锁信息
      • rbd_aio_write写数据到image,并入队
        • 出队时所有客户端自动抢锁,公平争抢
        • 抢到后执行IO
    • StandardPolicy
      • rbd_open拿到image的ctx,包括锁信息
      • rbd_lock_break将lock owner强制break掉,其IO加入blacklist中
      • rbd_lock_acquire强制将AutomaticPolicy转换成StandardPolicy
      • rbd_aio_write写数据到image

加锁流程代码详解

下面以抢锁为例,结合代码实现进行介绍。

librbd::io::ImageRequestWQ: _void_dequeue // 在写IO出队时加锁,加锁前会判断是否时StandardPolicy,如果是则会重新入队,直到超时
	librbd::ManagedLock: acquire_lock // 此时会执行ACTION_ACQUIRE_LOCK
	librbd::ManagedLock: send_acquire_lock
	librbd::ExclusiveLock: pre_acquire_lock_handler 
		librbd::exclusive_lock::PreAcquireRequest: send_prepare_lock // 准备拿锁
		librbd::exclusive_lock::PreAcquireRequest: send_flush_notifies // 将通知写入watcher
	librbd::ManagedLock: handle_pre_acquire_lock
		librbd::managed_lock::AcquireRequest: send_get_locker 
			librbd::managed_lock::GetLockerRequest: send_get_lockers // 获取当前拿锁的client
		librbd::managed_lock::AcquireRequest: handle_get_locker
		librbd::managed_lock::AcquireRequest: send_lock // 第一次尝试拿锁,由于另外一个client拿着,所以失败
		librbd::managed_lock::AcquireRequest: send_break_lock // break拿锁client
			librbd::managed_lock::BreakRequest: send_get_watchers // 获取所有的watcher,并查看watcher是否还活着,如果还活着,那么break会失败
			librbd::managed_lock::BreakRequest: handle_get_watchers // 并查看watcher是否还活着,如果还活着,那么break会失败,若其他watcher已经无法连接了,则break成功
		librbd::managed_lock::AcquireRequest: handle_break_lock
	librbd::ManagedLock: handle_acquire_lock // 由于有其他client拿锁,此时加锁失败
	librbd::ExclusiveLock: post_acquire_lock_handler
	librbd::ManagedLock: is_lock_owner // 发现没有拿到锁,说明有活着的client拿锁
		librbd::ImageWatcher: notify request lock
			librbd::image_watcher::NotifyLockOwner: send_notify // 通知拿到锁的watcher,通知的类型为RequestLockPayload,其他客户端在handle_payload(const RequestLockPayload &payload, C_NotifyAck *ack_ctx)函数中处理。如果为AutomaticPolicy,被通知client就将当前IO放到blacklist中,并释放锁。如果为StandardPolicy,被通知的client则不会释放锁。
	librbd::ManagedLock: handle_post_acquire_lock
		librbd::ImageWatcher: exclusive lock requested
		librbd::ImageWatcher: handle_request_lock // 若没有拿到锁会进行重试
		librbd::ImageWatcher: schedule_request_lock // 进行重试
	librbd::ManagedLock: send_acquire_lock // 重新执行拿锁流程
	librbd::ExclusiveLock: pre_acquire_lock_handler 
		librbd::exclusive_lock::PreAcquireRequest: send_prepare_lock // 准备拿锁
		librbd::exclusive_lock::PreAcquireRequest: send_flush_notifies // 将通知写入watcher
	librbd::ManagedLock: handle_pre_acquire_lock
		librbd::managed_lock::AcquireRequest: send_get_locker 
			librbd::managed_lock::GetLockerRequest: send_get_lockers // 获取当前拿锁的client
		librbd::managed_lock::AcquireRequest: handle_get_locker // 此时会发现已经没有人拿锁了,因为前面的owner watcher接受到notify之后,主动释放了锁
		librbd::managed_lock::AcquireRequest: send_lock // 加锁,持久化header
	librbd::ManagedLock: handle_acquire_lock // 加锁成功
	librbd::ExclusiveLock: post_acquire_lock_handler // 进行加锁后处理
	librbd::ExclusiveLock: handle_post_acquiring_lock
	librbd::ExclusiveLock: handle_post_acquired_lock // 拿到锁之后进行处理
		librbd::ImageWatcher: notify acquired lock // 通知所有其他watcher,当前client已经拿到锁了,通知的类型为AcquiredLockPayload,其他client接收到通知后执行handle_payload(const watch_notify::AcquiredLockPayload& payload, C_NotifyAck *ctx)函数处理,这里其他client会取消到其加锁的请求,因为此次的抢锁没有抢到
		librbd::io::ImageRequestWQ: set_require_lock
		librbd::io::ImageRequestWQ: unblock_writes // 此client拿到锁之后,将waitqueue中的IO不进行阻塞
	librbd::ManagedLock: handle_post_acquire_lock
librbd::io::ImageRequestWQ: handle_acquire_lock // 加锁成功

如何使用exclusive-lock?

AutomaticPolicy

对于自动锁,参考前面的代码介绍可知,流程如下

  • rbd_open拿到image的ctx,包括锁信息
  • rbd_aio_write写数据到image,并入队
    • 出队时所有客户端自动抢锁,公平争抢
    • 抢到后执行IO

StandardPolicy

从前面代码介绍可知,通知lock owner释放锁时,如果是StandardPolicy则不会释放锁,那么StandardPolicy是如何产生的,又是怎么应用的呢?其流程如下

  • rbd_open拿到image的ctx,包括锁信息
  • rbd_lock_break将lock owner强制break掉,其IO加入blacklist中
  • rbd_lock_acquire强制将AutomaticPolicy转换成StandardPolicy
  • rbd_aio_write写数据到image

参考文献

https://docs.ceph.com/en/latest/rbd/rbd-exclusive-locks/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值