基于单机redis的分布式锁实现

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 最近我们有个服务经常出现存储的数据出现重复,首先上一个系统流程图: 用户通过http请求可以通知任务中心结束掉自己发送的任务,这时候任务中心会通过MQ通知结束服务去结束任务保存数据,由于任务结束数据计算保存有一定延时,所以存在用户短时间内多次结束同一个任务,这时候就会导致我们结束服务对同一个任务保存

基于单机redis的分布式锁实现



最近我们有个服务经常出现存储的数据出现重复,首先上一个系统流程图:


 

用户通过http请求可以通知任务中心结束掉自己发送的任务,这时候任务中心会通过MQ通知结束服务去结束任务保存数据,由于任务结束数据计算保存有一定延时,所以存在用户短时间内多次结束同一个任务,这时候就会导致我们结束服务对同一个任务保存多次数据。恰好我们也是用了redis,所以对于这个问题我当时想到使用分布式锁来解决,那么如何用redis实现分布式锁呢?


首先要明确一个分布式锁应具备的原则:


  1. 互斥性。在任意时刻,只有一个客户端能持有锁;


  1. 不会发生死锁。即使一个客户端持有锁的期间崩溃而没有主动释放锁,也需要保证后续其他客户端能够加锁成功;


  1. 加锁和解锁必须是同一个客户端;


  1. 有高可用的获取锁和释放锁功能。


由于我们只使用了单机的redis,所以本文的实现不具备第四点原则。


我们这个锁的实现就包括两点:加锁、解锁。首先看加锁。先上代码:

public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) throws Exception{
        Jedis jedis = null;
        try {
            jedis = getJedisClient();
            String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        } finally {
            returnResource(jedis);
        }
 }

我们的加锁就是设置一个键值对,并且满足以下条件:


  1. 确保只有当键不存在时才设置有效;


  1. 设置的值必须是当前客户端生成的uuid;


  1. 键必须要有过期时间。


这三点条件就可以满足上述的原则1、原则2。


接下来看下解锁,代码如下:

public boolean releaseDistributedLock(String lockKey, String requestId) throws Exception{
        Jedis jedis = null;
        try {
            jedis = getJedisClient();
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }finally {
            returnResource(jedis);
        }
}


解锁是通过一段lua脚本实现,逻辑如下:


1、获取锁键值看是否与当初设置的值一致;


2、如果一致则删除键。


由于解锁过程分为两步,为了确保原子性所以通过让redis执行lua脚本来实现,校验键值可以确保加锁解锁都是同一个客户端。


这样一个简易的分布式锁就实现完毕了,当然在本文开头就说了,这个实现只能满足单机redis的情况,对于redis集群其实是不严谨的,对于redis集群有一个redlock方案,我也在研究中,后面也会总结一下。


分类: Redis

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
10天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
44 16
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
59 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
1月前
|
NoSQL Redis 数据库
计数器 分布式锁 redis实现
【10月更文挑战第5天】
48 1
|
1月前
|
NoSQL 算法 关系型数据库
Redis分布式锁
【10月更文挑战第1天】分布式锁用于在多进程环境中保护共享资源,防止并发冲突。通常借助外部系统如Redis或Zookeeper实现。通过`SETNX`命令加锁,并设置过期时间防止死锁。为避免误删他人锁,加锁时附带唯一标识,解锁前验证。面对锁提前过期的问题,可使用守护线程自动续期。在Redis集群中,需考虑主从同步延迟导致的锁丢失问题,Redlock算法可提高锁的可靠性。
74 4
|
1月前
|
缓存 NoSQL 关系型数据库
单机版Redis
【10月更文挑战第3天】
33 0
|
1月前
|
缓存 NoSQL 算法
面试题:Redis如何实现分布式锁!
面试题:Redis如何实现分布式锁!
|
缓存 NoSQL 前端开发
redis单机版安装+测试+项目运用
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
|
NoSQL Redis 数据库
【Redis】单机安装Redis
【Redis】单机安装Redis
80 0
|
存储 缓存 NoSQL
Redis概述和单机、集群安装
Redis概述和单机、集群安装
189 0
Redis概述和单机、集群安装