redis分布式锁

不为人所知的分布式锁实现全都在这里了!

◇◆丶佛笑我妖孽 提交于 2020-01-07 20:52:39
1、引入业务场景 首先来由一个场景引入: 最近老板接了一个大单子,允许在某终端设备安装我们的APP,终端设备厂商日活起码得几十万到百万级别,这个APP也是近期产品根据市场竞品分析设计出来的,几个小码农通宵达旦开发出来的,主要功能是在线购物一站式服务,后台可以给各个商家分配权限,来维护需要售卖的商品信息。 老板大O :谈下来不容易,接下来就是考虑如何吸引终端设备上更多的用户注册上来,如何引导用户购买,这块就交给小P去负责了,需求尽快做,我明天出差! 产品小P :嘿嘿~,眼珠一转儿,很容易就想到了,心里想:“这还不简单,起码在首页搞个活动页... ”。 技术小T: 很快了解了产品的需求,目前小J主要负责这块,找了前端和后端同学一起将活动页搞的快差不多了。 业务场景一出现 : 因为小T刚接手项目,正在吭哧吭哧对熟悉着代码、部署架构。在看代码过程中发现,下单这块代码可能会出现问题,这可是分布式部署的,如果多个用户同时购买同一个商品,就可能导致商品出现 库存超卖 (数据不一致) 现象,对于这种情况代码中并没有做任何控制。 原来一问才知道,以前他们都是售卖的虚拟商品,没啥库存一说,所以当时没有考虑那么多... 这次不一样啊,这次是售卖的实体商品,那就有库存这么一说了,起码要保证不能超过库存设定的数量吧。 小T大眼对着屏幕,屏住呼吸,还好提前发现了这个问题,赶紧想办法修复,不赚钱还赔钱

Redis-技术汇总

跟風遠走 提交于 2020-01-07 16:34:05
Redis Redis-优势总结 1 性能高,读每秒是11w,写每秒是8w 2 丰富的数据结构,支持string,list,set,hash,sortedset 3 原子性操作,要不全部成功,要不全部失败 4 发布与订阅,完成类似队列功能 5 分布式锁的内在支持 6 高可用,高性能,支持集群,支持哨兵,支持读写分离 Redis-使用场景 数据缓存(商品数据、新闻、热点数据) 单点登录 秒杀、抢购 网站访问排名,排行榜 应用的模块开发 Redis-RESP协议 Redis 的客户端和服务端之间采取了一种独立名为 RESP(REdis Serialization Protocol) 的协议,它的特点是容易实现和解析快,可读性强 在 RESP 中, 一些数据的类型通过它的第一个字节进行判断: 单行回复:回复的第一个字节是 “+” 错误信息:回复的第一个字节是 “-” 整形数字:回复的第一个字节是 “:” 多行字符串:回复的第一个字节是 “$” 数组:回复的第一个字节是 “*” 举例 比如使用set命令, SET simpleKey simpleValue, 3 代表有三个字符串 9 代表有九个字符串 11 代表有十一个字符串 \\r\\n代表空格和换行 *3\\r\\n$3\\r\\nSET\\r\\n$9\\r\\nsimpleKey\\r\\n$11\\r\\nsimpleValue

springboot + redis + 注解 + 拦截器 实现接口幂等性校验(转)

帅比萌擦擦* 提交于 2020-01-06 21:59:49
出处:   作者:wangzaiplus    www.jianshu.com/p/6189275403ed 一、概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能多次创建订单 支付接口, 重复支付同一笔订单只能扣一次钱 支付宝回调接口, 可能会多次回调, 必须处理重复回调 普通表单提交接口, 因为网络超时等原因多次点击提交, 只能成功一次 等等 二、常见解决方案 唯一索引 -- 防止新增脏数据 token机制 -- 防止页面重复提交 悲观锁 -- 获取数据的时候加锁(锁表或锁行) 乐观锁 -- 基于版本号version实现, 在更新数据那一刻校验数据 分布式锁 -- redis(jedis、redisson)或zookeeper实现 状态机 -- 状态变更, 更新数据时判断状态 三、本文实现   本文采用第2种方式实现, 即通过redis + token机制实现接口幂等性校验 四、实现思路 为需要保证幂等性的每一次请求创建一个唯一标识 token , 先获取 token , 并将此 token 存入 redis , 请求接口时, 将此 token 放到 header 或者作为请求参数请求接口, 后端接口判断 redis 中是否存在此 token : 如果存在, 正常处理业务逻辑, 并从 redis 中删除此 token

Java并发编程核心概念一览

戏子无情 提交于 2020-01-04 05:14:49
作者博客地址 https://muggle.javaboy.org。 并行相关概念 同步和异步 同步和异步通常来形容一次方法的调用。同步方法一旦开始,调用者必须等到方法结束才能执行后续动作;异步方法则是在调用该方法后不必等到该方法执行完就能执行后面的代码,该方法会在另一个线程异步执行,异步方法总是伴随着回调,通过回调来获得异步方法的执行结果。 并发和并行 很多人都将并发与并行混淆在一起,它们虽然都可以表示两个或者多个任务一起执行,但执行过程上是有区别的。并发是多个任务交替执行,多任务之间还是串行的;而并行是多个任务同时执行,和并发有本质区别。 对计算机而言,如果系统内只有一个 CPU ,而使用多进程或者多线程执行任务,那么这种情况下多线程或者多进程就是并发执行,并行只可能出现在多核系统中。当然,对 Java 程序而言,我们不必去关心程序是并行还是并发。 临界区 临界区表示的是多个线程共享但同时只能有一个线程使用它的资源。在并行程序中临界区资源是受保护的,必须确保同一时刻只有一个线程能使用它。 阻塞 如果一个线程占有了临界区的资源,其他需要使用这个临界区资源的线程必须在这个临界区进行等待(线程被挂起),这种情况就是发生了阻塞(线程停滞不前)。 死锁\饥饿\活锁 死锁就是多个线程需要其他线程的资源才能释放它所拥有的资源,而其他线程释放这个线程需要的资源必须先获得这个线程所拥有的资源

万丈高楼平地起:阿里架构师带你吃透不一样的Redis核心原理实战

一笑奈何 提交于 2020-01-03 23:09:43
前言 随着互联网科技的不断发展,我们以前单纯直接操作数据库的方式已经不能满足现有的高性能和高并发的需求了,于是缓存技术应用而生。 Redis是互联网技术领域使用最为广泛的存储中间件,它是「Remote DictionaryService」的首字母缩写,也就是「远程字典服务」。Redis 以其超高的性能、完美的文档、简洁易懂的源码和丰富的客户端库支持在开源中间件领域广受好评。国内外很多大型互联网公司都在使用 Redis,比如 Twitter、YouPorn、暴雪娱乐、Github、StackOverflow、腾讯、阿里、京东、华为、新浪微博等等,很多中小型公司也都有应用。也可以说,对 Redis 的了解和应用实践已成为当下中高级后端开发者绕不开的必备技能 当前比较成熟的缓存技术有:MongoDB、Redis、Memcache,那么此文主要讲的是其中的Redis,也许我们在平常的工作中也用到过,但大多数也仅限于简单的使用了,可能很多的知识点我们并不知道,所以今天我们就跟着阿里技术大牛,一起重新认识一下redis吧! 以下是阿里技术大牛所整理出来的《玩转redis》文档,因为细节太多,所以只展示了目录的主旨内容,需要完整版的可以加群:328993819 免费获取, 开篇 授人以鱼不若授人以渔——Redis 可以用来做什么? 由Redis 面试想到的 小册的内容范围 Redis 可以做什么

springboot 中单机 redis 实现分布式锁

不打扰是莪最后的温柔 提交于 2020-01-03 11:38:24
在微服务中经常需要使用分布式锁,来执行一些任务。例如定期删除过期数据,在多个服务中只需要一个去执行即可。 以下说明非严格意义的分布式锁,因为 redis 实现严格意义的分布式锁还是比较复杂的,对于日常简单使用使用如下简单方法即可。即偶尔不执行任务不影响业务。 实现要点 1)获得锁、释放锁需要是原子操作。要么获取成功,要么失败。释放要么成功,要么失败 2)任务完成需要自己释放自己的锁,不能释放别人的锁。 3)锁要有过期时间限制,防止任务崩溃没有释放锁,导致其他节点无法获得锁。 4)执行节点超时长时间不释放锁,到下次任务开始执行并行存在的情况 要考虑的风险点 1)获取锁失败,偶尔不执行任务要不影响业务或告警人工干预 2)redis 宕机,导致无法获取锁 方案一:低版本使用 jedis 实现 1 添加依赖,高版本或低版本有些方法可能没有 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>compile</scope></dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.10.2</version><

redis 的相关知识点

半腔热情 提交于 2020-01-03 02:16:11
1、为什么使用redis 使用redis,主要是从两个角度去考虑:性能和并发。当然,redis还具备可以做分布式锁等其他功能,但是如果只是为了分布式锁这些其他功能,完全还有其他中间件(如zookpeer等)代替,并不是非要使用redis。因此,这个问题主要从性能和并发两个角度去答。 回答:如下所示,分为两点 (一)性能 我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。 题外话:忽然想聊一下这个迅速响应的标准。其实根据交互效果的不同,这个响应时间没有固定标准。不过曾经有人这么告诉我:"在理想状态下,我们的页面跳转需要在瞬间解决,对于页内操作则需要在刹那间解决。另外,超过一弹指的耗时操作要有进度提示,并且可以随时中止或取消,这样才能给用户最好的体验。 (二)并发 在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。 2、使用redis有什么缺点 分析:大家用redis这么久,这个问题是必须要了解的,基本上使用redis都会碰到一些问题,常见的也就几个。 回答:主要是四个问题 (一)缓存和数据库双写一致性问题 (二)缓存雪崩问题 (三)缓存击穿问题 (四)缓存的并发竞争问题 3

redis实战(二)

眉间皱痕 提交于 2020-01-02 20:57:43
redis使用场景(String) 上文中我们讲到redis一共有5中数据结构(String,Hash,List,Set,Zset),大家了解到了其底层数据结构以及存储方式,那这五种数据结构怎么使用呢?本期带大家了解下redis各种数据结构的使用场景。 命令介绍 String类型作为我们开发日常使用redis时可谓是最常用的场景,简单的key-value的的存储不仅简单而且方便,常用作缓存某些热点数据(key-Json)、计数器(限流)、分布式锁等。这里只列举常用命令 //缓存热点数据 key-jsonString #设置mykey的值为hello 默认的过时时间-1永久 通过EX 指定超时时间 set mykey hello #获取mykey的值 get mykey (return : hello) //计数器 #设置mykey 10 set mykey 10 #incr 对key的值进行加1操作 incrby x 指定加x操作 incr mykey (return : 11) #程序中如果将redis中key值先拿出来 再加1 会出现线程安全问题 需要使用lua脚本解决此问题(将操作原子化 详情看使用场景) //分布式锁 #setnx 如果key不存在则插入 如果存在不做任何操作 setnx mykey hello (return : 1) setnx mykey world

redis如何实现分布式锁?

谁说我不能喝 提交于 2020-01-02 08:07:51
1.分布式锁需要解决的问题 互斥性:任意时刻只能有一个客户端拥有锁,不能同时多个客户端获取 安全性:锁只能被持有该锁的用户删除,而不能被其他用户删除 死锁:获取锁的客户端因为某些原因而宕机,而未能释放锁,其他客户端无法获取此锁,需要有机制来避免该类问题的发生 容错:当部分节点宕机,客户端仍能获取锁或者释放锁 2.如何通过Redis实现分布式锁:(非完善方法) SETNX key value :如果key不存在,则创建并赋值 时间复杂度: 0(1) 返回值:设置成功,返回1;设置失败,返回0。 但是此时我们获取的key是长期有效的,所以我们应该如何解决长期有效的问题呢? 如何解决SETNX长期有效的问题 EXPIRE key seconds 设置key的生存时间,当key过期时(生存时间为0) ,会被自动删除 缺点:原子性得不到满足 下面是伪代码 //该程序存在危险,如果执行到第二行就崩溃了,则此时key会被一直占用而无法被释放 RedisService redisService = SpringUtils.getBean(Redi sService.class); long status = redisService.setnx(key, "1"); if(status == 1) { redisService.expire(key, expire); //执行独占资源逻辑

java操作redis学习笔记

天大地大妈咪最大 提交于 2020-01-02 05:11:15
一、 jedis 操作: 1、POM依赖: 1 <dependency> 2 <groupId>redis.clients</groupId> 3 <artifactId>jedis</artifactId> 4 <version>2.5.0</version> 5 </dependency> 2、 建一个连接 redis 数据库的工具类: 1 public class RedisUtil { 2 3   //服务器IP地址 4 private static String ADDR = "x.x.x.x"; 5    6   //端口 7 private static int PORT = 6379; 8   //密码 9 private static String AUTH = "123456"; 10   //连接实例的最大连接数 11 private static int MAX_ACTIVE = 1024; 12    13   //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。 14 private static int MAX_IDLE = 200; 15    16 //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException 17 private