redis(二十四):Redis分布式锁以及实现(python)
阅读目录
- 什么事分布式锁
- 基于redis实现分布式锁
一、什么是分布式锁
我们在开发应用的时候,如果需要对某一个共享变量进行多线程同步访问的时候,可以使用我们学到的锁进行处理,并且可以完美的运行,毫无Bug!
注意这是单机应用,后来业务发展,需要做集群,一个应用需要部署到几台机器上然后做负载均衡,大致如下图:

上图可以看到,变量A存在三个服务器内存中(这个变量A主要体现是在一个类中的一个成员变量,是一个有状态的对象),如果不加任何控制的话,变量A同时都会在分配一块内存,三个请求发过来同时对这个变量操作,显然结果是不对的!即使不是同时发过来,三个请求分别操作三个不同内存区域的数据,变量A之间不存在共享,也不具有可见性,处理的结果也是不对的!
如果我们业务中确实存在这个场景的话,我们就需要一种方法解决这个问题!
为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用并发处理相关的功能进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。为了解决这个问题就需要一种跨机器的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!
分布式锁应该具备哪些条件:
1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
二、基于redis实现分布式锁
1、选用Redis实现分布式锁原因:
(1)Redis有很高的性能;
(2)Redis命令对此支持较好,实现起来比较方便
2、使用命令介绍:
(1)SETNX
SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。
(2)expire
expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。
(3)delete
delete key:删除key
在使用Redis实现分布式锁的时候,主要就会使用到这三个命令。
3、实现思想:
(1)获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
(2)获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
(3)释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。

#连接redis
import time
import uuid
from threading import Thread import redis redis_client = redis.Redis(host="localhost",
port=6379,
# password=123,
db=10) #获取一个锁
# lock_name:锁定名称
# acquire_time: 客户端等待获取锁的时间
# time_out: 锁的超时时间
def acquire_lock(lock_name, acquire_time=10, time_out=10):
"""获取一个分布式锁"""
identifier = str(uuid.uuid4())
end = time.time() + acquire_time
lock = "string:lock:" + lock_name
while time.time() < end:
if redis_client.setnx(lock, identifier):
# 给锁设置超时时间, 防止进程崩溃导致其他进程无法获取锁
redis_client.expire(lock, time_out)
return identifier
elif not redis_client.ttl(lock):
redis_client.expire(lock, time_out)
time.sleep(0.001)
return False #释放一个锁
def release_lock(lock_name, identifier):
"""通用的锁释放函数"""
lock = "string:lock:" + lock_name
pip = redis_client.pipeline(True)
while True:
try:
pip.watch(lock)
lock_value = redis_client.get(lock)
if not lock_value:
return True if lock_value.decode() == identifier:
pip.multi()
pip.delete(lock)
pip.execute()
return True
pip.unwatch()
break
except redis.excetions.WacthcError:
pass
return False if __name__ == __main__:
count=10
def seckill(i):
identifier=acquire_lock('resource')
print("线程:{}--获得了锁".format(i))
time.sleep(1)
global count
if count<1:
print("线程:{}--没抢到,票抢完了".format(i))
return
count-=1
print("线程:{}--抢到一张票,还剩{}张票".format(i,count))
release_lock('resource',identifier) # 线程之间通用一个变量,
# 此处也可以考虑使用进程, 进程的结果和线程反差很大
for i in range(50): t = Thread(target=seckill,args=(i,)) t.start()

redis(二十四):Redis分布式锁以及实现(python)的更多相关文章
- SpringBoot开发二十四-Redis入门以及Spring整合Redis
需求介绍 安装 Redis,熟悉 Redis 的命令以及整合Redis,在Spring 中使用Redis. 代码实现 Redis 内置了 16 个库,索引是 0-15 ,默认选择第 0 个 Redis ...
- 二十四 Redis消息订阅&事务&持久化
Redis数据类型: Redis控制5种数据类型:String,list,hash,set,sorted-set 添加数据,删除数据,获取数据,查看有多少个元素,判断元素是否存在 key通用操作 JR ...
- Redis(二十):Redis数据过期和淘汰策略详解(转)
原文地址:https://yq.aliyun.com/articles/257459# 背景 Redis作为一个高性能的内存NoSQL数据库,其容量受到最大内存限制的限制. 用户在使用Redis时,除 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[二]--基于Redisson实现分布式锁
一.redisson介绍 redisson实现了分布式和可扩展的java数据结构,支持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, L ...
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...
- Redis中是如何实现分布式锁的?
分布式锁常见的三种实现方式: 数据库乐观锁: 基于Redis的分布式锁: 基于ZooKeeper的分布式锁. 本地面试考点是,你对Redis使用熟悉吗?Redis中是如何实现分布式锁的. 要点 Red ...
- 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁
spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...
- python使用redis实现协同控制的分布式锁
python使用redis实现协同控制的分布式锁 上午的时候,有个腾讯的朋友问我,关于用zookeeper分布式锁的设计,他的需求其实很简单,就是节点之间的协同合作. 我以前用redis写过一个网络锁 ...
- Redis的“假事务”与分布式锁
关注公众号:CoderBuff,回复"redis"获取<Redis5.x入门教程>完整版PDF. <Redis5.x入门教程>目录 第一章 · 准备工作 第 ...
- 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有測试代码(何志雄)
转载请标明出处. 在分布式系统中,常常会出现须要竞争同一资源的情况,本代码基于redis3.0.1+jedis2.7.1实现了分布式锁. redis集群的搭建,请见我的另外一篇文章:<>& ...
随机推荐
- VS Code项目中通过npm包的方式共享代码片段的方案实现
VS Code项目中通过npm包的方式共享代码片段的方案实现 上周在 "VS Code项目中共享自定义的代码片段方案" 的文章中提到过一个共享代码片段的方案,上周经过调研后并没有发 ...
- JVM进阶之路(一)
JVM是Java程序运行的基本,了解Java程序的运行原理绝对有必要了解JVM的内容,JVM的内容其实很多,而且版本不同,其中的内容也很多不同,接下来就通过几篇文章来慢慢讲述JVM的内容. 一.Jvm ...
- 附015.Kubernetes其他技巧
一 优化镜像源 1.1 国内镜像源 global proxy in China format example dockerhub (docker.io) dockerhub.azk8s.cn dock ...
- c++ 对vector和deque进行逆序排序问题
1.vector vector<int> data1; 2.deque deque <int> data2; 逆序排序方式: 方式1.使用reverse函数 (内置数据类型 ...
- windows10安装配置WSL(Ubuntu)
windows10安装配置WSL(Ubuntu) 怎么在windows系统上用上Linux?有这么几种方法: 1. 安装双系统.这种方法的缺点是每次切换系统都需要关机.切换系统. 2. 虚拟机+Lin ...
- SpringMVC拦截器使用
源码地址 拦截器interceptor 拦截器是URL请求的第一道门,所有请求会先经过拦截器interceptor,然后再进入controller: 下面,记录一种通过注解方法拦截所有需要登录才能发起 ...
- docer
docker默认是不保存文件的,包保存文件需要进行映射 dockerfile编写如下 直接下面的命令会失败 因为run后面的命令/bin/bash会失败,执行的是dockffile中定义的httpd ...
- Linux软件服务管理
学习该课程之前先学习linux的软件安装管理 1.linux的运行级别有下面几种类型 在后面的服务启动管理之中会被使用到 [root@weiyuan httpd-2.4.20]# runlevel N ...
- 关于MySQL事务和存储引擎常见FAQ
1.什么是事务? 事务就是「一组原子性的SQL查询」,或者说一个独立的工作单元.如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询.如果其中有任何一条语句因为崩溃或其他原因无法 ...
- 九、深度优先 && 广度优先
原文地址 一.什么是"搜索"算法? 算法是作用于具体数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于"图"这种数据结构的. 因为图这种数据结构的表达能 ...