zoukankan      html  css  js  c++  java
  • 浅析Redis实现lock互斥访问资源

    Redis是当前很流行的一种开源键值数据库。目前睿思的后台架构在数据库层采用了Redis和MySQL组合的形式,其中Redis主要用来存储状态信息(比如当前种子的peer)和读写频繁的数据。Redis完全运行在内存之上,无lock设计,速度非常快!通过实测,在睿思服务器上读写速度达到3万次/s。
     
              在高并发的应用中,很多时候我们需要对某些资源进行竞争访问,比如在很多人下载一个热门资源,就可能存在很多请求去修改某个资源的peer信息(就是保存了当前保种人的ip地址和端口号),需要保证某个请求修改peer信息的时候,不允许其他请求修改,否则就会出现数据覆盖的问题。但是Redis没有提供对数据的加锁,所以需要我们通过Redis提供的命令自己实现:
     
     
    思路一:
     
           通过get 和set 命令实现
           这中方式很容易想到,就是当每次请求到来时通过get判断这个锁是否存在,如果不存在则set创建。这种方法有一个弊端,由于get和set是两次Redis请求,二者之间有延时,在高并发的环境下,有可能在get检测到锁不存之后在set之前已经被其他线程set,这时当前线程再set,这样锁就失效了。所以这种方法只能应对并发量不是很高的情况。
     
     
    思路二:
     
            通过setnx 和 expire命令实现
           在访问需要互斥访问的资源时,通过setnx命令去设置一个lock 键,setnx的作用是判断锁是否存在,如果不存在则创建,返回成功,如果存在则返回失败,服务器返回给客户端,指示客户端稍后重试。expire命令用于给该锁设定一个过期时间,用于防止线程crash,导致锁一直有效,从而导致死锁。例如:设定锁的有效期为100秒,那么即使线程奔溃,在100秒后锁会自动失效。
    1. > setnx lock "lock"
    复制代码

     

    如果成功则设置过期时间
    1. >expire lock 100
    复制代码


    访问互斥资源结束后,删除锁
    1. >del lock
    复制代码




    思路三:
     
          通过watch和Redis的事务命令实现
         这种方式的效果和思路二类似。在请求到时先watch改资源锁,然后再通过在事务执行 创建锁的过程,锁的键值能唯一标识改请求(比如用时间+用户标识)。如果当前还有其他线程请求该资源,当判断该锁存在时则返回错误重试(例如睿思BT tracker返回“服务器过载,自动重试的”的提示就属于此类情况)。如果有多个请求同时判断改锁不存在而创建锁,这样也会由于watch了这个锁,导致之前watch的线程执行事务失败,返回客户端自动重试。这样达最终达到了锁的目的。
    积极乐观,好好coding
  • 相关阅读:
    从0开始学FreeRTOS-(创建任务)-2
    从0开始学FreeRTOS-1
    linux(ubuntu)系统mysql-5.7 修改字符集
    腾讯云服务器简单环境配置
    linux系统ubuntu18.04安装mysql(5.7)
    ubuntu18.04从零开始配置环境(jdk+tomcat+idea)到使用idea开发web应用和servlet
    Eclipse为工具包关联源码(本例工具包为dom4j-1.6.1)
    关于c#(vs)dategridview控件继承不能修改的问题
    C语言写单链表的创建、释放、追加(即总是在最后的位置增加节点)
    c++邻接表存储图(无向),并用广度优先和深度优先遍历(实验)
  • 原文地址:https://www.cnblogs.com/xiaodi914/p/4520664.html
Copyright © 2011-2022 走看看