百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

压箱底Redis面试集 -22.Redis 的 Red Lock 是什么?你了解吗?

mhr18 2024-11-03 13:44 29 浏览 0 评论

在分布式系统的广袤世界中,确保资源的安全访问和操作的一致性如同在汹涌波涛中驾驭一艘平稳的航船,而 Redis 的 Red Lock 就是我们手中那关键的舵轮,引领我们驶向稳定与可靠的彼岸。

一、揭开 Red Lock 的神秘面纱

Red Lock 是一种在分布式环境下实现高可靠分布式锁的算法。传统的基于单个 Redis 节点的分布式锁存在一些潜在的风险,比如当 Redis 节点发生故障时,可能会导致锁的失效或者误判。而 Red Lock 则通过在多个独立的 Redis 节点上进行操作,极大地提高了分布式锁的可靠性和安全性。

想象一下一个繁忙的在线交易平台,多个交易处理程序同时在不同的服务器上运行,它们都需要对同一个关键的交易数据进行操作。如果没有一个强大的分布式锁机制,就可能会出现数据冲突、交易失败甚至是系统崩溃的情况。Red Lock 就像是一个坚固的堡垒,守护着这些关键资源,确保只有一个合法的程序能够在特定的时间内访问和修改这些数据。

二、Red Lock 的工作原理

Red Lock 算法的核心思想是通过在多个 Redis 节点上同时获取锁,并且只有当在大多数节点上都成功获取锁时,才认为真正获取了锁。在释放锁时,也需要向所有的节点发送释放锁的请求。

具体来说,它的工作流程如下:

  1. 客户端首先获取当前时间戳。
  2. 然后依次向多个 Redis 节点发送获取锁的请求,每个请求都带有一个超时时间(这个超时时间要远远小于锁的有效时间)。
  3. 当客户端在大多数节点上都成功获取了锁,并且获取锁的总时间小于锁的有效时间时,就认为成功获取了锁。此时,客户端开始执行关键业务逻辑。
  4. 在锁过期之前,客户端需要不断地延长锁的有效时间,以防止锁意外过期。
  5. 当业务逻辑执行完成后,客户端向所有的节点发送释放锁的请求。

三、Java 中的 Red Lock 实践

下面我们通过一个 Java 示例来看看如何使用 Red Lock 来保护关键资源的访问。

首先,我们需要一个连接到 Redis 节点的工具类:

import redis.clients.jedis.Jedis;

public class RedisConnectionUtil {

    public static Jedis connectToRedis(String host, int port) {
        return new Jedis(host, port);
    }
}

然后,我们实现一个 Red Lock 的类:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class RedLock {

    private final int numNodes;
    private final List<Jedis> nodes;
    private final int lockTimeoutMillis;

    public RedLock(int numNodes, int lockTimeoutSeconds) {
        this.numNodes = numNodes;
        this.lockTimeoutMillis = lockTimeoutSeconds * 1000;
        this.nodes = new ArrayList<>();
        for (int i = 0; i < numNodes; i++) {
            // 假设我们有多个 Redis 节点,这里可以根据实际情况配置节点的地址和端口
            Jedis jedis = RedisConnectionUtil.connectToRedis("localhost", 6379 + i);
            nodes.add(jedis);
        }
    }

    public String acquireLock(String resourceKey, String clientId) {
        long startTime = System.currentTimeMillis();
        List<String> lockKeys = new ArrayList<>();

        while (System.currentTimeMillis() - startTime < lockTimeoutMillis) {
            int successCount = 0;

            for (Jedis node : nodes) {
                String lockKey = "lock:" + resourceKey;
                String result = node.set(lockKey, clientId, "NX", "PX", lockTimeoutMillis);
                if ("OK".equals(result)) {
                    successCount++;
                    lockKeys.add(lockKey);
                }
            }

            if (successCount >= (numNodes / 2 + 1)) {
                return clientId;
            } else {
                // 释放已经获取的锁
                for (String lockKey : lockKeys) {
                    Jedis node = findNodeByLockKey(lockKey);
                    if (node!= null) {
                        node.del(lockKey);
                    }
                }
            }

            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return null;
            }
        }

        return null;
    }

    public boolean releaseLock(String resourceKey, String clientId) {
        int successCount = 0;

        for (Jedis node : nodes) {
            String lockKey = "lock:" + resourceKey;
            String value = node.get(lockKey);
            if (clientId.equals(value)) {
                node.del(lockKey);
                successCount++;
            }
        }

        return successCount >= (numNodes / 2 + 1);
    }

    private Jedis findNodeByLockKey(String lockKey) {
        for (Jedis node : nodes) {
            if (node.exists(lockKey)) {
                return node;
            }
        }
        return null;
    }
}

最后,我们可以在一个实际的业务场景中使用 Red Lock:

public class MainApp {

    public static void main(String[] args) {
        int numNodes = 5;
        int lockTimeoutSeconds = 10;
        RedLock redLock = new RedLock(numNodes, lockTimeoutSeconds);

        String resourceKey = "myResource";
        String clientId = "uniqueClientId";

        String lockResult = redLock.acquireLock(resourceKey, clientId);
        if (lockResult!= null) {
            try {
                // 执行关键业务逻辑
                System.out.println("Processing the resource...");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                boolean releaseSuccess = redLock.releaseLock(resourceKey, clientId);
                if (releaseSuccess) {
                    System.out.println("Lock released successfully.");
                } else {
                    System.out.println("Failed to release the lock.");
                }
            }
        } else {
            System.out.println("Failed to acquire the lock.");
        }
    }
}

在这个示例中,我们首先创建了一个包含多个 Redis 节点的 Red Lock 对象。然后,在 main 方法中,尝试获取锁并执行关键业务逻辑,最后释放锁。通过这种方式,我们可以在分布式环境下安全地对关键资源进行操作,避免了资源的冲突和错误。

四、总结

Redis Red Lock 为我们提供了一种在分布式系统中实现高可靠分布式锁的解决方案。它通过在多个节点上的协同工作,确保了锁的安全性和可靠性。在实际的应用开发中,我们可以根据具体的业务需求和系统架构,灵活地运用 Red Lock 来保护关键资源的访问,为分布式系统的稳定运行提供有力的保障。让我们借助 Red Lock 的力量,在分布式的海洋中畅游无阻,创造出更加稳定、高效的应用程序。

上一篇:压箱底Redis面试集 -21.如何避免 Redis 分布式锁的死锁问题?

下一篇:压箱底Redis面试集 -23.Redis 的 Lua 脚本功能是什么?如何使用?

相关推荐

Java面试题及答案总结(2025版)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Redis、Linux、SpringBoot、Spring、MySQ...

Java面试题及答案最全总结(2025春招版)

大家好,我是Java面试分享最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Spring...

Java面试题及答案最全总结(2025版持续更新)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...

蚂蚁金服面试题(附答案)建议收藏:经典面试题解析

前言最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答。点击上方“捡田螺的小男孩”,选择“设为星标”,干货不断满满1.用到分布式事务嘛?为什么用这种方案,有其他方案...

测试工程师面试必问的十道题目!全答上来的直接免试

最近参加运维工程师岗位的面试,笔者把自己遇到的和网友分享的一些常见的面试问答收集整理出来了,希望能对自己和对正在准备面试的同学提供一些参考。一、Mongodb熟悉吗,一般部署几台?部署过,没有深入研究...

10次面试9次被刷?吃透这500道大厂Java高频面试题后,怒斩offer

很多Java工程师的技术不错,但是一面试就头疼,10次面试9次都是被刷,过的那次还是去了家不知名的小公司。问题就在于:面试有技巧,而你不会把自己的能力表达给面试官。应届生:你该如何准备简历,面试项目和...

java高频面试题整理

【高频常见问题】1、事务的特性原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。一致性或可串性:事务的执行使得数据库从一种正确状态转换成另一种正确状态隔离性:在事务正确提交之前,不允许把该...

2025 年最全 Java 面试题,京东后端面试面经合集,答案整理

最近京东搞了个TGT计划,针对顶尖青年技术天才,直接宣布不设薪资上限。TGT计划面向范围包括2023年10月1日到2026年9月30日毕业的海内外本硕博毕业生。时间范围还...

idGenerator测评

工作中遇到需要生成随机数的需求,看了一个个人开发的基于雪花算法的工具,今天进行了一下测评(测试)。idGenerator项目地址见:https://github.com/yitter/IdGenera...

2024年开发者必备:MacBook Pro M1 Max深度体验与高效工作流

工作机器我使用的是一台16英寸的MacBookProM1Max。这台电脑的表现堪称惊人!它是我用过的最好的MacBook,短期内我不打算更换它。性能依然出色,即使在执行任务时也几乎听不到风扇的...

StackOverflow 2022 年度调查报告

一个月前,StackOverflow开启了2022年度开发者调查,历时一个半月,在6月22日,StackOverflow正式发布了2022年度开发者调查报告。本次报告StackO...

这可能是最全面的SpringDataMongoDB开发笔记

MongoDB数据库,在最近使用越来越广泛,在这里和Java的开发者一起分享一下在Java中使用Mongodb的相关笔记。希望大家喜欢。关于MongoDB查询指令,请看我的上一篇文章。SpringD...

Mac M2 本地部署ragflow

修改配置文件Dockerfile文件ARGNEED_MIRROR=1//开启国内镜像代理docker/.envREDIS_PORT=6380//本地redis端口冲突RAGFLOW_IMA...

别再傻傻分不清!localhost、127.0.0.1、本机IP,原来大有讲究!

调试接口死活连不上?部署服务队友访问不了?八成是localhost、127.0.0.1、本机IP用混了!这三个看似都指向“自己”的东西,差之毫厘谬以千里。搞不清它们,轻则调试抓狂,重则服务裸奔。loc...

我把 Mac mini 托管到机房了:一套打败云服务器的终极方案

我把我积灰的Macmini托管到机房了,有图有真相。没想到吧?一台在家吃灰的苹果电脑,帮我省了大钱!对,就是控制了自己的服务器,省了租用云服务器的钱,重要数据还全捏在自己手里,这感觉真爽。你可...

取消回复欢迎 发表评论: