当前位置: 首页 > 编程笔记 >

用Python实现一个Reids分布式锁的功能

夹谷腾
2023-05-12

一、Redis分布式锁的实现原理

通过setnx设置分布式锁,拿到这个锁的进程可以执行业务代码,没有拿到只能进行等待,进程执行完业务代码后需要通过del key 释放锁,让其他进程重新获取,这样就实现了在多进程并发的情况下始终只有一个进程在执行业务代码【在生产环境中通常需要对多进程同时写数据库的代码块加锁】


二、获得锁

通过调用redis底层命令 setnx来实现加锁(key,value),python 语言redis包封装了SETNX命令

setnx(key,value) 方法在key不存在的情况下,将key设置为value 返回True,若key存在则直接返回False

acquire_timeout 是客户端获取锁的结束时间,超过了acquire_timeout还没有获取到就会放弃获取

time_out 是key的过期时间,主要是为了防止进程崩溃导致其他线程无法获取锁


笔者通过以下Python代码,演示一下基于Python Redis客户端库实现的分布式锁:

import redis
import time

class RedisLock:
    def __init__(self, redis_client, key, expire=10):
        self.redis_client = redis_client
        self.key = key
        self.expire = expire
        self.value = None

    def __enter__(self):
        while True:
            # 尝试获取锁
            timestamp = time.time()
            self.value = str(timestamp)
            result = self.redis_client.set(self.key, self.value, ex=self.expire, nx=True)
            if result:
                return True
            else:
                # 未获取到锁,等待一段时间后重试
                time.sleep(0.1)

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 释放锁
        script = """
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        """
        self.redis_client.eval(script, 1, self.key, self.value)

if __name__ == '__main__':
    redis_client = redis.Redis(host='localhost', port=6379, db=0)
    with RedisLock(redis_client, 'mylock'):
        print('Get lock')
        time.sleep(5)
    print('Release lock')

在以上示例代码中,我们首先定义了一个RedisLock类,该类包含了获取锁和释放锁的逻辑,同时在__enter__方法中实现了自旋锁(spin lock)的逻辑,如果在一定的时间内未获取到锁,则会进行一次重试,这样可以减少对Redis的请求次数。在__exit__方法中实现了释放锁的逻辑,使用Redis Lua脚本来保证原子性。

1684203413672_用Python实现一个Redis分布式锁的功能.jpg

同时,我们使用Redis默认的0号数据库,并在本地运行的Redis服务器上测试了代码。我们首先获取锁并打印Get lock信息,然后等待5秒钟,最后释放锁并打印Release lock信息。

注意:在实际应用中,我们需要在获取到锁后执行一些临界区代码,并在临界区代码执行完毕后释放锁。同时,需要考虑到锁的超时问题,防止因为某个线程崩溃导致锁一直被占用。

 类似资料:
  • 背景 在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等。大部分的解决方案是基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制。 一、使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以

  • 使用Redis实现分布式锁 redis命令:set users 10 nx ex 12   原子性命令 //使用uuid,解决锁释放的问题 @GetMapping public void testLock() throws InterruptedException { String uuid = UUID.randomUUID().toString(); Boolean b_loc

  • 本文向大家介绍Zookeeper 如何实现分布式锁?相关面试题,主要包含被问及Zookeeper 如何实现分布式锁?时的应答技巧和注意事项,需要的朋友参考一下 分布式锁的实现方式有很多种,比如 、数据库 、 等。个人认为 在实现分布式锁这方面是非常非常简单的。 上面我们已经提到过了 zk在高并发的情况下保证节点创建的全局唯一性,这玩意一看就知道能干啥了。实现互斥锁呗,又因为能在分布式的情况下,所以

  • 本文向大家介绍Redis 怎么实现分布式锁?相关面试题,主要包含被问及Redis 怎么实现分布式锁?时的应答技巧和注意事项,需要的朋友参考一下 Redis 分布式锁其实就是在系统里面占一个“坑”,其他程序也要占“坑”的时候,占用成功了就可以继续执行,失败了就只能放弃或稍后重试。 占坑一般使用 setnx(set if not exists)指令,只允许被一个程序占有,使用完调用 del 释放锁。

  • 主要内容:实例分布式锁是控制分布式系统之间同步访问共享资源的一种方式。 下面介绍 zookeeper 如何实现分布式锁,讲解排他锁和共享锁两类分布式锁。 排他锁 排他锁(Exclusive Locks),又被称为写锁或独占锁,如果事务T1对数据对象O1加上排他锁,那么整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能进行读或写。 定义锁: 实现方式: 利用 zookeeper 的同级节点的

  • 本文向大家介绍实现一个页面锁屏的功能相关面试题,主要包含被问及实现一个页面锁屏的功能时的应答技巧和注意事项,需要的朋友参考一下 <!DOCTYPE html> <html> <head> <title>Ctrl+l监控锁屏</title> </head> <body> <div id="message_div"></div> <script type="text/javascript" langu

  • 本文向大家介绍Java使用Redisson分布式锁实现原理,包括了Java使用Redisson分布式锁实现原理的使用技巧和注意事项,需要的朋友参考一下 1. 基本用法 针对上面这段代码,重点看一下Redisson是如何基于Redis实现分布式锁的 Redisson中提供的加锁的方法有很多,但大致类似,此处只看lock()方法 更多请参见https://github.com/redisson/red

  • 本文向大家介绍Docker实现分布式应用功能教程,包括了Docker实现分布式应用功能教程的使用技巧和注意事项,需要的朋友参考一下 本文详细讲述了Docker实现分布式应用功能。分享给大家供大家参考,具体如下: 这里接着前面一篇《Docker简单安装与应用入门教程》后面扩展应用程序。实现负载平衡,要做到这一点,必须在分布式应用程序的层次结构中的服务层实现。 在分布式应用程序中,应用程序的不同部分被