分布式锁

Redis分布式锁的正确实现方式

妖精的绣舞 提交于 2020-02-01 05:17:09
转载至:https://www.cnblogs.com/linjiqin/p/8003838.html 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。 代码实现 组件依赖 首先我们要通过Maven引入Jedis开源组件,在pom.xml文件加入下面的代码: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> 加锁代码 正确姿势 Talk is

Redis实现分布式锁

…衆ロ難τιáo~ 提交于 2020-02-01 03:05:36
Redis实现分布式锁 1.锁的处理 单应用中使用锁:单进程多线程 synchroize , Lock 分布式应用中使用的锁:多进程 2.分布式锁的实现方式 数据库的乐观锁 基于zookeeper的分布式锁 基于redis的分布式锁 3.分布式锁的注意事项 互斥性:在任意时刻,只有一个客户能持有锁 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了 避免死锁:即使有一个客户端在持有锁的期间奔溃而没有主动解锁,也能保证后续其他客户端能加锁 4.实现分布式锁 4.1获取锁 在SET命令中,有很多选项可用来修改命令的行为,以下是SET命令可用选项的基本语法 EX seconds -设置指定的到期时间以秒为单位。 PX milliseconds-设置指定的到期时间(以毫秒为单位)。 NX -仅在键不存在时设置锁。 XX-只有在键已存在时才设置。 方式1(使用set命令实现) 使用redis的set命令实现获取分布式锁 @param lockkey 可以就是锁 @param requestId 请求ID,保证同一性 @param expireTime 过期时间,避免死 方式2(使用setnx命令实现) 4.2释放锁 来源: https://www.cnblogs.com/liyalong/p/12247460.html

Redis事务与可分布式锁

♀尐吖头ヾ 提交于 2020-01-28 23:39:13
1 Redis 事务 1.1 Redis 事务介绍 l Redis 的事务是通过 MULTI , EXEC , DISCARD 和 WATCH 这四个命令来完成的。 l Redis 的单个命令都是 原子性 的,所以这里确保事务性的对象是 命令集合 。 l Redis 将命令集合序列化并确保处于同一事务的 命令集合连续且不被打断 的执行 l Redis 不支持回滚操作 1.2 相关命令 l MULTI 用于标记事务块的开始 。 Redis 会将后续的命令逐个放入队列中,然后使用 EXEC 命令 原子化地执行这个命令序列。 语法: multi l EXEC 在一个事务中执行所有先前放入队列的命令 ,然后恢复正常的连接状态 语法: exec l DISCARD 清除所有先前在一个事务中放入队列的命令 ,然后恢复正常的连接状态。 语法: discard l WATCH 当某个 事务需要按条件执行 时,就要使用这个命令将给定的 键设置为受监控 的状态。 语法: watch key [key…] 注意事项: 使用该命令可以实现 redis 的 乐观锁 。 l UNWATCH 清除所有先前为一个事务监控的键。 语法: unwatch 1.3 事务失败处理 l Redis 语法错误(可以理解为 编译期错误 ) l Redis 类型错误(可以理解为 运行期错误 ) l Redis 不支持事务回滚

redis使用场景

给你一囗甜甜゛ 提交于 2020-01-27 12:08:38
String应用场景 #单值缓存 set key value get key # 对象缓存 set object '{"name":"ws","age":"18"}' get object mset object:name ws object:age 18 mget object:name object:age # 分布式锁 setnx key true //返回1代表成功,0代表失败 .. .执行业务逻辑 del key //执行完成释放锁 set key value ex seconds nx //防止程序意外终止导致死锁 # 计数器 incr key get key # Web集群session共享 redis存储sessionId及信息实现session共享 # 分布式全局序列号 incrby key increment Hash应用场景 一般对象用string + json存储,对象中某些频繁变化的属性抽出来用hash存储,比如电商购物车就可以用hash实现 # 模型设计 用户ID为key 商品ID为field 数量为value # 购物车常用操作 添加商品 hset userid productid 1 删除商品 hdel userid productid 增加数量 hincrby userid productid 1 减小数量 hincrby userid

分布式锁 原理及实现方式

纵饮孤独 提交于 2020-01-27 00:03:47
一、原理 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致性,在这种情况下,就需要使用分布式锁了。 在平时的实际项目开发中,我们往往很少会去在意分布式锁,而是依赖于关系型数据库固有的排他性来实现不同进程之间的互斥,但大型分布式系统的性能瓶颈往往集中在数据库操作上。 在单机环境中,Java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就是说单纯的Java Api并不能提供分布式锁的能力。 其实秒杀类场景最主要的是执行秒杀操作要单线程的,提到单线程,肯定会想到synchronized关键字,但是他有两个致命缺点:1、无法做到细粒度控制,2、只适合单点不适用集群。 所以大多数项目只能采用分布式锁的实现方式。 针对分布式锁的实现,目前比较常用的有以下几种方案:     基于数据库实现分布式锁     基于缓存(redis,memcached,tair)实现分布式锁     基于Zookeeper实现分布式锁 分布式锁主要有基于缓存如redis、基于zookeeper、基于数据库的实现。 在分析这几种实现方案之前我们先来想一下,我们需要的分布式锁应该是怎么样的?(这里以方法锁为例,资源锁同理)     

redis 是什么?都有哪些使用场景?

不想你离开。 提交于 2020-01-26 20:36:28
一、什么是redis 首先要说redis,应该先说一下nosql, NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”, 泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。 (例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。 Redis:REmote DIctionary Server(远程字典服务器)是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。 二、redis使用场景 1、热点数据的缓存 由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据,另外结合expire,我们可以设置过期时间然后再进行缓存更新操作,这个功能最为常见,我们几乎所有的项目都有所运用。

java redis分布式锁

我们两清 提交于 2020-01-26 04:42:36
public class RedisDistributedLock { private static final String LOCK_SUCCESS = "OK"; private static final Long RELEASE_SUCCESS = 1L; private static int WAIT_TIME = 1 * 1000; private static String EVAL_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; public String lock(Jedis jedis, String key) { try { // 超过等待时间,加锁失败 long waitEnd = System.currentTimeMillis() + WAIT_TIME; String value = UUID.randomUUID().toString(); while (System.currentTimeMillis() < waitEnd) { String result = jedis.set(key, value, "NX", "PX", 1000); if (LOCK_SUCCESS

分布式锁,进程锁,线程锁到底是什么

故事扮演 提交于 2020-01-26 02:49:29
在分布式集群系统的开发中,线程锁往往并不能支持全部场景的使用,必须引入新的技术方案分布式锁。   线程锁:大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。   进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制(操作系统基本知识)。   分布式锁:当多个进程不在同一个系统之中时,使用分布式锁控制多个进程对资源的访问。 分布式锁到底是什么,怎么实现?   intsmaze说简单点,实现分布式锁必须要依靠第三方存储介质来存储锁的元数据等信息。比如分布式集群要操作某一行数据时,这个数据的流水号是唯一的,那么我们就把这个流水号作为一把锁的id,当某进程要操作该数据时,先去第三方存储介质中看该锁id是否存在,如果不存在,则将该锁id写入,然后执对该数据的操作;当其他进程要访问这个数据时,会先到第三方存储介质中查看有没有这个数据的锁id,有的话就认为这行数据目前已经有其他进程在使用了,就会不断地轮询第三方存储介质看其他进程是否释放掉该锁

非关系型数据库--Redis

时光总嘲笑我的痴心妄想 提交于 2020-01-26 00:51:55
一、什么是Redis? Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求。目前为止Redis支持的键值数据类型如下: 二、Redis支持的键值数据类型: 1、 字符串类型(String),常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。 2、 散列类型(hash),value存放的是结构化的对象,比较方便的就是操作其中的某个字段。ps:hash被(string和json)取代了 3、 列表类型(list),使用List的数据结构,可以做简单的消息队列的功能。 4、 集合类型(set),set堆放的是一堆不重复值的集合,可以做全局去重的功能。 5、 有序集合类型(sorted set sorted set),多了一个权重参数score,集合中的元素能够按score进行排列。可以做范围查找。 三、redis的可以应用于哪些地方? 1、缓存(数据查询、短连接、新闻内容、商品内容等等)。 2、聊天室的在线好友列表。 3、任务队列。(秒杀、抢购、等) 4、应用排行榜。 5、网站访问统计。 6、数据过期处理(可以精确到毫秒) 7、分布式集群架构中的session分离。 四、为什么使用redis(优点)? 1、性能 ,我们在碰到需要执行耗时特别久

锁相关之---redis的分布式锁(redission实现分布式锁)

旧巷老猫 提交于 2020-01-25 05:27:37
分布式锁的实现: 基于redis的单线程机制及redis中的setnx方法实现的; 存在的问题: 1,可能会出现key失效的可能性; 2,可能出现key永生导致接口一直无法被调用; 解决方案1: 入锁:通过setnx方法,然后通过explain加入key对应的失效时间,防止key永生;再接口调用完成最后提交事务的时候,通过get方法校验当前key是否存在,如果不存在直接抛出异常回滚,默认本次调用不安全; 解决方案2,基于redssion的解决方案: 基于redssion可以设置等待锁的时间,及锁的失效时间。 @Override public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException { long time = unit.toMillis(waitTime); long current = System.currentTimeMillis(); final long threadId = Thread.currentThread().getId(); // 尝试获取锁,并返回剩余超时时间 Long ttl = tryAcquire(leaseTime, unit, threadId); // lock acquired //