Redis分布式锁的一次实践

简介: 分布式锁背景介绍在开发中,多线程场景,即多个线程共同去竞争同一个资源,我们为了避免出现线程不安全,常常采用Lock去锁住需要被线程共享的资源,常用的锁比如Synchronized和Reentrantlock。

分布式锁背景介绍

在开发中,多线程场景,即多个线程共同去竞争同一个资源,我们为了避免出现线程不安全,常常采用Lock去锁住需要被线程共享的资源,常用的锁比如Synchronized和Reentrantlock。在分布式的场景中,多台机器上的程序,需要实现Lock锁这个功能。
avatar
常见的有下面解决方案,一是使用Redis的setnx,二是使用Zookeeper的持久节点下为每个客户端访问时创建临时顺序节点。直接使用在Java代码中使用Zookeeper不太方便。所以在开发中选择了使用Redis的方案。

业务场景介绍

在进行开发虚拟货币交易所时,由于不像股票交易,一支股票在哪个交易所上市,就只能在此上市交易所交易,显示价格等,如在上交所上市,就只需要调用上交所API,不会出现去深交所调用。而虚拟币不一样,虚拟币可以在全球各大交易所都有交易。所以在开发虚拟货币交易的时候,获取价格需要通过定时任务,调用多个交易所的API。而很多交易所,对API调用频率会进行限制,在分布式服务中,会产生多个节点同时访问,导致超过对方交易所的调用频率,从而被对方交易所封禁。所以我们需要运用Redis分布式锁,保证同一时刻,只有一个节点进行访问请求。代码如下

 ThreadPoolTaskExecutor singleThreadExecutor = new ThreadPoolTaskExecutor();

    public static final int INTERVAL = 30;

    @PostConstruct
    public void circleGetPrice() {
        singleThreadExecutor = ThreadExecutorUtil.newSingleThreadExecutor("ZBPriceTaskThread-");
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("ZBPriceTask circleGetPrice running...");
                while (true) {
                    try {
                        long setnx = CodisConnector.setnx(ZBConstans.GET_PRICE_TASK_NAME, INTERVAL, ZBConstans.GET_PRICE_TASK_NAME);
                        if (setnx == 1) {
                            getXlmPrice();
                        }

                    } catch (Exception e) {
                        log.error("ZBPriceTask circleGetPrice error", e);
                    }
                    try {
                        Thread.sleep(INTERVAL * 1000L);
                    } catch (InterruptedException e) {
                    }
                }
            }
        });
    }
   

这里用了,我们团队自己对jedis进行封装的工具类,底层其实也是jedis。这里进行重载了两个方法。

 public static long setnx(String key, String value) {
        Jedis jedis = pool.getResource();
        try {
            return jedis.setnx(key, value);
        } catch (Exception e) {
            logger.error(e);
        } finally {
            jedis.close();
        }
        return -1L;
    }

    public static long setnx(String key, int expire, String value) {
        Jedis jedis = pool.getResource();
        try {

            if ("OK".equals(jedis.set(key, value, "NX", "EX", expire))) {
                return 1;
            }
            return 0;

        } catch (Exception e) {
            logger.error("codis异常:", e);
        } finally {
            jedis.close();
        }
        return -1L;
    }

解释

setnx(key, value)

如setnx(key, 1)当一个节点执行setnx返回value为1,则成功获得锁,执行代码完成后,再调用del方法。若返回!=1,则当前有其他节点执有锁。继续等待。
但这有一个致命的缺陷,若当前执有锁的节点,在执行代码时,死掉了,而没有来得及释放了锁。则其他所有节点,都会拿不到锁。造成死锁等待。所以redis又提供了另外一种方法。

set(key, value,expire,NX)

通过设置expire过期时间,当持有锁的节点,超时的时候,锁自动释放,从而避免死锁的现象。当然在此场景中,只有访问对方交易所价格API出现超时,这一种情况,所以对于原子性,没有太大的要求。

目录
相关文章
|
2月前
|
人工智能 安全 Java
分布式 Multi Agent 安全高可用探索与实践
在人工智能加速发展的今天,AI Agent 正在成为推动“人工智能+”战略落地的核心引擎。无论是技术趋势还是政策导向,都预示着一场深刻的变革正在发生。如果你也在探索 Agent 的应用场景,欢迎关注 AgentScope 项目,或尝试使用阿里云 MSE + Higress + Nacos 构建属于你的 AI 原生应用。一起,走进智能体的新世界。
638 47
|
2月前
|
关系型数据库 Apache 微服务
《聊聊分布式》分布式系统基石:深入理解CAP理论及其工程实践
CAP理论指出分布式系统中一致性、可用性、分区容错性三者不可兼得,必须根据业务需求进行权衡。实际应用中,不同场景选择不同策略:金融系统重一致(CP),社交应用重可用(AP),内网系统可选CA。现代架构更趋向动态调整与混合策略,灵活应对复杂需求。
|
4月前
|
数据采集 消息中间件 监控
单机与分布式:社交媒体热点采集的实践经验
在舆情监控与数据分析中,单机脚本适合小规模采集如微博热榜,而小红书等大规模、高时效性需求则需分布式架构。通过Redis队列、代理IP与多节点协作,可提升采集效率与稳定性,适应数据规模与变化速度。架构选择应根据实际需求,兼顾扩展性与维护成本。
126 2
|
4月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
373 2
|
4月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
324 6
|
3月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
308 86
|
3月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的"神经网络",强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
3月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
255 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
3月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
3月前
|
存储 缓存 监控
Redis分区的核心原理与应用实践
Redis分区通过将数据分散存储于多个节点,提升系统处理高并发与大规模数据的能力。本文详解分区原理、策略及应用实践,涵盖哈希、范围、一致性哈希等分片方式,分析其适用场景与性能优势,并探讨电商秒杀、物联网等典型用例,为构建高性能、可扩展的Redis集群提供参考。
205 0