一 前言
redis在分布式应用十分广泛,本篇文章也是互联网面试的重点内容,读者至少需要知道为什么需要分布式锁,分布式锁的实现原理,分布式锁的应用场景,在使用分布式锁时遇到哪些问题?你是如何解决的,如果读者能掌握以上问题,那么关于这道面试题,你也就基本过关了;
二 分布式锁的产生背景
分布式锁对应的是多个应用,每个应用中都可能会处理相同的数据,如果多个应用对用一个操作进行了重复操作,就会出现数据不一致,数据重复问题,于是分布式锁应用而生,通常你可以理解为多线程中的synchronized
三 分布式锁的应用场景
多台机器都能执行某个任务,如果限制任务每次只能被一台机器执行,不能重复执行,就可以用分布式锁来做标记秒杀场景,要求并发量很高,那么同一件商品只能被一个用户抢到,就可以使用分布式锁实现比较敏感的数据比如金额修改,同一时间只能有一个人操作,如果2个人同时修改金额,一个加一个减金额,为了防止同时操作造成数据不一致,就可以使用分布式锁实现
四 分布式锁的实现
4.1 分布式锁的实现方式
4.2 分布式锁使用原理
每个应用对敏感数据进行操作时都需要向获取一个锁,持有锁的应用才能对数据进行操作,保证在同一时间内只有一台应用能对数据进行操作;
4.3 分布式锁实现过程
基本实现思路:
redis分布式实现是基于 命令setnx key value , 其意指 若该键不存在则创建键,这就保证了redis中只有一个该键,故应用谁先获得该键,谁就拿到了锁的权限;然后业务逻辑执行完毕则需要使用 del key 删除键,表示释放锁;
出现了问题:
如果一台业务逻辑执行完毕,程序出现异常,则锁会一直存在,没有得到释放,其它应用就会无法获得锁,此时就会造成死锁问题;
改进方式:
拿到锁之后,给锁加上一个过期时间,也就是 expire key seconds 指令;此时避免了死锁问题,但是由于业务逻辑执行的时间不同,过期的时间设置也是一个问题,故通常分布式锁不能应用于业务逻辑执行较长的程序;
出现问题:
由于redis 每条指令都是原子性操作,但由于setnx 和 expire 是2 条指令,如果在执行setnx后程序出现问题expire指令未得到执行就会造成死锁问题;
解决问题:
redis2.8版本之后引入了指令 set key value [EX seconds] [PX milliseconds] [NX|XX] ,该指令可以同时执行 setnx 和 expire ,于是解决了死锁问题;
参数列表解释
使用jedis客户端实现分布式锁方式
public boolean lock(Jedis jedis,String key,String val,int expireTime){ String lock = jedis.set(key, val, "NX", "PX", expireTime); return "OK".equals(lock); }
关于未获得锁的解决思路:
可以直接抛出异常让客户重试
可以使用延迟队列
五 分布式锁的超时问题
问题:
如果在加锁和释放锁之间,业务逻辑执行时间太长,导致超出了锁的超时限制,就会出现锁过期问题;换句话说,就是第一台应用执行了业务,导致锁过期;第二台应用此时可以获得锁,进行执行业务,此时第一台应用释放了锁,第二台应用在执行业务的时第三台应用获得了锁执行业务,导致在执行过程中,会有2台应用在同时执行业务逻辑;
解决思路:
在释放锁的时候出现了问题,即每台应用都可以释放锁,这会造成1应用的锁释放了2应用锁的问题,换句话说,很多人手中持有的钥匙是通用的,都可以开同一个门;为了避免这个问题,就是1 应用只能释放1应用上的锁,2应用只能释放2应用上的锁,则需要对释放锁进行身份校验;由于上锁的时候key是唯一,但value可以不同,所以可以根据value进行身份的唯一标识,随机数就是一个很好的选择 :
String value = UUID.randomUUID().toString();
由于考虑到匹配到value校验和del不是同一个操作,故需要使用Lua脚本实现多条指令的原子性执行;
jedis释放锁实现方式:
public void unlock(Jedis jedis,String key,String value) { String script_command = "if redis.call('get',KEYS[1]) == ARGV[1] then " + "return redis.call('del',KEYS[1]) else return 0 end"; // 解锁 jedis.eval(script_command, Collections.singletonList(key), Collections.singletonList(value)); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
背景 在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等。大部分的解决方案是基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制。 一、使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以
问题内容: 因此,我刚刚阅读了有关redlock的文章。据我了解,它需要3台独立的机器才能工作。独立表示它们是指所有计算机都是主计算机,并且它们之间没有复制,这意味着它们正在提供不同类型的数据。那么,为什么我需要锁定在充当主服务器的三个独立Redis实例中存在的密钥?我需要使用redlock的用例是什么? 问题答案: 那么,为什么我需要锁定在三个独立的Redis实例中充当主键的密钥? 这并不是说您
一个挺着啤酒肚,身穿格子衫,发际线严重后移的中年男子,手拿着保温杯,胳膊夹着MacBook向你走来,看样子是架构师级别。 面试开始, 直入正题。 面试官: 你有没有参与过秒杀系统的设计? 我: 没有,我平时都是开发后台管理系统、OA办公系统、内部管理系统,从来没有开发过秒杀系统。 面试官: 嗯...,小伙子很实诚。今天就先到这里吧,后面有消息会主动联系你。 后面还可能有消息吗?你们啥时候主动联系过
使用Redis实现分布式锁 redis命令:set users 10 nx ex 12 原子性命令 //使用uuid,解决锁释放的问题 @GetMapping public void testLock() throws InterruptedException { String uuid = UUID.randomUUID().toString(); Boolean b_loc
本文向大家介绍Redis 怎么实现分布式锁?相关面试题,主要包含被问及Redis 怎么实现分布式锁?时的应答技巧和注意事项,需要的朋友参考一下 Redis 分布式锁其实就是在系统里面占一个“坑”,其他程序也要占“坑”的时候,占用成功了就可以继续执行,失败了就只能放弃或稍后重试。 占坑一般使用 setnx(set if not exists)指令,只允许被一个程序占有,使用完调用 del 释放锁。
主要内容:Redis分布式锁介绍,Redis分布式锁命令在分布式系统中,当不同进程或线程一起访问共享资源时,会造成资源争抢,如果不加以控制的话,就会引发程序错乱。此时使用分布式锁能够非常有效的解决这个问题,它采用了一种互斥机制来防止线程或进程间相互干扰,从而保证了数据的一致性。 提示:如果对分布式系统这一概念不清楚,可参考百度百科《分布式系统》,简而言之,它是一种架构、一种模式。 Redis分布式锁介绍 分布式锁并非是 Redis 独有,比如 MySQ
本文向大家介绍单机redis分布式锁实现原理解析,包括了单机redis分布式锁实现原理解析的使用技巧和注意事项,需要的朋友参考一下 最近我们有个服务经常出现存储的数据出现重复,首先上一个系统流程图: 用户通过http请求可以通知任务中心结束掉自己发送的任务,这时候任务中心会通过MQ通知结束服务去结束任务保存数据,由于任务结束数据计算保存有一定延时,所以存在用户短时间内多次结束同一个任务,这时候就会
分布式锁常见的三种实现方式: 数据库乐观锁; 基于Redis的分布式锁; 基于ZooKeeper的分布式锁。 要点 Redis要实现分布式锁,以下条件应该得到满足 互斥性 在任意时刻,只有一个客户端能持有锁。 不能死锁 客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 容错性 只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。 实现 可以直接通过 set key v