分布式锁在多实例部署,分布式系统中经常会使用到,这是因为基于jvm的锁无法满足多实例中锁的需求,本篇将讲下redis如何通过Lua脚本实现分布式锁,不同于网上的redission,完全是手动实现的

我们先来看一个无锁的情况下会导致什么问题:

这是一个普通的更新用户年龄的功能,各层代码如下,访问controller层,一个更新,一个查询

这是service层,我们使用contdownlatch发令枪来模拟线程同时并的情况,发令枪设为32,即32个线程同时去请求修改年龄,

这里使用线程池来提交多线程任务,看代码知道,这里我们已经有了判断年龄的操作,当查询用户查询大于0时,才去调更新用户年龄-1的方法,等下看看有没有用

这里是sql,可以看到两个sql,一个查询用户年龄,一个会执行用户年龄每次减1 ,

这里是用户数据,我们可以看到,用户UID为UR12324的用户,他的年龄是30,接着我们来调32个线程来操作减他年龄

我们请求下这个方法

然后看看结果:

可以看到库中年龄已被减为-2,在未加锁的情况下,查询较验并没有什么作用,此时如果加个synchronized或lock锁肯定能避免这种情况,但我们本文讨论的是多实例或分布式环境中,此加锁方式仍然会产生问题,感兴趣的可以试下是不是

下面我们开始实现一个redis分布式锁,来避免这种情况发生,先说说实现思路:

1,线程请求访问前先调用加锁的方法,加锁就去里生成一个随机数同时保存在线程本地变量和redis的某key中,此key设有效期为200ms,具体值根据业务执行时间自行调整,加锁成功;

2.其它线程试着访问拿出它本地变量与redis中某key进行比较,如果不一致,则说明有锁,此线程休眠一段时间,再试着加锁;

3.加锁成功的线程在操作结束后删掉它持有锁(用lua实现,保证原子性,在它比对和删除锁的过程中,其它线程不会加锁成功),让其它线程再次加锁以执行任务;

下面看看我们写的锁代码:

片段1:使用redislock 实现lock来复写它的方法

片段2:试着加锁的方法

片段3:解锁方法,此处首先从线程本地变量获取它的随机数,然后调用lua脚本,与redis中key相比较,如果相同则删除,否则返回0;

此为lua脚本方法,用此方法可以保证判断和删除的原子性,在此过程中没有线程可以操作此key

到此为止,我们锁基本写完,来测试下有没有用:

我们在此方法前后分别加入加锁和解锁方法,使用方式和lock锁一样, 我们重新把年龄恢复到30后来测试一下吧

先看看日志

这里可以看到各个线程争夺锁的情况,再看看执行结果

这里我们可以看到虽然是32个线程并发执行,但此值并不会变为负数,加锁成功.

我们可以看到最后2个线程并没有执行方法

此时说明加锁成功,大家可以在分布式环境中测试更明显,有关极端情况下解锁失败后应该做什么也可以由我们自己决定,比redission要灵活,带锁的redis最好是单实例,在集群中可能会出问题,有机会我们再用zk实现下.

redis分布式锁实践的更多相关文章

  1. spring-boot 中实现标准 redis 分布式锁

    一,前言 redis 现在已经成为系统缓存的必备组件,针对缓存读取更新操作,通常我们希望当缓存过期之后能够只有一个请求去更新缓存,其它请求依然使用旧的数据.这就需要用到锁,因为应用服务多数以集群方式部 ...

  2. 分布式锁实践(一)-Redis编程实现总结

    写在最前面 我在之前总结幂等性的时候,写过一种分布式锁的实现,可惜当时没有真正应用过,着实的心虚啊.正好这段时间对这部分实践了一下,也算是对之前填坑了. 分布式锁按照网上的结论,大致分为三种:1.数据 ...

  3. redis分布式锁的这些坑,我怀疑你是假的开发

    摘要:用锁遇到过哪些问题? 一.白话分布式 什么是分布式,用最简单的话来说,就是为了较低单个服务器的压力,将功能分布在不同的机器上面:就比如: 本来一个程序员可以完成一个项目:需求->设计-&g ...

  4. Redis分布式锁 (图解-秒懂-史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

  6. Redis分布式锁

    Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...

  7. redis分布式锁和消息队列

    最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP ...

  8. redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  9. spring boot redis分布式锁

    随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁.分布式锁的实现有很多种,比如基于数据库. zookeeper 等,本文主要介绍使用 Redis 做分布式锁的方式,并封装成spring b ...

随机推荐

  1. Cocos2D iOS之旅:如何写一个敲地鼠游戏(七):弹出地鼠

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  2. 【翻译】使用Sencha Ext JS创建美丽的图画(1)

    原文:Creating Beautiful Drawings Using Sencha Ext JS – Part 1 许多人可能对Ext JS中的图表包相当熟悉了.通过它可以快速创建相当强悍的可视化 ...

  3. android的PackageManagerService详解

    PackageManagerService主要是一个包的管理服务,在开机的时候会解析以前保存的一些安装包的相关数据,android运行过程中新安装的apk也会保存到PackageManagerServ ...

  4. C++ Primer 有感(面向对象编程)

    1.除了构造函数之外,任意非static成员函数都可以是虚函数.保留字virtual只在类内部的成员函数声明处出现,不能用在类定义体外部出现的函数定义上. 2.派生类只能通过派生类对象访问其基类的pr ...

  5. 【uWSGI】 实战之操作经验

    以下是uWSGI版本为2.0以上,uwsgi的启动可以把参数加载命令行中,也可以是配置文件 .ini, .xml, .yaml 配置文件中,个人用的比较多得是 .ini 文件.下面总结下自己操作和使用 ...

  6. 【一天一道LeetCode】#80. Remove Duplicates from Sorted Array II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Follow ...

  7. jquery跳出当前的each循环的方式

    jquery跳出当前的each循环,使用如下方式: return false;--跳出所有循环:相当于 javascript 中的 break 效果. return true;--跳出当前循环,进入下 ...

  8. 安卓TV开发(三) 移动智能设备之实现主流TV电视盒子焦点可控UI

    前言:移动智能设备的发展,推动了安卓另一个领域,包括智能电视和智能家居,以及可穿戴设备的大量使用,但是这些设备上的开发并不是和传统手机开发一样,特别是焦点控制和用户操作体验上有很大的区别,本系列博文主 ...

  9. (三十三)Xcode项目的重要工程文件

    1.Supporting files内有一个Xxx-Info.plist文件(旧版本Xcode的配置文件叫Info.plist).因此自定义的plist不要带Info关键词. 这个plist是系统的全 ...

  10. java缓存系统

    第一版 package cache; import java.util.HashMap; import java.util.Map; public class Cache1 { private Map ...