Redis를 사용하여 분산 잠금을 구현하는 방법은 무엇입니까? 다음 글에서는 Redis를 기반으로 분산 잠금을 구현하는 방법을 소개하겠습니다. 도움이 되셨으면 좋겠습니다!
분산 시스템에서는 여러 노드가 공유하는 리소스를 잠가야 하는 상황에 직면하게 됩니다. 이 경우 분산 잠금을 사용해야 합니다. 분산 잠금은 일반적으로 공유 스토리지 시스템에 저장되며 여러 노드에서 공유하고 액세스할 수 있습니다. [관련 추천 : Redis 영상 튜토리얼]
간단히 말하면, 자물쇠는 변수로 표현될 수 있습니다. 예를 들어, 단일 머신 다중 스레드 프로그램에서 특정 리소스의 잠금은 1비트 데이터로 표시될 수 있습니다. 즉, 0은 리소스에 액세스할 수 없음을 의미하고, 1은 다른 스레드가 리소스 잠금을 획득하여 액세스할 수 없음을 의미합니다.
특정 리소스의 잠금을 획득하고 해제하는 것은 본질적으로 이 변수의 값을 획득하고 수정하는 것입니다. 값이 0이면 1로 수정하여 획득 프로세스를 완료합니다. 액세스된 값이 0이 아니면 잠금 획득이 실패합니다. 이전에 잠금을 획득한 경우 잠금을 나타내는 변수의 값이 다음과 같이 수정됩니다. 0. 실제로는 잠금을 해제하는 동작입니다.
분산 시나리오에서 리소스 잠금을 나타내는 변수를 공유 스토리지 시스템에 저장해야 한다는 점을 제외하면 잠금을 구현하는 방법은 동일합니다. 이 공유 스토리지 시스템은 Redis이거나 데이터 스토리지를 제공할 수 있는 다른 시스템일 수 있습니다.
Redis를 공유 저장소 시스템으로 사용하는 경우 특정 리소스의 잠금을 나타내는 변수가 Redis 값 쌍의 키가 됩니다. . 분산 잠금으로 추가해야 하는 리소스를 리소스_a라고 하면 Redis lock_a에서 리소스_a의 잠금 변수 키를 호출할 수 있습니다.
예를 들어 노드 1이 잠금을 획득해야 하는 경우 Redis의 lock_a 값에 액세스합니다. 획득한 값이 0이라고 가정하면 노드 1은 이 값을 1로 설정한 후 잠금 작업을 완료합니다. 이때 노드 2도 Resource_a의 잠금을 획득해야 하는데 Redis에서 lock_a 값에 액세스하여 값이 1인 것을 확인합니다. 이는 다른 노드에서 잠금을 획득하고 해제되지 않았음을 나타냅니다. 두 개는 Resource_a 리소스를 잠그는 데 실패합니다.
노드 1이 잠금을 해제해야 하는 경우 Redis의 lock_a 값을 0으로 설정하기만 하면 잠금 해제가 완료되고 나면 다른 노드가 다시 리소스 잠금을 획득할 수 있습니다.
위 설명에서 잠금은 단일 작업이 아니라 잠금 변수 읽기, 변수 값 판단, 잠금 변수 수정 등 여러 단계로 구성됩니다. 이 세 가지 작업은 원자적이어야 합니다.
Redis에는 키-값 쌍의 값을 설정하는 데 사용되는 SETNX 명령이 있습니다. SET 명령과 달리 지정된 KEY가 존재하는 경우에만 키-값 쌍이 존재하는지 여부를 미리 결정합니다. 존재하지 않으면 해당 값의 설정을 실행하고, 그렇지 않으면 아무 것도 실행되지 않습니다. SETNX는 "SET if Not eXist"를 의미합니다. 사용법은 SET과 동일합니다.
SETNX lock_a 1
이렇게 잠금을 획득해야 할 경우 SETNX 명령을 사용하여 lock_a에 값을 설정합니다. 설정이 성공하면 잠금을 획득합니다. 잠금이 획득되지 않았습니다. 잠금을 해제해야 할 경우 DEL 작업을 사용하여 키-값 쌍을 삭제하면 됩니다.
이것은 잠금을 획득하고 해제하는 원자적 작업을 달성합니다.
다음으로 고려해야 할 점은 노드가 잠금을 획득하면 프로그램 예외나 다른 이유로 인해 잠금이 절대 해제되지 않는다는 것입니다. 남아있어 보유하고 해제할 수 없으며 다른 노드가 리소스에 액세스할 수 없습니다.
이러한 상황을 방지하려면 잠금 변수의 만료 시간을 설정해야 합니다. 잠금 변수가 만료되면 잠금을 다시 요청하여 이 문제를 피할 수 있습니다.
SETNX 명령에는 만료 시간을 설정하는 옵션이 없습니다. 다행히 Redis는 SET 명령에 대해 SETNX를 시뮬레이션하는 NX 옵션을 제공합니다.
SET lock_a 1 NX PX 10000
위 명령은 lock_a 존재하지 않는 경우 해당 값은 1로 설정되고 10초 후에 만료됩니다.
마지막 문제는 노드 1이 잠금을 획득하고 어떤 이유로 노드 2가 DEL 작업을 수행하면 다른 노드가 다시 잠금을 획득할 수 있다는 것입니다.
이 문제를 해결하기 위해 잠금 변수에 저장된 내용을 수정하면 됩니다. 이전 로직에서는 잠금을 적용할 때 잠금 변수가 존재하는지 판단하는데, 그 안에 저장된 값과 거의 관련이 없으므로 이 값을 사용할 수 있습니다.
잠금을 걸 때 값이 각 노드의 고유 식별자로 저장되면 잠금을 해제하고 DEL을 실행하기 전에 값을 판단한 다음 현재 노드에 잠금이 추가되었는지 여부를 먼저 판단할 수 있습니다. 그런 다음 잠금을 해제하면 "자물쇠를 잠그는 사람이 잠금을 해제합니다"라는 것을 깨닫게 됩니다.
이 부분에서는 잠금 변수를 읽고 판단하고 삭제하는 작업을 완료할 수 있는 단일 명령이 없으므로 Lua 스크립트를 사용하여 구현할 수 있습니다. 스크립트에서 현재 잠금 변수의 값을 가져와 지정된 노드 식별자와 비교합니다. 일치하면 삭제 작업이 수행되지 않습니다.
잠금을 해제할 때 Lua 스크립트를 실행하면 됩니다.
기능 개선 후 최종적으로 고가용성을 구현합니다. 단일 Redis를 분산 잠금용 공유 스토리지 시스템으로 사용하는 경우 이 Redis를 사용할 수 없으면 분산 잠금과 관련된 모든 부분을 사용할 수 없게 됩니다. 이는 매우 취약한 잠금이므로 필요한 고가용성에 매우 효과적입니다. .
이때 Redis의 저자인 Antirez가 제안한 분산 잠금 알고리즘인 Redlock을 옮겨야 합니다. 즉, 잠금 신청자는 여러 독립 Redis 인스턴스에서 잠금을 요청하라는 요청을 받습니다. Redis 인스턴스의 절반 이상에서 잠금 작업을 완료할 수 있으면 잠금이 성공적으로 획득되고 그렇지 않으면 획득이 실패합니다.
잠금 해제 작업에서도 잠금 변수를 성공적으로 삭제한 Lua 스크립트가 인스턴스의 절반 이상에서 실행되면 성공으로 간주됩니다.
더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 소개를 방문하세요! !
위 내용은 Redis는 분산 잠금을 어떻게 구현합니까? 구현 방법에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!