Redis分布式锁的实现方式、实现原理

2023-11-04

在这里插入图片描述

目录

大家好,我是哪吒。

公司想招聘一个5年开发经验的后端程序员,看了很多简历,发现一个共性问题,普遍都没用过分布式锁,这正常吗?

下面是已经入职的一位小伙伴的个人技能包,乍一看,还行,也没用过分布式锁。

午休的时候,和她聊了聊,她之前在一家对日的公司。

  1. 需求是产品谈好的;
  2. 系统设计、详细设计是PM做的;
  3. 接口文档、数据库设计书是日本公司提供的;
  4. 最夸张的是,就连按钮的颜色,文档中都有标注…
  5. 她需要做的,就只是照着接口文档去编码、测试就ok了。

有的面试者工作了5年,做的都是自家产品,项目只有两个,翻来覆去的改BUG,加需求,做运维。 技术栈很老,还是SSM那一套,最近在改造,终于用上了SpringBoot…
微服务、消息中间件、分布式锁根本没用过…

还有的面试者,在XX大厂工作,中间做了一年C#,一年Go,一看简历很华丽,精通三国语言,其实不然,都处于入门阶段,毫无竞争力可言。

一时兴起,说多了,言归正传,总结一篇分布式锁的文章,丰富个人简历,提高面试level,给自己增加一点谈资,秒变面试小达人,BAT不是梦。

一、分布式锁的重要性与挑战

1.1 分布式系统中的并发问题

在现代分布式系统中,由于多个节点同时操作共享资源,常常会引发各种并发问题。这些问题包括竞态条件、数据不一致、死锁等,给系统的稳定性和可靠性带来了挑战。让我们深入探讨在分布式系统中出现的一些并发问题:

竞态条件

竞态条件指的是多个进程或线程在执行顺序上产生了不确定性,从而导致程序的行为变得不可预测。在分布式系统中,多个节点同时访问共享资源,如果没有合适的同步机制,就可能引发竞态条件。例如,在一个电商平台中,多个用户同时尝试购买一个限量商品,如果没有良好的同步机制,就可能导致超卖问题。

数据不一致

在分布式系统中,由于数据的拆分和复制,数据的一致性可能受到影响。多个节点同时对同一个数据进行修改,如果没有适当的同步措施,就可能导致数据不一致。例如,在一个社交网络应用中,用户在不同的节点上修改了自己的个人资料,如果没有同步机制,就可能导致数据不一致,影响用户体验。

死锁

死锁是指多个进程或线程因相互等待对方释放资源而陷入无限等待的状态。在分布式系统中,多个节点可能同时竞争资源,如果没有良好的协调机制,就可能出现死锁情况。例如,多个节点同时尝试获取一组分布式锁,但由于顺序不当,可能导致死锁问题。。

二、分布式锁的基本原理与实现方式

2.1 分布式锁的基本概念

分布式锁是分布式系统中的关键概念,用于解决多个节点同时访问共享资源可能引发的并发问题。以下是分布式锁的一些基本概念:

  • 锁(Lock):锁是一种同步机制,用于确保在任意时刻只有一个节点(进程或线程)可以访问共享资源。锁可以防止竞态条件和数据不一致问题。

  • 共享资源(Shared Resource):共享资源是多个节点需要访问或修改的数据、文件、服务等。在分布式系统中,多个节点可能同时尝试访问这些共享资源,从而引发问题。

  • 锁的状态:锁通常有两种状态,即锁定状态和解锁状态。在锁定状态下,只有持有锁的节点可以访问共享资源,其他节点被阻塞。在解锁状态下,任何节点都可以尝试获取锁。

  • 竞态条件(Race Condition):竞态条件指的是多个节点在执行顺序上产生了不确定性,导致程序的行为变得不可预测。在分布式系统中,竞态条件可能导致多个节点同时访问共享资源,破坏了系统的一致性。

  • 数据不一致(Data Inconsistency):数据不一致是指多个节点对同一个数据进行修改,但由于缺乏同步机制,数据可能处于不一致的状态。这可能导致应用程序出现错误或异常行为。

  • 死锁(Deadlock):死锁是多个节点因相互等待对方释放资源而陷入无限等待的状态。在分布式系统中,多个节点可能同时竞争资源,如果没有良好的协调机制,就可能出现死锁情况。

分布式锁的基本目标是解决这些问题,确保多个节点在访问共享资源时能够安全、有序地进行操作,从而保持数据的一致性和系统的稳定性。

2.2 基于数据库的分布式锁

原理与实现方式

一种常见的分布式锁实现方式是基于数据库。在这种方式下,每个节点在访问共享资源之前,首先尝试在数据库中插入一条带有唯一约束的记录。如果插入成功,说明节点成功获取了锁;否则,说明锁已经被其他节点占用。

数据库分布式锁的原理比较简单,但实现起来需要考虑一些问题。以下是一些关键点:

  • 唯一约束(Unique Constraint):数据库中的唯一约束确保了只有一个节点可以成功插入锁记录。这可以通过数据库的表结构来实现,确保锁记录的键是唯一的。

  • 超时时间(Timeout):为了避免节点在获取锁后崩溃导致锁无法释放,通常需要设置锁的超时时间。如果节点在超时时间内没有完成操作,锁将自动释放,其他节点可以获取锁。

  • 事务(Transaction):数据库事务机制可以确保数据的一致性。在获取锁和释放锁的过程中,可以使用事务来包装操作,确保操作是原子的。

在图中,节点A尝试在数据库中插入锁记录,如果插入成功,表示节点A获取了锁,可以执行操作。操作完成后,节点A释放了锁。如果插入失败,表示锁已经被其他节点占用,节点A需要处理锁争用的情况。

优缺点
优点 缺点
实现相对简单,不需要引入额外的组件。 性能相对较差,数据库的IO开销较大。
可以使用数据库的事务机制确保数据的一致性。 容易产生死锁,需要谨慎设计。
不适用于高并发场景,可能成为系统的瓶颈。

这个表格对基于数据库的分布式锁的优缺点进行了简明的总结。

2.3 基于缓存的分布式锁

原理与实现方式

另一种常见且更为高效的分布式锁实现方式是基于缓存系统,如Redis。在这种方式下,每个节点尝试在缓存中设置一个带有过期时间的键,如果设置成功,则表示获取了锁;否则,表示锁已经被其他节点占用。

基于缓存的分布式锁通常使用原子操作来实现,确保在并发环境下锁的获取是安全的。Redis提供了类似SETNX(SET if Not

eXists)的命令来实现这种原子性操作。此外,我们还可以为锁设置一个过期时间,避免节点在获取锁后崩溃导致锁一直无法释放。

上图中,节点A尝试在缓存系统中设置一个带有过期时间的锁键,如果设置成功,表示节点A获取了锁,可以执行操作。操作完成后,节点A释放了锁键。如果设置失败,表示锁已经被其他节点占用,节点A需要处理锁争用的情况。

优缺点
优点 缺点
性能较高,缓存系统通常在内存中操作,IO开销较小。 可能存在缓存失效和节点崩溃等问题,需要额外处理。
可以使用缓存的原子操作确保获取锁的安全性。 需要依赖外部缓存系统,引入了系统的复杂性。
适用于高并发场景,不易成为系统的瓶颈。

通过基于数据库和基于缓存的分布式锁实现方式,我们可以更好地理解分布式锁的基本原理以及各自的优缺点。根据实际应用场景和性能要求,选择合适的分布式锁实现方式非常重要。

三、Redis分布式锁的实现与使用

3.1 使用SETNX命令实现分布式锁

在Redis中,可以使用SETNX(SET if Not eXists)命令来实现基本的分布式锁。SETNX命令会尝试在缓存中设置一个键值对,如果键不存在,则设置成功并返回1;如果键已存在,则设置失败并返回0。通过这一机制,我们可以利用SETNX来创建分布式锁。

以下是一个使用SETNX命令实现分布式锁的Java代码示例:

import redis.clients.jedis.Jedis;

public class DistributedLockExample {

    private Jedis jedis;

    public DistributedLockExample() {
        jedis = new Jedis("localhost", 6379);
    }

    public boolean acquireLock(String lockKey, String requestId, int expireTime) {
        Long result = jedis.setnx(lockKey, requestId);
        if (result == 1) {
            jedis.expire(lockKey, expireTime);
            return true;
        }
        return false;
    }

    public void releaseLock(String lockKey, String requestId) {
        String storedRequestId = jedis.get(lockKey);
        if (storedRequestId != null && storedRequestId.equals(requestId)) {
            jedis.del(lockKey);
        }
    }

    public static void main(String[] args) {
        DistributedLockExample lockExample = new DistributedLockExample();

        String lockKey = "resource:lock";
        String requestId = "request123";
        int expireTime = 60; // 锁的过期时间

        if (lockExample.acquireLock(lockKey, requestId, expireTime)) {
            try {
                // 执行需要加锁的操作
                System.out.println("Lock acquired. Performing critical section.");
                Thread.sleep(1000); // 模拟操作耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lockExample.releaseLock(lockKey, requestId);
                System.out.println("Lock released.");
            }
        } else {
            System.out.println("Failed to acquire lock.");
        }
    }
}

3.2 设置超时与防止死锁

在上述代码中,我们通过使用expire命令为锁设置了一个过期时间,以防止节点在获取锁后崩溃或异常退出,导致锁一直无法释放。设置合理的过期时间可以避免锁长时间占用而导致的资源浪费。

3.3 锁的可重入性与线程安全性

分布式锁需要考虑的一个问题是可重入性,即同一个线程是否可以多次获取同一把锁而不被阻塞。通常情况下,分布式锁是不具备可重入性的,因为每次获取锁都会生成一个新的标识(如requestId),不会与之前的标识相同。

为了解决可重入性的问题,我们可以引入一个计数器,记录某个线程获取锁的次数。当线程再次尝试获取锁时,只有计数器为0时才会真正获取锁,否则只会增加计数器。释放锁时,计数器减少,直到为0才真正释放锁。

需要注意的是,为了保证分布式锁的线程安全性,我们应该使用线程本地变量来存储requestId,以防止不同线程之间的干扰。

四、分布式锁的高级应用与性能考虑

4.1 锁粒度的选择

在分布式锁的应用中,选择合适的锁粒度是非常重要的。锁粒度的选择会直接影响系统的性能和并发能力。 一般而言,锁粒度可以分为粗粒度锁和细粒度锁。

  • 粗粒度锁:将较大范围的代码块加锁,可能导致并发性降低,但减少了锁的开销。适用于对数据一致性要求不高,但对并发性能要求较低的场景。
  • 细粒度锁:将较小范围的代码块加锁,提高了并发性能,但可能增加了锁的开销。适用于对数据一致性要求高,但对并发性能要求较高的场景。

在选择锁粒度时,需要根据具体业务场景和性能需求进行权衡,避免过度加锁或锁不足的情况。

4.2 基于RedLock的多Redis实例锁

RedLock算法是一种在多个Redis实例上实现分布式锁的算法,用于提高锁的可靠性。由于单个Redis实例可能由于故障或网络问题而导致分布式锁的失效,通过使用多个Redis实例,我们可以降低锁失效的概率。

RedLock算法的基本思想是在多个Redis实例上创建相同的锁,并使用SETNX命令来尝试获取锁。在获取锁时,还需要检查大部分Redis实例的时间戳,确保锁在多个实例上的时间戳是一致的。只有当大部分实例的时间戳一致时,才认为锁获取成功。

以下是基于RedLock的分布式锁的Java代码示例:

import redis.clients.jedis.Jedis;

public class RedLockExample {

    private static final int QUORUM = 3;
    private static final int LOCK_TIMEOUT = 500;

    private Jedis[] jedisInstances;

    public RedLockExample() {
        jedisInstances = new Jedis[]{
            new Jedis("localhost", 6379),
            new Jedis("localhost", 6380),
            new Jedis("localhost", 6381)
        };
    }

    public boolean acquireLock(String lockKey, String requestId) {
        int votes = 0;
        long start = System.currentTimeMillis();
        
        while ((System.currentTimeMillis() - start) < LOCK_TIMEOUT) {
            for (Jedis jedis : jedisInstances) {
                if (jedis.setnx(lockKey, requestId) == 1) {
                    jedis.expire(lockKey, LOCK_TIMEOUT / 1000); // 设置锁的超时时间
                    votes++;
                }
            }
            
            if (votes >= QUORUM) {
                return true;
            } else {
                // 未获取到足够的票数,释放已获得的锁
                for (Jedis jedis : jedisInstances) {
                    if (jedis.get(lockKey).equals(requestId)) {
                        jedis.del(lockKey);
                    }
                }
            }
            
            try {
                Thread.sleep(50); // 等待一段时间后重试
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        
        return false;
    }

    public void releaseLock(String lockKey, String requestId) {
        for (Jedis jedis : jedisInstances) {
            if (jedis.get(lockKey).equals(requestId)) {
                jedis.del(lockKey);
            }
        }
    }

    public static void main(String[] args) {
        RedLockExample redLockExample = new RedLockExample();
        
        String lockKey = "resource:lock";
        String requestId = "request123";

        if (redLockExample.acquireLock(lockKey, requestId)) {
            try {
                // 执行需要加锁的操作
                System.out.println("Lock acquired. Performing critical section.");
                Thread.sleep(1000); // 模拟操作耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                redLockExample.releaseLock(lockKey, requestId);
                System.out.println("Lock released.");
            }
        } else {
            System.out.println("Failed to acquire lock.");
        }
    }
}

4.3 分布式锁的性能考虑

分布式锁的引入会增加系统的复杂性和性能开销,因此在使用分布式锁时需要考虑其对系统性能的影响。

一些性能优化的方法包括:

  • 减少锁的持有时间:尽量缩短代码块中的加锁时间,以减少锁的竞争和阻塞。
  • 使用细粒度锁:避免一次性加锁过多的资源,尽量选择合适的锁粒度,减小锁的粒度。
  • 选择高性能的锁实现:比如基于缓存的分布式锁通常比数据库锁性能更高。
  • 合理设置锁的超时时间:避免长时间的锁占用,导致资源浪费。
  • 考虑并发量和性能需求:根据系统的并发量和性能需求,合理设计锁的策略和方案。

分布式锁的高级应用需要根据实际情况来选择适当的策略,以保证系统的性能和一致性。在考虑性能优化时,需要综合考虑锁的粒度、并发量、可靠性等因素。

五、常见并发问题与分布式锁的解决方案对比

5.1 高并发场景下的数据一致性问题

在高并发场景下,数据一致性是一个常见的问题。多个并发请求同时修改相同的数据,可能导致数据不一致的情况。分布式锁是解决这一问题的有效方案之一,与其他解决方案相比,具有以下优势:

  • 原子性保证: 分布式锁可以保证一组操作的原子性,从而确保多个操作在同一时刻只有一个能够执行,避免了并发冲突。
  • 简单易用: 分布式锁的使用相对简单,通过加锁和释放锁的操作,可以有效地保证数据的一致性。
  • 广泛适用: 分布式锁适用于不同的数据存储系统,如关系型数据库、NoSQL数据库和缓存系统。

相比之下,其他解决方案可能需要更复杂的逻辑和额外的处理,例如使用乐观锁、悲观锁、分布式事务等。虽然这些方案在一些场景下也是有效的,但分布式锁作为一种通用的解决方案,在大多数情况下都能够提供简单而可靠的数据一致性保证。

5.2 唯一性约束与分布式锁

唯一性约束是另一个常见的并发问题,涉及到确保某些操作只能被执行一次,避免重复操作。例如,在分布式环境中,我们可能需要确保只有一个用户能够创建某个资源,或者只能有一个任务被执行。

分布式锁可以很好地解决唯一性约束的问题。当一个请求尝试获取分布式锁时,如果获取成功,说明该请求获得了执行权,可以执行需要唯一性约束的操作。其他请求获取锁失败,意味着已经有一个请求在执行相同操作了,从而避免了重复操作。

与其他解决方案相比,分布式锁的实现相对简单,不需要修改数据表结构或增加额外的约束。而其他方案可能涉及数据库的唯一性约束、队列的消费者去重等,可能需要更多的处理和调整。

六、最佳实践与注意事项

6.1 分布式锁的最佳实践

分布式锁是一种强大的工具,但在使用时需要遵循一些最佳实践,以确保系统的可靠性和性能。以下是一些关键的最佳实践:

选择合适的场景

分布式锁适用于需要确保数据一致性和控制并发的场景,但并不是所有情况都需要使用分布式锁。在设计中,应仔细评估业务需求,选择合适的场景使用分布式锁,避免不必要的复杂性。

例子

适合使用分布式锁的场景包括:订单支付、库存扣减等需要强一致性和避免并发问题的操作。

反例

对于只读操作或者数据不敏感的操作,可能不需要使用分布式锁,以避免引入不必要的复杂性。

锁粒度的选择

在使用分布式锁时,选择适当的锁粒度至关重要。锁粒度过大可能导致性能下降,而锁粒度过小可能增加锁争用的风险。需要根据业务场景和数据模型选择恰当的锁粒度。

例子

在订单系统中,如果需要同时操作多个订单,可以将锁粒度设置为每个订单的粒度,而不是整个系统的粒度。

反例

如果锁粒度过大,比如在整个系统级别上加锁,可能会导致并发性能下降。

设置合理的超时时间

为锁设置合理的超时时间是防止死锁和资源浪费的重要步骤。过长的超时时间可能导致锁长时间占用,而过短的超时时间可能导致锁被频繁释放,增加了锁争用的可能性。

例子

如果某个操作的正常执行时间不超过5秒,可以设置锁的超时时间为10秒,以确保在正常情况下能够释放锁。

反例

设置过长的超时时间可能导致锁被长时间占用,造成资源浪费。

6.2 避免常见陷阱与错误

在使用分布式锁时,还需要注意一些常见的陷阱和错误,以避免引入更多问题:

重复释放锁

在释放锁时,确保只有获取锁的请求才能进行释放操作。重复释放锁可能导致其他请求获取到不应该获取的锁。

例子

// 错误的释放锁方式
if (storedRequestId != null) {
    jedis.del(lockKey);
}

正例

// 正确的释放锁方式
if (storedRequestId != null && storedRequestId.equals(requestId)) {
    jedis.del(lockKey);
}
锁的可重入性

在实现分布式锁时,考虑锁的可重入性是必要的。某个请求在获取了锁后,可能还会在同一个线程内再次请求获取锁。在实现时需要保证锁是可重入的。

例子

// 错误的可重入性处理
if (lockExample.acquireLock(lockKey, requestId, expireTime)) {
    // 执行操作
    lockExample.acquireLock(lockKey, requestId, expireTime); // 错误:再次获取锁
    lockExample.releaseLock(lockKey, requestId);
}

正例

// 正确的可重入性处理
if (lockExample.acquireLock(lockKey, requestId, expireTime)) {
    try {
        // 执行操作
    } finally {
        lockExample.releaseLock(lockKey, requestId);
    }
}

锁的正确释放

确保锁的释放操作在正确的位置进行,以免在锁未释放的情况下就进入了下一个阶段,导致数据不一致。

例子

// 错误的锁释放位置
if (lockExample.acquireLock(lockKey, requestId, expireTime)) {
    // 执行操作
    lockExample.releaseLock(lockKey, requestId); // 错误:锁未释放就执行了下一步操作
    // 执行下一步操作
}

正例

// 正确的锁释放位置
if (lockExample.acquireLock(lockKey, requestId, expireTime)) {
    try {
        // 执行操作
    } finally {
        lockExample.releaseLock(lockKey, requestId);
    }
}
不应滥用锁

分布式锁虽然能够解决并发问题,但过度使用锁可能会降低系统性能。在使用分布式锁时,需要在性能和一致性之间做出权衡。

例子

不应该在整个系统的每个操作都加上分布式锁,以避免锁竞争过于频繁导致性能问题。

正例

只在必要的操作中加入分布式锁,以保证一致性的同时最大程度地减少锁竞争。

通过遵循以上最佳实践和避免常见陷阱与错误,可以更好地使用分布式锁来实现数据一致性和并发控制,确保分布式系统的可靠性和性能。

Redis一网打尽

兄弟,王者荣耀的段位排行榜是通过Redis实现的?

Redis事务与管道详解

本地缓存、Redis数据缓存策略

2023年再不会Redis,就要被淘汰了

图解Redis,谈谈Redis的持久化,RDB快照与AOF日志

Redis单线程还是多线程?IO多路复用原理

Redis集群的最大槽数为什么是16384个?

Redis缓存穿透、击穿、雪崩到底是个啥?7张图告诉你

Redis分布式锁的实现方式

Redis分布式缓存、秒杀

Redis布隆过滤器的原理和应用场景,解决缓存穿透

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis分布式锁的实现方式、实现原理 的相关文章

  • 带 Java 客户端的键值数据库

    我基本上想在磁盘上存储一个哈希表 以便以后可以查询它 我的程序是用Java 编写的 哈希表从字符串映射到列表 那里有很多键值存储 但经过大量研究 阅读后 尚不清楚哪一个最适合我的目的 以下是一些对我来说很重要的事情 简单的键值存储 允许您使
  • Predis 给出“从服务器读取行时出错”

    我在用predis https github com nrk predis 它已订阅频道并正在收听 它抛出以下错误 如下 并在 60 秒后死亡 这肯定不是我的网络服务器错误或其超时 有一个类似的问题正在讨论here https github
  • Redis多插入问题

    我尝试多次插入 但它给了我错误 http pastie org 7337421 http pastie org 7337421 cat mass insert txt 3 r n 3 r nSET r n 3 r nkey r n 5 r
  • Redis 写入 .ssh/authorized_keys

    当前设置 2 个主服务器 12 个工作服务器 工作人员通过 ssh copy id 连接到主设备 主设备和工作人员正在主设备上的 redis 队列中写入数据 过去一周我遇到的问题是 Redis 正在将数据写入authorized keys
  • 如何清理redis中不活跃的玩家?

    我正在制作一个使用 redis 来存储游戏状态的游戏 它可以很好地跟踪位置和玩家 但我没有一个好的方法来清理不活跃的玩家 每当玩家移动时 这是一个半慢速移动游戏 想想每秒 1 5 帧 我就会用新位置更新哈希并删除旧位置键 跟踪活跃玩家的最佳
  • AWS Redis 从外部连接

    有没有办法从外部 AWS 网络连接 AWS 上托管的 Redis 实例 我有一个基于 Windows 的 EC2 实例在 AWS 上运行 另一个是 Redis 缓存节点 我知道有人问过这个问题 但答案是在基于 Linux 的系统中 但我的是
  • Spring RedisTemplate:8次调用后方法键挂起

    我使用 Spring RedisTemplate spring data redis 1 7 1 与 Redis 进行通信 我需要通过正则表达式获取然后删除键 例如 context user1 我用的方法 RedisTemplate key
  • Redis键空间事件不触发

    我有两个 Redis 客户端 在一个文件中我有一个简单的脚本设置并删除了 Redis 键 var redis require redis var client redis createClient 6379 127 0 0 1 client
  • 如何统计 Redis 流中未读或已确认的消息?

    使用 Redis 5 0 3 假设我们创建一个名为streamy和一个消费群体consumers XGROUP CREATE streamy consumers MKSTREAM 然后向其中添加一些消息 XADD streamy messa
  • 如何设置 Celery 以通过 ssl 与 Azure Redis 实例对话

    使用 的伟大答案 如何在microsoft azure上的django项目中配置celery redis https stackoverflow com questions 39616701 how to configure celery
  • redis-cli 重定向到 127.0.0.1

    我在PC1上启动Redis集群 然后在PC2上连接它 当需要重定向到另一个集群节点时 它会显示Redirected to slot 7785 located at 127 0 0 1 但应该显示Redirected to slot 7785
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • 如何批量删除Redis中数十万个带有特殊字符的key

    我们有一个包含数十万个 Redis 键的列表 其中包含各种特殊字符 我们希望批量删除它们 对于这个问题上的类似问题 有一些很好的答案 如何使用 Redis 自动删除与模式匹配的键 https stackoverflow com questi
  • Caffeine Expiry 中如何设置多个过期标准?

    我正在使用 Caffeine v2 8 5 我想创建一个具有可变到期时间的缓存 基于 值的创建 更新以及 该值的最后一次访问 读取 无论先发生什么都应该触发该条目的删除 缓存将成为三层值解析的一部分 The key is present i
  • 在 Kubernetes/Openshift 中将客户端-服务器流量保持在同一区域的最佳方法?

    我们运行兼容 Kubernetes OKD 3 11 的本地 私有云集群 其中后端应用程序与用作缓存和 K V 存储的低延迟 Redis 数据库进行通信 新的架构设计将在两个地理上分布的数据中心 区域 之间平均划分工作节点 我们可以假设节点
  • SignalR 无法连接到 SSL 上的 Azure Redis

    我目前在 Azure 上托管我的 redis 缓存服务器 并让 signalR 依赖它作为骨干 使用以下内容 GlobalHost DependencyResolver UseRedis 服务器 端口 密码 eventKey 这可以在端口
  • 如何在Redis中进行持久化存储?

    关闭redis服务器后 使用set存储的值被破坏 在这里我找到了使用持久性存储的方法 有人帮助我 如何使用javascript实现这一点 我想将客户端的一些值存储在 redis 数据库中 并且必须在其他客户端中使用该值 您需要配置 Redi
  • Redis发布/订阅:查看当前订阅了哪些频道

    我目前有兴趣查看我拥有的 Redis 发布 订阅应用程序中订阅了哪些频道 当客户端连接到我们的服务器时 我们将它们注册到如下所示的通道 user user id 这样做的原因是我希望能够看到谁 在线 目前 我在不知道客户端是否在线的情况下盲
  • 使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

    我正在开发一个 Web 应用程序 该应用程序将接收用户的请求 并且必须调用许多外部 API 来编写对该请求的答案 这可以直接从主 Web 线程使用 gevent 之类的东西来扇出请求来完成 或者 我在想 我可以将传入的请求放入队列中 并使用
  • StackExchange.Redis Get 函数抛出 TimeoutException

    我在用着StackExchange Redis与 C 和StackExchangeRedisCacheClient Get函数抛出以下异常 myCacheClient Database StringGet txtKey Text myCac

随机推荐

  • 用户态虚拟化IO通道实现概览及实践(上)

    自虚拟化技术诞生起 提升虚拟化场景中IO设备性能和驱动的兼容性 可扩展性一直是备受关注和追求的目标 随着半虚拟化技术的出现 virtio设备及驱动也很快流行并逐步变成了虚拟化应用中的主要IO通道形态 例如 virtio现已支持实现的设备涵盖
  • Dell IDRAC服务器重装系统详解(远程连接)

    主要的操作步骤文末附上的那篇博客写的比较详细了 不足的地方是有一些小问题没有说明白 导致新手可能不太清楚操作 而无法 复现 安装过程 TIPS 1 远程连接登录的时候 用户名root 密码calvin不一定可行 如果不行的话 看一下服务器机
  • 研一Python基础课程第四周课后习题分享(含源代码)

    代码写的较多 有问题可以私聊我 第四周作业分享 一 题目前言 二 题目分享 1 问题1 2 问题2 3 问题3 4 问题4 5 问题5 6 问题6 7 问题7 8 问题8 9 问题9 10 问题10 11 问题11 12 问题12 13 问
  • 深度学习之经典案例 CIFAR10 图形识别(jupyter)

    图像识别 CIFAR10图形识别 1 CIFAR10数据集共有60000张彩色图像 这些图像式32 32 3 分为10个类 每个类6000张 2 这里面有50000张用于训练 构成5个训练批 每一批10000张图 另外10000张用于测试
  • Centos7网卡配置——动态与静态

    Centos7网卡配置 一 自动获取动态IP地址 二 配置静态IP地址 三 修改网卡注意事项 四 基础知识 以下实例全部基于VM虚拟机操作 一 自动获取动态IP地址 1 输入命令 ip addr 查看IP地址 右下图可以发现只有一张名为en
  • git版本回退到某一次提交

    背景 今天一个前端女同事问我她如何才能回退到上一次她提交的版本 她网上找了方法 却没有起作用 问题虽然简单 但是还是记录下来 解决问题 使用命令 git log查看提交记录 并复制下想要回退到那个版本的commitId 就是commit后面
  • 医学图像肝脏分割(一)---预处理

    预处理是肝脏分割重要的一步 良好的预处理过程可以有效的提高分割的准确度 此博文主要记录肝脏分割过程中常见的预处理方法及相关代码 一 标准的预处理过程 1 Kaggle LUNA16 competition preprocessing tut
  • 创建Component的方式

    createClass createClass 组件的props state等都是以对象属性的方式组合在一起 其中默认属props和初始state都是返回对象的函数 component component state是通过在构造函数中对th
  • php通过递归获取分公司的上下级数据

    1 表结构 2 php核心代码 param branches 全部分公司数据 param parentId 查询的分公司id 传0则全部排序 大于0 则查询该分公司下的下级 param int level 层级 方便界面特效 param i
  • html怎么给背景图固定位置,css实现固定背景图像的方法

    css实现固定背景图像的方法 发布时间 2020 08 29 11 26 59 来源 亿速云 阅读 81 作者 小新 小编给大家分享一下css实现固定背景图像的方法 相信大部分人都还不怎么了解 因此分享这篇文章给大家参考一下 希望大家阅读完
  • 重磅!《2022中国开源发展蓝皮书》正式发布

    作为数字时代的新趋势 开源正以 开放 共享 协同 商业模式 的新型生产方式 以 自由 的传播形式 成为全球信息技术发展的强大推动力 在全世界开源大发展的背景下 近年来中国开源的发展速度已成为全球最快 局部领域已接近或达到世界先进水平 其迸发
  • Ubuntu上通过android toolchain交叉编译Valgrind操作步骤

    关于Valgrind的介绍可以参考 https blog csdn net fengbingchun article details 50196189 这里介绍下在Ubuntu 16 04上通过android toolchain如andro
  • 一套简单的基本生活财富自由方案

    前言 之前一直觉得财富自由似乎遥不可及 但今年学习理财以来 至今已有一年的样子了 读完了100本书 再加上实操经验 发现虽然成为富豪依然遥不可及 但一些基本的财富自由方案已经可以实现了 试算了一下 按照保守收益估计 其实是完全可以实现的 经
  • hadoop支持lzo完整过程

    简介 部署 安装lzop native library 安装hadoop lzo 配置hadoop环境变量 验证lzo通过hive测试 创建lzo表 导入数据 索引LZO文件 利用hive执行mr任务 修改使用中hive表的输入输出格式 简
  • .\Objects\new project.axf: Error: L6200E: Symbol __asm___17_system_mb9bf40x_等5个报错的原因

    不知道有没有人遇到我这种问题 二十分钟才大概把错误原因的范围锁定在device那里 这是所有的报错 如果你遇到了这样的错误 那么接下来就可以解决这个问题了 提示重复定义了后面的 这里无论你用的什么芯片 只要报错的前部分信息一样 我想解决办法
  • Python发送Post请求及解析响应结果

    一 Post请求 1 使用python发送一个Post请求 有时候遇到请求url中有很多参数 1 1 示例1 accounts和pwd请到http shop xo hctestedu com 注册 import requests 请求体 d
  • 父组件监听子组件声明周期的方法

    父组件 hook mounted watchChild watchChild写监听到子组件生命周期触发后 要走的逻辑
  • 【Confluence】创建分级文件目录

    需求 在confluence文档中构建如下图所示的分级目录文件 解决 首先在该目录下创建一个文件 确定好位置 创建好之后 在该创建好的文件下在重复创建文件即可
  • 【Python基础】Matplotlib如何绘制多个子图的几种方法

    作者 雪山飞猪 博客地址 https www cnblogs com chenqionghe p 12355018 html 说明 本文经作者授权转载 禁止二次转载 Matplotlib是Python的底层绘图工具 可定制性很强 很多人刚开
  • Redis分布式锁的实现方式、实现原理

    目录 一 分布式锁的重要性与挑战 1 1 分布式系统中的并发问题 竞态条件 数据不一致 死锁 二 分布式锁的基本原理与实现方式 2 1 分布式锁的基本概念 2 2 基于数据库的分布式锁 原理与实现方式 优缺点 2 3 基于缓存的分布式锁 原