Redisson分布式锁的简单使用

redis分布式锁学习和集成框架Redisson分布式锁的一些简单使用

大家好,又见面了,我是全栈君。

做一个积极的人

编码、改bug、提升自己

我有一个乐园,面向编程,春暖花开!

一:前言

我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id 当做唯一的值!
而uuid是递增生成的,从1开始一直递增,那么在同一台机器上运行代码,加上同步方法(synchronized),这个生成id的方法就是ok!

但是因为业务扩展或者说为了安全,项目运行在两台机器上,此时单个的同步方法(synchronized或者Lock)就不能防止id的重复了!!!


要解决上面的这个问题,其他有如下解决办法!

(1):每台机器生产Id的代码,key+id 可以在前加上机器编号区分,key + id — >机器唯一编号 + key + id
(2):使用数据库行锁(单个数据库的是时候,如何是分布式数据库也会出现问题),在需要插入id的表加上行锁,防止数据重复导致程序异常!
(3):使用分布式锁

二:分布式锁简介

网上有很多的讲解分布式锁的文章,但是细细分析很多的代码还是有很多的问题的,如下代码片段摘自博文:

public void lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= 1000000;
        final Random r = new Random();
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
                    redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
                    locked = true;
                    logger.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
        }
    }
	

上面的代码博主也说了:如果长时间获取不到,就会获取锁失败,相当于没加锁!

这里还有可能发生其他问题:

(1)并发情况,expire主动释放锁的时候,可能释放的是别人的锁(不懂请自行查询相关资料

(2)Redis服务挂掉,锁失败,相当于没加锁!最好使用主从+哨兵提高 高可用

注:使用的时候要注意上面问题!!!

还有一种摘自博文:
http://www.cnblogs.com/0201zcr/p/5942748.html
这个博问分析的:

 while (timeout >= 0) {
            long expires = System.currentTimeMillis() + expireMsecs + 1;
            String expiresStr = String.valueOf(expires); //锁到期时间
            if (this.setNX(lockKey, expiresStr)) {
                // lock acquired
                locked = true;
                return true;
            }

            String currentValueStr = this.get(lockKey); //redis里的时间
            if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
                //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的
                // lock is expired

                String oldValueStr = this.getSet(lockKey, expiresStr);
                //获取上一个锁到期时间,并设置现在的锁到期时间,
                //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                    //防止误删(覆盖,因为key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,但是因为什么相差了很少的时间,所以可以接受

                    //[分布式的情况下]:如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁
                    // lock acquired
                    locked = true;
                    return true;
                }
            }
            timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS;

            /*
                延迟100 毫秒,  这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程,
                只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足.
                使用随机的等待时间可以一定程度上保证公平性
             */
            Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);

        }
        

这个相比第一个完善了误删除key的问题,但是要合理的设置超时时间 (要了解具体加锁的业务),否则的话,也会使锁失效。

三:Redisson分布式锁的介绍和简单的使用

Redisson的介绍可以到:https://github.com/redisson/redisson/wiki/1.-概述 这里去了解!

我这里说一下使用时候要注意的问题:

1:文档里面说明了支持Redis 2.8以上版本,支持Java1.6+以上版本。根据自己的环境选择合适的版本!

2:2.8.1的redisson 需要使用 netty的jar包, 否则报错:Hopper: java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup。

3:2.8.1的redisson需要jackson 2.5+版本,否则报错bjectMapper.addMixIn method not fond。

我写了一个简单的例子,自己也做了一下测试,使用的Redis主从+哨兵模式!
demo的目录结构,具体的源码我放到github上面,地址:https://github.com/dufyun/learn-tech-collection/tree/master/redissondemo

这里写图片描述

注:这里一定要先安装Redis服务,如果没有安装Redis服务,请参考这篇:http://blog.csdn.net/u010648555/article/details/69944668
如果Redis服务安装到服务器上面,请修改代码中的Redis地址和端口!否则运行不起了!

运行这个类UUidGeneratorLockTest就可以看到效果!测试结果我也在readme.txt进行了总结!

如果在测试和学习的过程中有疑问,可以随时和我联系,也可以加左侧的群或者QQ互相探讨!谢谢!

四:总结

这个时代,信息爆炸,各种技术博文之间互相参考,真正的问题可能没有暴露出来,真正好的文章还是需要鉴别的!(我自己也会参考一些文章,但是我都会进行一些自己验证,一个是为准确性,一个加深自己的对知识的认识)

我也要反思,自己之前也写过一些博文,也是遇到问题了,去网上搜一些解决方案,很多方案确实是理论上可以解决当前遇到的问题,当时去深究,就会发现很多的不完整性!

多思考,多测试!让代码能够更加高效、健壮和安全!

五:参考博文

Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现
分布式锁的几种实现方式


谢谢你的阅读,如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你每天开心愉快!


不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

愿你我在人生的路上能都变成最好的自己,能够成为一个独挡一面的人
Redisson分布式锁的简单使用

© 每天都在变得更好的阿飞云

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120946.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • AE常用表达式汇总「建议收藏」

    很多朋友面对AE表达式望而生畏,不过再难的东西都会有它最本质的规则,如果你理解了基本的原理和常用的表达式命令,这也许会提高你的工作效率。我通过自己对AE表达式的理解,尝试用最简单的语言解释一些看似复杂的操作,如果此篇文章能给你带来一些启发,不胜荣幸~首先什么是表达式呢?表达式就是AE内部基于JS编程语言开发的编辑工具,可以理解为简单的编程,不过没有编程那么复杂。其次表达式只能添加在可以编辑的关建帧的属性上,不可以添加在其他地方;表达式的使用根据实际情况来决定,如果关键帧可以更好的实现你想要的效果,使

    2022年4月6日
    352
  • wget(1.11.4) for win「建议收藏」

    wget(1.11.4) for win「建议收藏」下载wget(1.11.4)forwin安装添加wget环境变量,这样使用就更方便了,右键计算机->属性->高级系统设置->高级->环境变量->选中PATH->编辑,在最后添加;C:\ProgramFiles(x86)\GnuWin32\bin下载文件wget网址而要让档案自动储存到指令的目录下,则需要借用-P这个参数,可以使用以下的指令wge…

    2022年6月3日
    24
  • Linux:常用命令大全

    Linux:常用命令大全

    2021年9月26日
    42
  • js的数据类型有哪些?[通俗易懂]

    js的数据类型有哪些?[通俗易懂]数据类型一、数据类型:基本数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)。引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function)。特殊的对象:正则(RegExp)和日期(Date)。特殊类型:underfined未定义、Null空对象、Infinate无穷、NAN非数字基本数据类型的值直接在栈内存中存储,值与值之间独立存在,修改一个变量不会影响.

    2022年9月5日
    3
  • linux centos安装wine qq,ubuntu安装wine QQ「建议收藏」

    linux centos安装wine qq,ubuntu安装wine QQ「建议收藏」题外话:在使用win7,8的时候,发现如果硬盘存有大量文件的时候,笔记本自带的渣渣机械硬盘读取会很慢。而win10在硬盘读取方面的优化,确实比前几个版本好。但是,随之出现的问题是,内存不够用。后来上手linux,才发现这才是真爱。装过ubuntu,centos。总结ubuntu更适合日常的使用。顺带说一句,16.04TLS,装入很多大型IDE和虚拟机的时候,4G也是有点抗不住。开始正题:首先,安装…

    2022年9月5日
    2
  • 自监督学习(self-supervised learning)(20201124)

    自监督学习(self-supervised learning)(20201124)看论文总是会看出来一堆堆奇奇怪怪的名词。从远程监督、有监督、半监督、无监督开始,最近又看到了一个自监督。首先先对上面的概念进行简述:半监督(semi-supervisedlearning):利用好大量无标注数据和少量有标注数据进行监督学习;远程监督(distant-supervisedlearning):利用知识库对未标注数据进行标注;无监督:不依赖任何标签值,通过对数据内在特征的挖掘,找到样本间的关系,比如聚类相关的任务。自监督:利用辅助任务从无监督的数据中挖掘大量自身的信息。

    2022年9月14日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号