>  기사  >  데이터 베이스  >  Redis를 사용하여 리소스를 잠그는 방법

Redis를 사용하여 리소스를 잠그는 방법

WBOY
WBOY앞으로
2023-05-28 11:01:45898검색

1. 개요

이 기술이 계속 업데이트되고 반복되면서 기업에서는 유통의 개념이 점점 더 중요해지고 있습니다! 분산, 분산 잠금에 관해 이야기할 때 이 단계에서는 분산 잠금의 세 가지 주요 구현 방법인 Zookeeper, DB, Redis가 있습니다. code>, 이 문서에서는 Redis를 예로 사용합니다! ZookeeperDBRedis,我们本篇文章以Redis为例!

从我们的角度来看,这三个属性是有效使用分布式锁所需的最低保证。

  1. 安全特性:互斥。在任何给定时刻,只有一个客户端可以持有锁。

  2. 活力属性:无死锁。最终,即使锁定资源的客户端崩溃或分区,也始终可以获得锁。

  3. 活动性:容错能力。只要大多数Redis节点都处于运行状态,客户端就可以获取和释放锁。

二、redis多节点实现分布式锁带来的挑战

我们使用Redis锁定资源的最简单方法是:

  1. 在实例中创建锁。

  2. 锁通常使用Redis过期功能在有限时间存在,因此最终将被释放,最终超过给定期限会被删除。

  3. 当客户端需要释放资源时,它将删除锁。

乍一看,似乎并没有什么问题。但是不妨我们深究一下,这种实现方案在redis单机环境下似乎并没有什么问题!但是如果节点宕了呢?好吧,那么让我们添加一个slave节点!如果主服务器宕机了,就使用这个节点!但是我们不妨来看看她真的能保证可用吗?

在谈论这个的致命缺陷时,我们需要了解一个知识点,Redis复制是异步的。

  1. 客户端A获取主服务器中的锁。

  2. 在将锁复制传输到从机之前,主机崩溃。

  3. slavemaster

  4. 客户端B获取锁,因为从机并没有该锁的对象,获取成功!

显然,这样是不对的,主节点因为没来得及同步数据就宕机了,所以从节点没有该数据,从而造成分布式锁的失效,那么作者antirez的观点是如何解决这个呢?

三、Redlock算法

作者认为,我们应该使用多个Redis우리의 관점에서 볼 때 이 세 가지 속성은 분산 잠금을 효과적으로 사용하는 데 필요한 최소한의 보장입니다.

  1. 안전 기능: 상호 배제. 특정 순간에 단 하나의 클라이언트만이 잠금을 보유할 수 있습니다.

  2. 활력 속성: 교착 상태가 없습니다. 궁극적으로 리소스를 잠그는 클라이언트가 충돌하거나 파티션을 나누더라도 항상 잠금을 얻을 수 있습니다.

  3. 이동성: 내결함성. 대부분의 Redis 노드가 실행 중인 한 클라이언트는 잠금을 획득하고 해제할 수 있습니다.

  4. 2. 분산 잠금의 Redis 다중 노드 구현으로 인한 과제 设置的有效时间-获取锁花费的时间

    Redis를 사용하여 리소스를 잠그는 가장 간단한 방법은 다음과 같습니다.
  5. 인스턴스에 잠금을 생성합니다.
  6. 잠금은 일반적으로 Redis 만료 기능을 사용하여 제한된 시간 동안 존재하므로 결국 잠금이 해제되고 일정 기간이 지나면 결국 삭제됩니다.

클라이언트가 리소스를 해제해야 할 때 잠금을 제거합니다.

얼핏 보면 이상이 없는 것 같습니다. 하지만 자세히 살펴보면 이 구현 솔루션은 Redis 독립형 환경에서는 문제가 없는 것 같습니다! 하지만 노드가 다운되면 어떻게 될까요? 좋습니다. 이제 slave 노드를 추가해 보겠습니다! 메인서버가 다운되면 이 노드를 이용해보세요! 하지만 그녀가 정말로 이용 가능한지 한번 살펴볼까요?
    이것의 치명적인 단점에 대해 이야기할 때 우리가 알아야 할 지식 포인트는 Redis 복제가 비동기식이라는 것입니다.
  1. 클라이언트 A가 메인 서버의 잠금을 획득합니다.
  2. 잠금 복사본을 슬레이브에 전송하기 전에 마스터가 충돌했습니다.

노예는 다음으로 승격되었습니다.  마스터. 🎜🎜🎜🎜슬레이브에는 잠금에 대한 개체가 없기 때문에 클라이언트 B가 잠금을 획득하고 획득에 성공합니다! 🎜🎜🎜🎜분명히 이것은 잘못된 것입니다. 마스터 노드가 데이터를 동기화하기 전에 다운되어 슬레이브 노드에 데이터가 없어 분산 잠금이 실패했습니다. 그러면 작성자는 antirez입니다. code>의 관점 이 문제는 어떻게 해결하나요? 🎜🎜3. Redlock 알고리즘🎜🎜 저자는 여러 <code>Redis를 사용해야 한다고 믿습니다. 이러한 노드는 완전히 독립적이며 여러 Redis 시스템이 잠금을 획득하기 위해 복제나 시스템을 사용할 필요가 없습니다. 프로세스는 다음 단계로 진행됩니다. 🎜🎜🎜🎜현재 서버 시간을 밀리초 단위로 가져옵니다. 🎜🎜🎜🎜 잠금을 획득하려면 동일한 키와 임의의 값을 사용하세요. 잠금을 획득할 때 각 시스템에 시간 초과가 있어야 합니다. 예를 들어 잠금 만료 시간이 10초인 경우 단일 노드 잠금을 획득하기 위한 시간 제한은 약 5~50밀리초여야 합니다. 이는 클라이언트가 실패한 시스템에 연결되어 추가 시간을 낭비하도록 하는 것입니다. 제한 시간 내에 데이터를 획득하지 못한 경우, 해당 노드는 포기되고, 모든 노드를 획득할 때까지 다음 노드를 획득하게 됩니다! 🎜🎜🎜🎜획득이 완료된 후 현재 시간에서 1단계에서 얻은 시간을 뺀 값을 얻습니다. 클라이언트의 절반 이상이 성공적으로 획득하고 잠금을 획득하는 데 걸리는 시간이 잠금 시간 초과보다 짧은 경우에만 가능합니다. 잠금이 효과적이라는 것을 증명했습니다! 🎜🎜🎜🎜잠금을 획득한 후 잠금 시간 초과는 다음과 같습니다. 🎜🎜🎜🎜🎜잠금을 획득한 머신의 절반 이상이 만족되지 않거나, 계산 후 잠금 시간 초과가 음수이거나 기타 비정상적인 작업이 수행되면 시스템은 일부 인스턴스가 획득에 실패하더라도 모든 인스턴스를 잠금 해제하려고 시도합니다. 성공적으로 잠금이 해제되어도 잠금 해제가 시도됩니다! 🎜🎜🎜🎜 잠금을 해제하세요. 클라이언트가 주어진 인스턴스를 성공적으로 잠글 수 있다고 생각하는지 여부에 관계없이 모든 인스턴스에서 잠금을 해제하기만 하면 됩니다. 🎜🎜🎜🎜4. 그런데 Redlock이 정말 문제를 해결할 수 있을까요? 🎜🎜Martin Kleppmann이 기사 작업을 게시했는데 Redlock은 자물쇠의 보안을 보장하지 않습니다! 🎜🎜그는 잠금의 용도가 두 번뿐이라고 믿습니다🎜🎜🎜🎜🎜 효율성을 높이려면 잠금을 사용하여 작업을 두 번 실행할 필요가 없도록 하세요. 예를 들어 (매우 비용이 많이 드는 계산) 🎜🎜🎜🎜정확성을 보장하기 위해 잠금 메커니즘을 사용하여 작업이 정상적인 프로세스 순서로 수행되도록 하여 동시에 동일한 데이터에 대해 두 노드가 작동하여 파일 충돌이 발생하는 것을 방지합니다. 데이터 손실. 🎜🎜🎜🎜🎜첫 번째 이유로 우리는 잠금에 대해 특정 허용 오차를 갖고 있습니다. 두 노드가 동시에 작동하더라도 시스템에 미치는 영향은 더 많은 계산 비용만 발생하며 추가 영향은 없습니다. 이때 Redis의 단일 지점을 사용하면 문제를 매우 잘 해결할 수 있습니다. 이렇게 많은 Redis 인스턴스를 유지 관리하고 시스템 유지 관리 비용을 늘리기 위해 RedLock을 사용할 필요가 없습니다. 🎜

1. 분산 잠금 시간 초과로 인한 단점

그러나 두 번째 시나리오의 경우 잠금이 실패하고 두 노드가 동시에 처리할 가능성이 높기 때문에 더 조심스럽습니다. 파일 손상, 데이터 손실, 영구적인 불일치 또는 금전적 손실이 발생할 수 있습니다!

두 개의 클라이언트가 있는 시나리오를 가정해 보겠습니다. 각 클라이언트는 데이터를 데이터베이스에 저장하기 전에 잠금을 얻어야 합니다. 이를 구현하기 위해 RedLock 알고리즘을 사용하면 어떤 문제가 발생합니까? RedLock에서는 교착 상태를 방지하기 위해 잠금에 만료 시간이 있지만 Martin 이것이 안전하지 않다고 생각합니다! 순서도는 이렇게 생겼어요!

Redis를 사용하여 리소스를 잠그는 방법

클라이언트 1이 성공적으로 잠금을 획득한 후 실행이 시작되었습니다. 실행 중간에 시스템에서 Full GC가 발생하고 시스템 서비스가 일시 중지되었으며 잠시 후 잠금 시간이 초과되었습니다.

클라이언트 2는 클라이언트 1의 잠금 시간이 초과될 때까지 기다린 후 성공적으로 잠금을 획득하고 웨어하우징 작업을 시작했습니다. 완료 후 클라이언트 1은 Full GC를 완료하고 또 다른 웨어하우징 작업을 수행했습니다! 이것은 안전하지 않습니다! 어떻게 해결하나요?

Martin 는 낙관적 잠금과 유사한 구현 메커니즘을 제안합니다. 예시 그림은 다음과 같습니다.

Redis를 사용하여 리소스를 잠그는 방법

클라이언트 1이 오랫동안 정지된 후, 클라이언트 2는 잠금을 획득하고 라이브러리 쓰기를 시작했으며, 동시에 라이브러리 쓰기 후 토큰 34를 들고 일어났습니다. 라이브러리 운영에 들어가려고 하는데, 가지고 있는 토큰이 최신 토큰보다 33개 적어서 제출이 거부됩니다! 34,写库完成后,客户端1苏醒,开始进行入库操作,但是因为携带的令牌为33 小于最新令牌,该次提交就被拒绝!

即使系统出现问题导致挂起,该思路似乎完备,可确保数据仍能得到正确处理。但是仔细想一下:

  • 如果仅当您的令牌大于所有过去的令牌时,数据存储区才能始终接受写入,则它是可线性化的存储区,相当与使用数据库来实现一个 分布式锁系统,那么RedLock的作用就变的微乎其微!甚至不在需要使用redis保证分布式锁! 

2.RedLock对于系统时钟强依赖

回想一下Redlock算法获取锁的几个步骤,你会发现锁的有效性是与当前的系统时钟强依赖,我们假设:

我们有,A B C D E 五个redis节点:

  1. 客户端1获取节点A,B,C的锁定。由于网络问题,无法访问D和E。

  2. 节点C上的时钟向前跳,导致锁过期。

  3. 客户端2获取节点C,D,E的锁定。由于网络问题,无法访问A和B。

  4. 现在,客户1和2都认为他们持有该锁。

如果C在将锁持久保存到磁盘之前崩溃并立即重新启动,则可能会发生类似的问题。

Martin认为系统时间的阶跃主要来自两个方面(以及作者给出的解决方案):

  1. 人为修改。

  • 对于人为修改,能说啥呢?人要搞破坏没办法避免。

  • 从NTP服务收到了一个跳跃时时钟更新。

    • 需要运维人员处理NTP接受阶跃时钟更新的问题。需要将阶跃的时间更新到服务器的时候,应当采取小步快跑的方式。多次修改,每次更新时间尽量小。

    3.基于程序语言弥补分布式锁的超时性所带来的缺点

    我们回顾 1 观点,深究抽象出现这个缺陷的根本原因,就是为了解决由于系统宕机带来的锁失效而给锁强加了一个失效时间,异常情况下,程序(业务)执行的时间大于锁失效时间从而造成的一系列的问题,我们能否从这方面去考虑,从而用程序来解决这个样一个死局 呢?

    我们可以保证业务程序执行时间绝对小于锁超时时间,这样就可以避免锁失效时间小于业务时间的问题

    java语言中redisson

    시스템에 문제가 생겨서 멈춤 현상이 발생하더라도 데이터가 계속해서 올바르게 처리되도록 하기 위해서는 이 아이디어가 완성된 것 같습니다. 하지만 생각해 보세요.
    • Redis를 사용하여 리소스를 잠그는 방법토큰이 모든 이전 토큰보다 큰 경우에만 데이터 저장소가 항상 쓰기를 허용하는 경우 , 선형화 가능한 저장 영역으로 데이터베이스를 사용하여 분산 잠금 시스템을 구현하는 것과 동일하므로 RedLock의 역할은 최소화됩니다! 분산 잠금을 보장하기 위해 Redis를 사용할 필요조차 없습니다!

    2.RedLock은 시스템 시계에 크게 의존합니다잠금을 획득하기 위한 Redlock 알고리즘 단계를 기억해 보세요. 잠금의 효과는 다음과 같습니다. 현재 시스템과 관련된 시계는 크게 종속적입니다. 우리는 A B C D E 5개의 Redis 노드를 가지고 있습니다:

    1. 🎜Client 1은 노드 A, B, C 잠금을 얻습니다. D와 E는 네트워크 문제로 접속이 불가능합니다. 🎜
    2. 🎜노드 C의 시계가 앞으로 이동하여 잠금이 만료됩니다. 🎜
    3. 🎜클라이언트 2는 노드 C, D, E의 잠금을 획득합니다. 네트워크 문제로 인해 A와 B에 접속할 수 없습니다. 🎜
    4. 🎜이제 클라이언트 1과 클라이언트 2 모두 자신이 자물쇠를 쥐고 있다고 생각합니다. 🎜
    🎜디스크 잠금을 유지하기 직전에 C가 충돌하고 다시 시작되면 비슷한 문제가 발생할 수 있습니다. 🎜🎜Martin은 시스템 시간 점프가 주로 두 가지 측면(및 저자가 제공한 솔루션)에서 비롯된다고 믿습니다. 🎜
    1. 🎜 인간 가감. 🎜
    • 🎜인간 변형에 대해 뭐라고 말할 수 있나요? 사람들이 파괴를 일으키는 것을 막을 방법은 없습니다. 🎜
  • 🎜NTP 서비스로부터 점프타임 시계 업데이트를 받았습니다. 🎜
    • 🎜운영 및 유지 관리 담당자는 NTP가 단계 시계 업데이트를 받아들이는 문제를 처리해야 합니다. 서버에 걸음 시간을 업데이트해야 할 때는 작은 걸음으로 빠르게 실행해야 합니다. 여러 번 수정하고 각 업데이트에 소요되는 시간은 최대한 짧아야 합니다. 🎜
    🎜3. 프로그래밍 언어 기반 분산 잠금의 시간 초과로 인한 단점을 보완합니다.🎜🎜1가지 관점을 검토하고 이 추상적인 결함의 근본 원인을 조사합니다. 시스템 다운타임으로 인한 잠금 실패로 인해 잠금에 만료 시간이 부과되는 비정상적인 상황에서는 프로그램(비즈니스)의 실행 시간이 잠금 만료 시간보다 길어져 일련의 문제가 발생합니다. .이 측면을 고려할 수 있습니까? 그렇다면 이러한 죽은 상황을 해결하기 위해 프로그램을 어떻게 사용할 수 있습니까? 🎜🎜비즈니스 프로그램의 실행 시간이 잠금 시간 초과보다 절대적으로 짧다는 것을 보장할 수 있으므로 잠금 만료 시간이 비즈니스 시간보다 짧은 문제를 피할 수 있습니다.🎜🎜Java 언어에서는 redisson 는 잠금 만료 시간이 비즈니스 프로그램 실행 시간 메커니즘보다 절대적으로 길도록 보장하는 방법을 구현합니다. 공식적으로 감시 메커니즘(Watchdog)이라고 불리는 주요 원리는 프로그램이 성공적으로 잠금을 획득한 후 하위 스레드를 분기하여 잠금이 해제될 때까지 잠금을 계속 갱신한다는 것입니다. 그의 회로도는 대략 다음과 같습니다: 🎜🎜🎜 🎜🎜redisson은 잠금을 갱신하기 위해 데몬 스레드를 사용합니다. (데몬 스레드의 역할: 🎜메인 스레드🎜가 파괴되면 🎜메인 스레드🎜와 함께 파괴됩니다.) 스레드가 계속해서 갱신되는 것을 방지합니다. 프로그램이 다운된 후 사망 잠금이 발생합니다! 🎜

    또한 Redisson은 RedLock 알고리즘, 공정 잠금, 재진입 잠금, 체인 및 기타 작업을 구현하고 최적화하여 Redis 분산 잠금 구현을 더 쉽고 효율적으로 만듭니다!

    위 내용은 Redis를 사용하여 리소스를 잠그는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제