openstack 锁的使用及其原理
来源:互联网 发布:会计事务所做帐软件 编辑:程序博客网 时间:2024/06/03 23:05
1 锁使用场景
compute 服务使用协程锁
@utils.synchronized(instance['uuid'])def _sync_refresh(): xxxxxxx
下载镜像,使用线程锁 external=True
@utils.synchronized(filename, external=True, lock_path=self.lock_path)def call_if_not_exists(target, *args, **kwargs): if not os.path.exists(target): fetch_func(target=target, *args, **kwargs)
2 锁的类型
• 协程锁: semaphore.Semaphore() 实现• 进程锁: Nova 在 semaphore.Semaphore() 基础之上自身实现的跨进程的文件锁
external关键字参数标示加锁类型。
3 锁原理
3.1 进程锁
python 中给文件加锁——fcntl模块
3.1.1 简单示例:
import fcntl
锁的时机:
打开一个文件f = open('./test') ##当前目录下test文件要先存在,如果不存在会报错。
加锁:
fcntl.flock(f,fcntl.LOCK_EX)
这样就对文件test加锁了,如果有其他进程对test文件加锁,则不能成功,会被阻塞,但不会退出程序。
解锁:
fcntl.flock(f,fcntl.LOCK_UN)
3.1.2 fcntl模块提供方法
LOCK_NB可以同LOCK_SH或LOCK_NB进行按位或(|)运算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB),我们在 nova 中的就是这种加锁方式。如果一个方法已经被加锁,另一个线程获得这个锁时,抛出异常返回,下面是一个循环等待加锁的例子:
while True: try: fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB) break except IOError as e: # raise on unrelated IOErrors if e.errno != errno.EAGAIN: raise else: time.sleep(0.1)
try 尝试加锁,如果检测到有锁,抛出异常,except 捕获后,进入下一个循环尝试获得锁。
文件所高级使用方式:with语句对 线程锁进行的包装,加锁方式如下:
with lock: retval = f(*args, **kwargs)
lock中含有两个方法:
enter 加锁,
exit进行解锁
def __enter__(self): self.lockfile = open(self.fname, 'w') while True: try: self.trylock() return self except IOError, e: if e.errno in (errno.EACCES, errno.EAGAIN): time.sleep(0.01) else: raise def __exit__(self, exc_type, exc_val, exc_tb): try: self.unlock() self.lockfile.close() except IOError: LOG.exception(_("Could not release the acquired lock `%s`") % self.fname)
3.2 协程锁
使用 协程提供的 Semaphore 类,与其它Semaphore 锁类似,Semaphore锁可以进行流控制,但是nova这里只是用了信号量为1 的锁。信号量为1 表示同时只有一个进程可以获得锁,
假设有两个协程A B,其抢占锁过程如下:
- A 获得锁,Semaphore 对象中变量 counter(初始值为1)减一为0;
- B 尝试获得锁,counter 为零,把B加入到 waiters队列中;
- A 释放锁,counter +1 , counter为1,B 的acquire 方法立即获得锁;
- A 释放所,同时把B 从waiters 队列中取出,立即唤醒;
- B 执行自己方法;
加锁的整个过程,B 获得锁时,使用 hubs.get_hub().switch() 方法,把执行机会让给其他线程。
当B 从waiters 队列中取出时,B 可能处于睡眠状态,使用 switch()方法,把B唤醒并执行。
hubs.get_hub().switch() 执行的是协程的切换,b 的switch() 方法唤醒本身。
参考:http://eventlet.net/doc/modules/semaphore.html
以上,是协程锁的原理。
其加锁方式,和线程锁类似,使用with 进行封装。
4 nova使用
openstack nova 使用with语句,对上锁,解锁进行封装,两种锁,嵌套使用,简化如下:
sem = _semaphores.get(name, semaphore.Semaphore())with sem: if external and not FLAGS.disable_process_locking: lock = InterProcessLock(lock_file_path) with lock: funtion()
以上:
1 尝试使用eventlet 提供的 semaphore 对像,实现协程之间的加锁。
2 在协程锁的基础上,如果传入参数中含有external 这个关键字,此时标识:线程之间不能同时访问锁
nova 在使用with封装的基础上,又使用装饰器,对使用方式进行进一步的转化,最终我们使用@utils.synchronized()的方式即可对方法进行加锁。
5 锁使用
@utils.synchronized() 方式使用锁,锁住的是一个方法。当我们向在一个方法中对一个逻辑进行加锁,我们可以可以把这个逻辑提取成一个方法,然后把这个方法使用@utils.synchronized() 进行装饰。
def run_instance(self): @utils.synchronized(instance['uuid']) def do_run_instance(): xxxx do_run_instance()
- openstack 锁的使用及其原理
- 继电器的使用及其原理
- ThreaLocal的使用及其原理
- volatile的原理及其使用
- 代理的使用及其实现原理
- (一)CocoaPods的使用及其原理
- 详述ROWID的原理及其使用
- 文件锁使用原理及其方法
- lbp原理及其使用
- Converter使用及其原理
- OpenStack 中 RabbitMQ 的原理
- 【OpenStack】Nova目前的filter及其功能
- OpenStack-Nova目前的filter及其功能
- 【OpenStack】Nova目前的filter及其功能
- openstack 工作流workflows使用原理讲解
- openstack 工作流workflows使用原理讲解
- openstack 工作流 workflows使用原理讲解
- Linux操作系统的打印原理及其命令的使用
- RecycleView之 DiffUtil的使用
- jQuery
- 数据结构与算法之Josephus问题(用Java解决)
- 奇数序列运算式
- 区块链开发(二)部署和运行第一个以太坊智能合约
- openstack 锁的使用及其原理
- PopupMenu和PopupWindow
- 小记前端 URL 传参 中文乱码
- cdev设备驱动的使用
- 区块链开发(三)编写调试第一个以太坊智能合约
- 屏蔽非法字符
- dubbox新特性介绍
- 【JAVA】10.流程控制语句
- jQuery中 hide和fadeOut的区别 show和fadeIn的区别