Redis 분산 잠금 장치 구현 원리는 무엇입니까?
지금 면접을 볼 때, 보통 분산 시스템을 말한다. 일반적으로 면접관은 서비스 프레임워크 (Spring Cloud, Dubbo) 부터 분산 트랜잭션, 분산 잠금 장치, ZooKeeper 등에 대해 이야기합니다.
그런 다음 이 문서의 분산 잠금에 대한 지식을 살펴보고 Redis 분산 잠금의 구현 원리를 구체적으로 살펴보겠습니다.
솔직히 말해서, 회사의 생산 환경에서 분산 잠금을 사용한다면, Redis 분산 잠금과 같은 오픈 소스 클래스 라이브러리를 사용하게 될 것입니다. 일반적으로 Redisson 프레임워크를 사용하는 것이 좋습니다. 매우 간단합니다. (데이비드 아셀, Northern Exposure (미국 TV 드라마), 예술명언)
관심이 있으시면 Redisson 의 공식 홈페이지를 살펴보고 Redisson 의 의존성을 프로젝트에 도입하여 Redisson 기반 분산 잠금의 잠금 및 해제를 실현할 수 있습니다.
간단한 코드 조각을 보여드리겠습니다. 먼저 직관적으로 느껴보세요.
위의 코드는 어떻습니까? 간단하다고 느껴지지 않나요?
또한 redis 단일 인스턴스, redis Sentinel, redis 클러스터, redis 마스터-슬레이브 등 다양한 배포 아키텍처도 지원합니다.
둘째, Redisson 은 Redis 분산 잠금의 기본 원리를 구현합니다.
자, 다음은 Redis 분산 잠금의 구현 원리에 대해 손으로 그린 것입니다.
(1) 매커니즘을 잠급니다
우리는 그림을 보러 왔다. 이제 클라이언트를 잠가야 합니다. 클라이언트가 redis cluster 클러스터를 상대하는 경우 먼저 hash 노드를 기준으로 시스템을 선택합니다.
여기서 주의하세요, 기계를 고르시면 됩니다! 이것은 매우 중요합니다!
그런 다음 루아 스크립트가 다음과 같이 redis 로 전송됩니다.
루아 스크립트를 사용해야 하는 이유는 무엇입니까?
많은 복잡한 비즈니스 논리가 루아 스크립트에 캡슐화되어 redis 에 전달될 수 있기 때문에 이러한 복잡한 비즈니스 로직 실행의 원자성을 보장할 수 있습니다.
그럼 이 루아 스크립트는 무슨 뜻인가요?
KEYS[ 1] 는 잠근 키를 나타냅니다. 예를 들면 다음과 같습니다.
R lock lock = redisson.getlock ("mylock");
여기서 네가 직접 설치한 자물쇠의 열쇠는' 내 자물쇠' 이다.
ARGV[ 1] 는 잠금 키의 기본 수명을 나타내며 기본값은 30 초입니다.
ARGV[2] 는 다음과 같이 잠긴 클라이언트의 ID 를 나타냅니다.
8743 c9c0-0795-4907-87fd-6c719a6b4586:1
제가 설명해 드리겠습니다. 첫 번째 if 판단문은' exists myLock' 명령으로 판단한 것입니다. 잠그려는 잠금 키가 없으면 잠글 수 있습니다.
어떻게 잠궈요? 매우 간단합니다. 다음 명령을 사용합니다.
Hset myLock
8743 c9c0-0795-4907-87fd-6c719a6b4586:11
이 명령을 통해 해시 데이터 구조를 설정합니다. 이 명령을 실행하면 다음과 유사한 데이터 구조가 나타납니다.
위의 내용은 클라이언트 "8743c9c0-0795-4907-87fd-6c719a6b4586:1"이 잠금 키 "myLock" 을 잠갔음을 나타냅니다
그런 다음' p expire my lock 30000' 명령이 실행되고 mylock 의 lock 키 수명 주기가 30 초로 설정됩니다.
좋아, 그게 다야. 자, 자물쇠가 완성되었습니다.
(2) 잠금 상호 배제 메커니즘
이때 클라이언트 2 가 동일한 루아 스크립트를 잠그고 실행하려고 하면 어떻게 합니까?
간단합니다. 첫 번째 if 판단은' exists myLock' 을 실행하는데, myLock 의 잠금 키가 이미 있다는 것을 발견했습니다.
그런 다음 두 번째 if 판단을 수행하여 myLock Lock key 의 해시 데이터 구조에 클라이언트 2 의 ID 가 포함되어 있는지 확인합니다. 그러나 클라이언트1의 ID 가 포함되어 있기 때문에 그렇지 않습니다.
따라서 클라이언트 2 는 myLock 의 남은 수명을 나타내는 pttl myLock 에서 반환한 숫자를 얻습니다. 예를 들어 15000 밀리초가 남아 살 수 있습니다.
이제 클라이언트 2 가 while 루프로 들어가 잠금을 계속 시도합니다.
(3) 워치 독 자동 확장 기관.
클라이언트 1 잠긴 lock 키의 기본 수명은 30 초입니다. 30 초가 넘으면 클라이언트 1 은 이 자물쇠를 계속 갖고 싶어합니다. 어떻게 해야 할까요?
간단합니다! 클라이언트 1 잠금이 성공하면 watch dog 감시견이 시작됩니다. 이는 백그라운드 스레드이며 10 초마다 한 번씩 확인됩니다. 클라이언트 1 이 여전히 잠금 키를 보유하고 있다면 잠금 키의 수명이 계속 연장됩니다.
(4) 재진입 잠금 메커니즘
그렇다면 클라이언트 1 이 잠금을 이미 보유하고 있다면 다시 잠그는 것은 어떻게 될까요?
예를 들어, 다음 코드는 :
이제 위의 루아 스크립트를 분석해 보겠습니다.
첫 번째 if 판단은 확실히 사실이 아니며, "exists myLock" 은 잠금 키가 이미 있음을 보여줍니다.
두 번째 if 판단은 myLock 의 해시 데이터 구조에 포함된 ID 가 클라이언트 1 의 ID 인 "8743C9C0-0795-4907-87fd-6C7/KLOC-0" 이기 때문에 성립됩니다.
이 시점에서 다시 잠금 가능한 논리가 실행되고 다음을 사용합니다.
나한테 갇혔어
8743 c9c0-0795-4907-87fd-6c71a6b4586:11
이 명령을 사용하면 클라이언트 1 의 잠금 횟수가 1 으로 롤업됩니다.
이 시점에서 myLock 데이터 구조는 다음과 같습니다.
보시다시피, myLock 의 해시 데이터 구조에 있는 클라이언트 ID 는 잠금 수에 해당합니다.
(5) 잠금 메커니즘 해제
Lock.unlock () 을 실행하여 분산 잠금을 해제할 수 있는 경우 비즈니스 논리는 매우 간단합니다.
사실은 myLock 데이터 구조의 잠금 수에서 매번 1 을 빼는 것입니다.
잠금 수가 0 인 경우 클라이언트가 더 이상 잠금을 보유하지 않으며 다음을 사용합니다.
Redis 에서 키를 제거하는 "del myLock" 명령입니다.
그런 다음 다른 클라이언트 2 가 잠금을 완료할 수 있습니다.
이것이 바로 분산 잠금 오픈 소스 Redisson 프레임워크의 구현 메커니즘입니다.
일반적으로 프로덕션 시스템에서는 redisson 프레임워크가 제공하는 클래스 라이브러리를 사용하여 Redis 기반 분산 잠금을 잠그고 해제할 수 있습니다.
(6) 위의 Redis 분산 잠금의 단점
실제로 위 시나리오의 가장 큰 문제는 redis 마스터 인스턴스에 키 myLock 값을 기록하면 해당 마스터-슬레이브 인스턴스에 비동기적으로 복제된다는 것입니다.
그러나 이 과정에서 redis 주 서버에 장애가 발생하면 주 서버와 대기 서버가 전환되고 redis 슬레이브 서버가 redis 주 서버가 됩니다.
그런 다음 클라이언트 2 가 잠금을 시도하면 새 redis 주 서버에서 잠금이 완료되고 클라이언트 1 은 성공적으로 잠겨 있다고 간주합니다.
이로 인해 여러 클라이언트가 분산 잠금을 잠급니다.
이때 시스템의 업무 의미론에 문제가 생겨 각종 더러운 데이터를 초래할 수 있다.
따라서 redis 클러스터 또는 redis 마스터-슬레이브 아키텍처의 마스터-슬레이브 비동기 복제로 인한 redis 분산 잠금의 가장 큰 결함입니다. redis 마스터 인스턴스가 다운되면 여러 클라이언트가 동시에 잠길 수 있습니다.