ASP.Net Core 에서 CSRedis 를 통 해 안전 하고 효율 적 인 분포 식 자 물 쇠 를 어떻게 실현 하 는 지 상세 하 게 설명 합 니 다.
질문:
(1)여기 setnx 가 설정 한 값"1"입 니 다.마지막 으로 del 의 이 값 은 반드시 당신 이 만 든 것 입 니까?
(2)그림 에 표 시 된 절차 1 과 절차 2 는 원자 조작 이 아니 라 잠 금 이 걸 릴 확률 이 있 습 니까?
먼저 생각해 보 세 요.다음은 이 두 가지 문 제 를 가지 고 아래 를 보 겠 습 니 다.다음은 Redis 를 사용 하여 분포 식 잠 금 을 실현 하 는 데 자주 사용 되 는 몇 가지 명령 을 소개 합 니 다.
1.Redis 를 사용 하여 분포 식 잠 금 에서 흔히 볼 수 있 는 몇 가지 명령 을 실현 합 니 다.
► Setnx
명령:SETNX key value
설명:키 의 값 을 value 로 설정 하고 키 만 존재 하지 않 는 다.주어진 키 가 존재 한다 면 SETNX 는 아무런 동작 도 하지 않 습 니 다.SETNX 는"SET if Not eXists"(존재 하지 않 으 면 SET)의 약자 입 니 다.
시간 복잡 도:O(1)
반환 값:설정 성공,반환 1;설정 실패,0 되 돌리 기
► Getset
명령:GETSET key value
설명:주어진 key 의 값 을 value 로 설정 하고 key 의 이전 값(old value)을 되 돌려 줍 니 다.키 가 존재 하지만 문자열 형식 이 아 닐 때 오 류 를 되 돌려 줍 니 다.
시간 복잡 도:O(1)
반환 값:주어진 key 의 이전 값 을 되 돌려 줍 니 다.키 가 오래된 값 이 없 을 때,즉 키 가 존재 하지 않 을 때,nil 로 돌아 갑 니 다.
► Expire
명령:EXPIRE key seconds
설명:키 에 게 생존 시간 을 설정 하기 위해 키 가 만 료 될 때(생존 시간 0)자동 으로 삭 제 됩 니 다.
시간 복잡 도:O(1)
반환 값:설정 성공 반환 1;key 가 존재 하지 않 거나 key 에 생존 시간 을 설정 할 수 없 을 때(예 를 들 어 2.1.3 버 전보 다 낮은 Redis 에서 key 의 생존 시간 을 업데이트 하려 고 시도)0 으로 돌아 갑 니 다.
► Del
명령:DEL key[key...]
설명:주어진 키 하나 이상 을 삭제 합 니 다.존재 하지 않 는 키 는 무 시 됩 니 다.
시간 복잡 도:O(N);N 은 삭 제 된 키 의 개수 입 니 다.
단일 문자열 형식의 key 를 삭제 합 니 다.시간 복잡 도 는 O(1)입 니 다.
단일 목록,집합,질서 있 는 집합 또는 해시 표 형식의 key 를 삭제 합 니 다.시간 복잡 도 는 O(M)이 고 M 은 상기 데이터 구조 내의 요소 수량 입 니 다.
반환 값:키 가 삭 제 된 수량 입 니 다.
자,명령 이 익숙해 지면 분포 식 자 물 쇠 를 하나씩 실현 하기 시작 합 니 다.
2.Redis 를 사용 하여 분포 식 잠 금 버 전 1:시간 스탬프 와 의 결합
위의 setnx 설정 의 기본 값 1 에 대해 우 리 는 시간 스탬프 를 사용 하여 문 제 를 방지 합 니 다.첫째,다음은 당연히 작성 하고 자 하 는 프로 세 스 도 를 살 펴 보 겠 습 니 다.
흐름 도:
C\#코드 구현:
static void Main(string[] args)
{
var lockTimeout = 5000;//
var currentTime = DateTime.Now.ToUnixTime(true);
if (SetNx("lockkey", currentTime+ lockTimeout,lockTimeout))
{
//TODO:
//.....
//.....
//
Remove("lockkey");
}
else
{
Console.WriteLine(" ");
}
Console.ReadKey();
}
public static bool SetNx(string key,long time ,double expireMS)
{
if (redisClient.SetNx(key, time))
{
if (expireMS > 0)
redisClient.Expire(key, TimeSpan.FromMilliseconds(expireMS));
return true;
}
return false;
}
public static bool Remove(string key)
{
return redisClient.Del(key) > 0;
}
위의 코드 에서 value 의 값 은 시간 스탬프 를 사용 합 니 다.고정된 값 이 아 닙 니 다.적어도 삭 제 된 key 가 자신의 것 임 을 보증 할 수 있 습 니 다.따라서 value 의 값 을 설정 할 때 고정된 값 을 설정 하지 말고 무 작위 로 하 는 것 이 좋 습 니 다.그러나 이렇게 쓰 면 문제 가 해결 되 었 지만 이런 쓰 기 는 어느 정도 위험 이 존재 합 니 다.Redis 는 단일 스 레 드 이 고 setnx,expire 는 원자 조작 이지 만 먼저 setnx 를 한 다음 에 expire 는 원자 조작 이 아 닙 니 다!!우 리 는 다 중 스 레 드 환경 과 용기 배치 시 다 중 인 스 턴 스 환경 등 을 고려 해 야 한다.그러면 이런 쓰기 에 문제 가 생 길 것 이다.예 를 들 어 현재 A,B 두 대의 서버 가 이 애플 리 케 이 션 을 달리 고 있 습 니 다.A 대 애플 리 케 이 션 이 달 려 갔 을 때 setnx 가 성공 하지만 기한 이 지난 시간 을 설정 하지 않 았 을 때 갑자기 서 비 스 를 다시 시작 합 니 다.이 럴 때 분포 식 환경 에서 잠 금 문제 가 발생 합 니 다.기한 이 지난 시간 을 설정 하지 않 았 기 때 문 입 니 다.
다음은 디 버 깅 을 통 해 잠 겨 있 는 장면 을 보 여 드 리 겠 습 니 다.
A 응용 프로그램:setnx 가 성공 적 으로 실행 되 었 으 나 expire 를 실행 하기 전에 다운 되 었 습 니 다.이때 Redis 는 데이터 가 있 지만 기한 이 지나 지 않 았 습 니 다.
B 적용:정상 작 동
하지만 B 앱 은 자 물 쇠 를 계속 가 져 오지 못 해 자물쇠 가 사라 진다.
그래서 위 에서 자 물 쇠 를 얻 는 논리 에 문제 가 있 습 니 다.이 문 제 를 해결 하기 위해 우 리 는 아래 의 방식 으로 처리 합 니 다.
3.Redis 를 사용 하여 분포 식 잠 금 버 전 2:이중 잠 금 방지
흐름 도:
C\#코드 구현:
public static void RedisLockV2()
{
var lockTimeout = 5000;//
var currentTime = DateTime.Now.ToUnixTime(true);
if (SetNxV2("lockkey",DateTime.Now.ToUnixTime(true)+lockTimeout))
{
//
redisClient.Expire("lockkey", TimeSpan.FromMilliseconds(5000));
//TODO:
Console.WriteLine(" ing");
Thread.Sleep(100000);
Console.WriteLine(" ed");
//
Remove("lockkey");
}
else
{
// , ,
var lockValue = redisClient.Get("lockkey");
var time = DateTime.Now.ToUnixTime(true);
if (!string.IsNullOrEmpty(lockValue) && time> lockValue.ToInt64())
{
// getset
// key ,
var getsetResult = redisClient.GetSet("lockkey", time);
if (getsetResult == null || (getsetResult != null && getsetResult == lockValue))
{
Console.WriteLine(" Redis ");
//
redisClient.Expire("lockkey", TimeSpan.FromMilliseconds(5000));
//TODO:
//.....
//.....
Console.WriteLine(" ");
//
Remove("lockkey");
}
else
{
Console.WriteLine(" ");
}
}
else
{
Console.WriteLine(" ");
}
}
}
현재 Redis 의 상황 은 다음 과 같다.우 리 는 위의 코드 를 실행 합 니 다.결 과 는 다음 과 같 습 니 다.
복사 본.exe 에 코드 를 추가 합 니 다.이러한 장면 을 모 의 한다.A,B 두 대의 서버 가 이 응용 프로그램 을 달리 고 있다.A 대 응용 프로그램 이 달 려 가면 setnx 가 성공 하지만 기한 이 지난 시간 을 설정 하지 않 았 을 때 갑자기 서 비 스 를 다시 시작 하면 분포 식 환경 에서 잠 금 문제 가 발생 한다.왜냐하면 기한 이 지난 시간 을 설정 하지 않 았 기 때문이다.
Lottery.ThriftRpc-던 전.exe 를 먼저 실행 합 니 다.Redis 에 값 이 있 으 면 이 key 는 만 료 시간 이 없 으 면 프로그램 을 닫 습 니 다.
그리고 Lottery.ThriftRpc.exe 를 실행 합 니 다.
보 세 요.우리 가 이 문 제 를 해 결 했 는 지,기한 이 지난 시간 을 얼마 로 설정 하 는 지 에 대해 서 는 당신 의 구체 적 인 업무 처리 시간 과 결합 하여 합 리 적 인 가 치 를 계산 해 야 합 니 다.자,여기까지 이야기 하 겠 습 니 다.Redis 의 분포 식 자물쇠 에 대해 말씀 드 리 겠 습 니 다.도움 이 되 기 를 바 랍 니 다.감사합니다.
4.요약:
위의 예제 에서 Redis 의 구성 요 소 는 CSRedisCore 를 사 용 했 습 니 다.여 기 는 단지 자신의 경험 일 뿐 입 니 다.만약 에 더 좋 은 방법 이 있다 면 평론 구역 에서 토론 할 수 있 습 니 다.Redis 의 이론 에 대한 설명 이 너무 많은 글 이 있 습 니 다.여러분 은 참고 하 셔 도 됩 니 다.Redis 에 관 한 글 은 저 는 작업 과정 에서 만난 문제 만 정리 하고 글 중의 소스 코드 에 대해 서 는 제공 하지 않 겠 습 니 다.너무 간단 합 니 다.앞으로 레 디 스 문 제 를 비정 기적 으로 공유 하 겠 습 니 다.많은 응원 부 탁 드 리 겠 습 니 다.
위 에서 말 한 것 은 편집장 이 여러분 에 게 소개 한 ASP.Net Core 에서 CSRedis 를 통 해 안전 하고 효율 적 인 분포 식 자물쇠 의 상세 한 통합 을 실현 하 는 방법 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 저 에 게 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!