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

使用redis分布式锁解决并发线程资源共享问题

颛孙钱青
2023-03-14
本文向大家介绍使用redis分布式锁解决并发线程资源共享问题,包括了使用redis分布式锁解决并发线程资源共享问题的使用技巧和注意事项,需要的朋友参考一下

前言

众所周知, 在多线程中,因为共享全局变量,会导致资源修改结果不一致,所以需要加锁来解决这个问题,保证同一时间只有一个线程对资源进行操作

但是在分布式架构中,我们的服务可能会有n个实例,但线程锁只对同一个实例有效,就需要用到分布式锁----redis setnx

原理

修改某个资源时, 在redis中设置一个key,value根据实际情况自行决定如何表示

我们既然要通过检查key是否存在(存在表示有线程在修改资源,资源上锁,其他线程不可同时操作,若key不存在,表示资源未被线程占用,允许线程抢占,然后将通过setnx设置vlaue,表示资源上锁,其他线程不可同时操作)

图示:

分析

我们的服务处于一个集群中,如果只是简单的的使用线程锁来解决以上问题,是存在问题的:因为线程是基于进程的,两个web server处于不同的进程空间

也就是说,user1的请求发往web server1,那只能与web server1的其他请求进行锁的操作,而不能对web server2的请求产生影响

上面的图中,user1发往web server1的请求负责处理的线程为Thread1,同理负责处理user2发往web server2的请求的线程thread2

在同一时刻1,两个线程都读取了mysql中residue_ticket的值为100,对应上图 (1)(2), 各自对100进行-1操作,更新到数据库,对应(3)(4)

我们预期的情况是residue_ticket值被减少了两次,应该为98,但是实际情况下,两个线程都做了100-1=99的操作,并都将mysql中的值改为了99, 的这就会导致最终数据不一致,所以就要用到分布式锁。

为什么用redis?

因为redis是单线程的,不存在多线程资源竞争,并且它真的很快

为什么用setnx 而不是set?

setnx表示只有在key不存在时才能设置成功,但是set会在key存在的情况下修改value

利用setnx的特性,我们可以这样这样设计:

伪代码:

# 设置redis锁的
  redis key = 'residue_ticket_lock'

  # get_ticket是处理购票的逻辑
  def get_ticket():
    time_out = 5  # 为了防止线程过多,当前线程获取不到锁,长时间处于循环中而导致的性能影响,我们设置一个超时时间,如果当前线程在超时时间内还没有抢占到分布式锁,就返回失败的结果
    while True:
       if redis.setnx('residue_ticket_lock','lock',5):
          # 如果setnx返回True, 表示此刻没有其他线程在操作数据库,当前线程可以上锁成功,注意不仅设置了value=lock,还设置了过期时间,这是必要的,为了防止上锁的线程异常崩掉导致不能释放(删除key)而导致其他所有线程永远拿不到操作权
          residue_ticket = mysql.get('residue_ticket')   # 从mysql中获取当前剩余票数
          mysql.update('residue_ticket',residue_ticket-1)  # 订购成功,将票数-1,更新数据到mysql
          # 删除key,释放锁
          redis.del('residue_ticket')
          return True
       else:
          # 如果setnx返回False,表示有其他线程对在操作,当前线程等待0.01s,并继续循环
          time.sleep(0.01)
          time_out -= 0.01
          continue
    return False

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 因此,我刚刚阅读了有关redlock的文章。据我了解,它需要3台独立的机器才能工作。独立表示它们是指所有计算机都是主计算机,并且它们之间没有复制,这意味着它们正在提供不同类型的数据。那么,为什么我需要锁定在充当主服务器的三个独立Redis实例中存在的密钥?我需要使用redlock的用例是什么? 问题答案: 那么,为什么我需要锁定在三个独立的Redis实例中充当主键的密钥? 这并不是说您

  • 问题内容: 对于以下发布请求如何使用烧瓶中从ajax发布的数据?: 我收到一个错误: 我尝试通过以下两种方式解决该问题,但似乎无济于事。 使用Flask-CORS 这是用于处理的扩展,应使跨域AJAX成为可能。 我的 pythonServer.py 使用此解决方案: 使用特定的Flask装饰器 这是Flask 官方 代码片段,定义了一个装饰器,该装饰器应允许其装饰功能。 http://flask.

  • 问题内容: 对于以下ajax发布请求Flask(如何使用烧瓶中ajax发布的数据?): 我收到一个错误: 我尝试通过以下两种方法解决该问题,但似乎没有任何效果。 1.使用Flask-CORS 这是用于处理的扩展,应使跨域AJAX成为可能。 我的pythonServer.py使用此解决方案: 2.使用特定的Flask装饰器 这是Flask 官方代码片段,定义了一个装饰器,该装饰器应允许CORS其装饰

  • 本文向大家介绍详解springboot中redis的使用和分布式session共享问题,包括了详解springboot中redis的使用和分布式session共享问题的使用技巧和注意事项,需要的朋友参考一下 对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash、轮训、根据权重、随机等。不管对于哪一种负载均衡算法,由于Nginx对不同的请求分发到某一个Tomcat,T

  • 对于以下post请求(如何在flask中使用从ajax发布的数据?): 我得到一个错误: null http://flask-cors.readthedocs.org/en/latest/ 如何在烧瓶和Heroku中启用CORS 应用jwt auth包装器时Flask-cors包装器不工作。 JavaScript-请求的资源上没有'access-control-allog-origin'标头 我的

  • 主要内容:Redis分布式锁介绍,Redis分布式锁命令在分布式系统中,当不同进程或线程一起访问共享资源时,会造成资源争抢,如果不加以控制的话,就会引发程序错乱。此时使用分布式锁能够非常有效的解决这个问题,它采用了一种互斥机制来防止线程或进程间相互干扰,从而保证了数据的一致性。 提示:如果对分布式系统这一概念不清楚,可参考百度百科《分布式系统》,简而言之,它是一种架构、一种模式。 Redis分布式锁介绍 分布式锁并非是 Redis 独有,比如 MySQ