美文网首页
基于redis的分布式锁

基于redis的分布式锁

作者: 小小辉 | 来源:发表于2018-08-30 20:27 被阅读0次

1.概述

    现在大部分公司的服务通过分布式部署实现了高可用,但是问题来了:如果有一段逻辑只希望一个应用中的一个线程进行执行,如何能够保证用户的一次操作,同时只受理一次呢?以前单机应用,可以通过java的synchronize和Lock来实现。现在则需要使用分布式锁。

    分布式锁的实现主要有redis、zookeeper、db等方式。本文主要说明用redis实现方式。

2.方案1

    因为redis是单线程处理的,并且支持cas操作。不难想到的一个实现是:

    lock:

        setnx    key    value

    unlock:

        del  key

    其中,setnx语义为:若给定的 key 已经存在,则 SETNX 不做任何动作。  成功设置返回1、设置失败返回0。

    根据setnx的返回值判断是否加锁成功。

   问题:

        如果一个服务lock完之后,崩溃了或者重启了,那么将永远不会unlock,对于需要继续执行的场景来说,是无法接受的。

3.方案2

   针对方案2的一些问题,不难想到对key设置一个超时就ok了。那么方案2来了:

    lock:

        set   key   value  px  timeout_millisecond  nx

    unlock:

        del key

    其中set方法支持同时设置超时和nx,这种方案是否ok?

    问题:

        如果最早拿到锁的服务器1执行结束,调用unlock失败(实际redis删除成功),另外一个服务器2加锁成功。某种补偿导致服务器1重复调用unlock。这时候问题出现了,服务器2加的锁被服务器1释放了。

4.方案3    

   针对上面的问题:一个全备的分布式锁要求是:

    key 一致

    value 包含了持有者信息、加锁的次数(可重入)

    对于redis来说,基于lua脚本实现。代码如下(参考redisson):

        lock:

            if (redis.call('exists', key) == 0)  then 

                redis.call('hset', key, holder_info, 1); 

                redis.call('pexpire', key, timeout); 

                return nil; 

            end;

        if (redis.call('hexists', key, holder_info) == 1)  then 

                redis.call('hincrby',  key, holder_info, 1); 

                redis.call('pexpire',  key, timeout); 

                return nil; 

        end; 

        return redis.call('pttl', key);

unlock:

    if (redis.call('exists', key) == 0) then 

        return 1;  

   end;

    if (redis.call('hexists', key, holder_info) == 0) then 

        return nil; //非本持有者加的锁

    end; 

    local counter = redis.call('hincrby', key, holder_info, -1); 

    if (counter > 0) then 

        redis.call('pexpire', key, timeout); 

        return 0; 

     else 

        redis.call('del', key); 

        return 1;

    end; 

    return nil;

5.总结

    那么真正对于分布式锁的要求是什么,有以下几点:

        1. 不同服务器之间操作串行化(锁的含义)

        2.可重入(根据业务场景、代码来决定)

        3.一个服务器加的锁,不可被另外的服务器删除(误删除)

        4.具有应用崩溃恢复机制

6.展望

    希望以下的能够引起读者的思考:

        1.如果一个应用没有获取到锁,并且业务需求是需要进行重试加锁,那么只能够轮询。是否还有别的办法?

        2.目前讨论的都是基于redis单点且服务正常的情况下。 如果redis崩溃,那么如何处理?

        3.redis、zookeeper、db实现的分布式锁的优缺点各是什么?

相关文章

  • 基于redis实现的分布式锁

    本文要点 基于redis实现分布式锁demo 基于redis实现分布式锁原理 基于redis实现分布式锁优缺点 正...

  • 分布式锁实现

    基于数据库实现分布式锁基于缓存(redis,memcached)实现分布式锁基于Zookeeper实现分布式锁 s...

  • 7.2-基于Redis实现分布式锁的几种坑你是否踩过《上》—小滴

    基于Redis实现分布式锁的几种坑你是否踩过《上》 简介:基于Redis实现分布式锁的几种坑 实现分布式锁 可以用...

  • 基于redis的分布式锁

    分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis,memcached,tair)实现分布式锁 基于Z...

  • 分布式锁的实现方式

    分布式锁通常有3种实现方式,即数据库乐观锁、基于redis的分布式锁和基于zookeeper的分布式锁。 一、基于...

  • 分布式锁之Redis实现(acquire)

    分布式锁一般有三种实现方式: 基于数据库的锁; 基于Redis的分布式锁; 基于ZooKeeper的分布式锁。 本...

  • Redis实现分布式锁

    分布式下的分布式锁一般实现有三种: 基于数据库的乐观锁 基于redis的分布式锁 基于zookeeper的分布式锁...

  • 84 redis实现分布式锁的原理

    1,Redis使用setnx 实现2,Redisson 分布式锁;Redis基于 setnx 实现分布式锁原理:R...

  • Redis实现分布式锁

    1. 分布式锁分类 数据库乐观锁 基于Redis的分布式锁 基于ZooKeeper的分布式锁 2. 组件依赖 po...

  • Redis分布式锁实现

    分布式锁实现方式 数据库乐观锁; 基于Redis的分布式锁; 基于ZooKeeper的分布式锁。 本篇将介绍第二种...

网友评论

      本文标题:基于redis的分布式锁

      本文链接:https://www.haomeiwen.com/subject/mumrwftx.html