一、背景

为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用并发处理相关的功能进行互斥控制。

但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。

为了解决这个问题就需要一种跨机器的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

二、分布式锁实现示例

分布式锁应该具备哪些条件:

  • 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
  • 高可用的获取锁与释放锁;
  • 高性能的获取锁与释放锁;
  • 具备可重入特性;
  • 具备锁失效机制,防止死锁;
  • 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。

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进行锁释放。

代码示例如下,定义了2个函数,acquire_lock()获取锁,release_lock()释放锁。最后例子中使用20个线程模拟秒杀5张票,使用–运算符来实现商品减少,从结果有序性就可以看出是否为加锁状态。

# -*- coding: UTF-8 -*-
"""
# rs勿忘初心
"""
import time
import uuid
import redis
from threading import Thread# redis连接
redis_client = redis.Redis(host="127.0.0.1",port=6379,password="xxxxx",db=8)# 获取一个锁
# 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_timelock = "string:lock:" + lock_namewhile time.time() < end:if redis_client.setnx(lock, identifier):# 给锁设置超时时间, 防止进程崩溃导致其他进程无法获取锁redis_client.expire(lock, time_out)return identifierelif 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_namepip = redis_client.pipeline(True)while True:try:pip.watch(lock)lock_value = redis_client.get(lock)if not lock_value:return Trueif lock_value.decode() == identifier:pip.multi()pip.delete(lock)pip.execute()return Truepip.unwatch()breakexcept redis.excetions.WacthcError:passreturn False# 测试刚才实现的分布式锁
# 例子中使用20个线程模拟秒杀5张票,使用–运算符来实现商品减少,从结果有序性就可以看出是否为加锁状态。
count = 5def seckill(i):identifier = acquire_lock('resource')print("线程:{}--获得了锁".format(i))time.sleep(1)global countif count < 1:print("线程:{}--没抢到,票抢完了".format(i))returncount -= 1print("线程:{}--抢到一张票,还剩{}张票".format(i, count))release_lock('resource', identifier)for i in range(20):t = Thread(target=seckill, args=(i, ))t.start()

4、其它实现

在python中,redis库默认只有乐观锁的一种写法,在这里我再推荐使用一个库python-redis-lock,使用这个库对redis多个客户端并发的情况加锁,真的很方便。(多个redis客户端访问同一个redis服务端,控制并发),导入包方法如下:

import redis_lock

参考:

python基于redis实现分布式锁

Redis的分布式锁python-redis-lock使用 - -零 - 博客园

基于Python + Redis实现分布式锁相关推荐

  1. 基于单机版redis的分布式锁设计实现

    本文转载自简书 作者:谢随安 链接:https://www.jianshu.com/p/20c5282c1df7 分布式锁介绍 分布式并发环境下,为了保证事务操作的原子性,需要引入分布式锁来保证一连串 ...

  2. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  3. 基于Redis实现分布式锁之前,这些坑你一定得知道

    开头 基于Redis的分布式锁对大家来说并不陌生,可是你的分布式锁有失败的时候吗?在失败的时候可曾怀疑过你在用的分布式锁真的靠谱吗?以下是结合自己的踩坑经验总结的一些经验之谈. 你真的需要分布式锁吗? ...

  4. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  5. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  6. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

  7. 基于 Redis 的分布式锁到底安全吗?

    [完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...

  8. 基于Redis实现分布式锁

    http://blog.csdn.net/ugg/article/details/41894947 背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部分的解 ...

  9. js 拉勾网效果_Node.js 中实践基于 Redis 的分布式锁实现

    在一些分布式环境下.多线程并发编程中,如果对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题. 作者简介:五月君,Nodejs Developer ...

最新文章

  1. 【C++】Google C++编码规范(四):其他C++
  2. PHP如何通过Http Post请求发送Json对象数据?
  3. Unsupported ONNX opset version: 11
  4. xgb多线程成功运行记录
  5. 无向图双连通分量BCC(全网最好理解)
  6. 4个空格和一个tab有什么区别_火花塞为什么一换就是4个?只换一个不行吗?
  7. go 根据输入类型执行对应的方法_Go 每日一库之 sqlc
  8. ASP.NET AJAX1.0尝鲜试用:Web Service调用
  9. 【Python】BeautifulSoup导入lxml报错
  10. android编译的错误日志,android编译遇到错误
  11. Tarjan算法——求强连通分量
  12. 在CentOS8.3上安装Vlmcsd-1113搭建Kms服务
  13. 数值计算之第四期:追赶法和范数
  14. mysql MVCC产生幻读原因及解决方式
  15. MATLAB | 绘图复刻(二) | 折线图+误差棒+柱状图+散点抖动+灰色背景+图片叠加
  16. 区块链前景分析和学习建议
  17. Silverlight 教程第二部分:使用布局管理 (木野狐译) 1
  18. 电脑控制手机 教你实现多个手机同时打开关闭软件
  19. 面试系列(二十):金山云 C++开发
  20. 满二叉树 / 真二叉树 / 完全二叉树 ~

热门文章

  1. #includeiostream与#includeiostream.h的区别
  2. 1431. 拥有最多糖果的孩子
  3. android自定义屏幕,Android自定义屏保
  4. HALCON:lines_gauss用法解析
  5. aver函数C语言怎么用,C语言函数使用
  6. Python爬虫技巧!网站有反爬?我们有selenium!
  7. 个人博客开发系列:前台博客页面开发部署完成
  8. TortoiseGit使用入门
  9. 在文本框中插入@对象
  10. 恶意软件利用Windows故障诊断平台传播