如何使用Redis锁处理并发问题详解

 更新时间:2019年07月15日 14:08:54   作者:haofly  
这篇文章主要给大家介绍了关于如何使用Redis锁处理并发问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

上周“被”上线了一个紧急项目,周五下班接到需求,周一开始思考解决方案,周三开发完成,周四走流程上线,也算是面向领导编程了。之前的项目里面由于是自运维,然后大多数又都赶时间,所以在处理定时任务上面基本都是自己在服务器上添加crontab,而不是让多个实例自己去处理定时任务的并发锁,并且Laravel 5.5开始自带并发锁,我们也快升级了。但是这次项目是Python项目,无奈只能自己实现一下,以下这个方案实现起来非常简单且易于理解。

import redis
r = redis.Redis(...)

last_heart = 0		# 记录上一次得到的锁心跳
free_lock_try = 6	# 锁无心跳的最大次数 

while not r.setnx('mylock', 1):
 now_heart = r.get('mylock')
 print(f"没获取到锁,now_heart={now_heart},last_heart={last_heart},free_lock_try={free_lock_try}")
 if now_heart == last_heart:
  free_lock_try = free_lock_try - 1
  if free_lock_try == 0:	# 锁已经1分钟没有心跳了
   old_heart = r.getset('mylock', 1)	# 将lock重置为1,并返回set之前的心跳值
   if old_heart < now_heart:
    time.sleep(10)
    continue
   else:
    break	# 成功获取到锁,退出循环
 else:
  free_lock_try = 6	# 锁有心跳,重置free_lock_try值
  last_heart = now_heart
 time.sleep(10)

def producer_exit():
 """程序正常退出时候自动清理锁"""
 r.delete('mylock')
import atexit
atexit.register(producer_exit)

# 业务代码
while True:
 r.incr('mylock')	# 让锁心跳加一
 ...

我们来看看这段程序都解决了并发锁中的哪些问题

  • 高并发下,多个进程无法同时获取到锁。这里使用的是redis.setnx,如果锁已经存在,其他进程是无法重置锁并获取到锁的。另外当多个进程同时发现有锁已经没有心跳了,使用的是redis.getset将心跳重置为1,都能set成功,但是get出来的值多个进程是不一样的,只有真正获取到锁的进程返回的是之前进程的心跳,而其他进程获取到的都是1。
  • 有锁进程正常退出,可以使用atexit注册进程退出函数删除锁,这里也可以不要,不过下次启动得等新的进程等待几次心跳
  • 有锁进程意外退出,退出后心跳不再增加,超过free_lock_try次数后,其他进程会重新设置并获取锁
  • 所有进程全都意外退出,这个问题不是锁来关心的,可以使用supervisor进行守护进程。

导致Redis并发原因解释

正所谓只有知其然才能知其所以然,只有弄明白问题出现的原因所在,才能对症下药,寻找解决问题的良方。众所周知,Redis程序采用单线程模式进行运行,作为单线程程序,Redis客户端的命令是逐条执行,也叫做One by One执行。既然是逐条命令执行,从表面上来看Redis似乎不存在高并发的问题,这一观点论也有道理,原子性的Redis命令本身也确实不存在高并发问题,这与多线程下的程序勃然不同。但是我们项目工作搭建Redis环境之后,通常都会是一组命令集合执行程序,一个请求中就包含了N个Redis执行命令,再加上多个客户端请求,命令就更多了,导致连接超时、数据混乱或错误、请求阻塞等多种问题。

即总结为,产生Redis并发诱因是程序中的业务复杂度导致。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • Redis实现延迟任务的三种方法详解

    Redis实现延迟任务的三种方法详解

    延迟任务(Delayed Task)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下
    2025-04-04
  • redis数据倾斜处理方法

    redis数据倾斜处理方法

    我们在使用Redis分片集群时,集群最好的状态就是每个实例可以处理相同或相近比例的请求,但如果不是这样,则会出现某些实例压力特别大,而某些实例特别空闲的情况发生,本文就一起来看下这种情况是如何发生的以及如何处理
    2022-12-12
  • 浅谈一下Redis的数据结构

    浅谈一下Redis的数据结构

    这篇文章主要介绍了浅谈一下Redis的数据结构,简单字符串结构被用于存储redis的key对象和String类型的value对象,其中的free和len字段可以轻松的使得在该字符串被修改时判断是否需要扩容,需要的朋友可以参考下
    2023-08-08
  • CentOS 7下安装 redis 3.0.6并配置集群的过程详解

    CentOS 7下安装 redis 3.0.6并配置集群的过程详解

    这篇文章主要给大家介绍了CentOS 7下安装 redis 3.0.6并配置集群的过程,文中通过示例代码和详细的步骤介绍的很相信,对大家具有一定的参考价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • Redis中一些最常见的面试问题总结

    Redis中一些最常见的面试问题总结

    Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行各种刁难。下面这篇文章主要给大家总结介绍了关于Redis中一些最常见的面试问题,需要的朋友可以参考下
    2018-09-09
  • Redis实现附近商铺的项目实战

    Redis实现附近商铺的项目实战

    本文主要介绍了Redis实现附近商铺的项目实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Redis解决优惠券秒杀应用案例

    Redis解决优惠券秒杀应用案例

    这篇文章主要介绍了Redis解决优惠券秒杀应用案例,本文先讲了抢购问题,指出其中会出现的多线程问题,提出解决方案采用悲观锁和乐观锁两种方式进行实现,然后发现在抢购过程中容易出现一人多单现象,需要的朋友可以参考下
    2022-11-11
  • Linux上安装Redis详细教程

    Linux上安装Redis详细教程

    这篇文章主要给大家详细介绍了在Linux上安装Redis详细教程,文中有详细的代码示例和安装步骤,对我们学习安装redis有一定的帮助,需要的朋友可以参考下
    2023-07-07
  • redis部署及各种数据类型使用命令详解

    redis部署及各种数据类型使用命令详解

    这篇文章主要介绍了redis部署及各种数据类型使用命令,编译安装redis及部署过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • redis缓存穿透解决方法

    redis缓存穿透解决方法

    在本篇文章里小编给大家分享了关于redis缓存穿透的解决方法以及相关实例内容,需要的朋友们学习下。
    2019-06-06

最新评论