[REDIS] 잠금과 분산 증가를 레디 스
REDIS잠금과 분산 증가를 레디 스
나는 몇 가지 API 호출로 전송 될 것 카운터를 생성하기위한 요구 사항을 가지고있다. 나는 고유 카운터를 생성하고 싶었 어떻게 내 응용 프로그램 때문에 약간의 여러 노드에서 실행됩니다. 나는 다음과 같은 코드를 시도
public static long GetTransactionCountForUser(int telcoId)
{
long valreturn = 0;
string key = "TelcoId:" + telcoId + ":Sequence";
if (Muxer != null && Muxer.IsConnected && (Muxer.GetDatabase()) != null)
{
IDatabase db = Muxer.GetDatabase();
var val = db.StringGet(key);
int maxVal = 999;
if (Convert.ToInt32(val) < maxVal)
{
valreturn = db.StringIncrement(key);
}
else
{
bool isdone = db.StringSet(key, valreturn);
//db.SetAdd(key,new RedisValue) .StringIncrement(key, Convert.ToDouble(val))
}
}
return valreturn;
}
그리고 실행은 작업 병렬 라이브러리를 통해 테스트. 내가 경계 값을 가질 때 내가 볼 것은 여러 시간 0 항목이 세트는 점이다
제가 할 필요가 무엇 보정 알려주세요
최신 정보: 내 마지막 논리는 다음과 같다
public static long GetSequenceNumberForTelcoApiCallViaLuaScript(int telcoId)
{
long valreturn = 0;
int maxIncrement = 9999;//todo via configuration
if (true)//todo via configuration
{
IDatabase db;
string key = "TelcoId:" + telcoId + ":SequenceNumber";
if (Muxer != null && Muxer.IsConnected && (db = Muxer.GetDatabase()) != null)
{
valreturn = (int)db.ScriptEvaluate(@"
local result = redis.call('incr', KEYS[1])
if result > tonumber(ARGV[1]) then
result = 1
redis.call('set', KEYS[1], result)
end
return result", new RedisKey[] { key }, flags: CommandFlags.HighPriority, values: new RedisValue[] { maxIncrement });
}
}
return valreturn;
}
해결법
-
==============================
1.의 조건이 "수"여전히 적용된다는 것을 확인하지 않고 - 당신이, (대기 시간과 생각) "GET", "설정"을하고 있기 때문에 실제로 코드는 롤오버 경계 주변에 안전하지 않습니다. 서버가 항목 1,000의 주위에 바쁜 경우는 같은 것들을 포함 미친 출력, 모든 종류의를 얻을 수있을 것입니다 :
의 조건이 "수"여전히 적용된다는 것을 확인하지 않고 - 당신이, (대기 시간과 생각) "GET", "설정"을하고 있기 때문에 실제로 코드는 롤오버 경계 주변에 안전하지 않습니다. 서버가 항목 1,000의 주위에 바쁜 경우는 같은 것들을 포함 미친 출력, 모든 종류의를 얻을 수있을 것입니다 :
1 2 ... 999 1000 // when "get" returns 998, so you do an incr 1001 // ditto 1002 // ditto 0 // when "get" returns 999 or above, so you do a set 0 // ditto 0 // ditto 1
옵션 :
이제 어려운 (옵션 1 당) 거래 레디 스. 개인적으로, 나는 "2"를 사용하십시오 - 또한 코드 및 디버그에 간단하게되고, 그것은, 간부 / 시계 "에 도착 반대 만 멀티, 증분 / 세트, 얻을, 1 왕복 및 작업을 의미 폐기 ", 그리고"를 중단 시나리오에 대한 계정에 재시도 처음부터 "루프. 이 4 선에 대해해야 - 만약 당신이 좋아하면, 나는 당신을 위해 루아로 작성하려고 할 수 있습니다.
여기에 루아 구현입니다 :
string key = ... for(int i = 0; i < 2000; i++) // just a test loop for me; you'd only do it once etc { int result = (int) db.ScriptEvaluate(@" local result = redis.call('incr', KEYS[1]) if result > 999 then result = 0 redis.call('set', KEYS[1], result) end return result", new RedisKey[] { key }); Console.WriteLine(result); }
참고 : 최대를 파라미터해야하는 경우 사용합니다 :
if result > tonumber(ARGV[1]) then
과:
int result = (int)db.ScriptEvaluate(..., new RedisKey[] { key }, new RedisValue[] { max });
(ARGV는 [1]에서 최대 값을 취하므로)
그것은 이해하는 것이 필요하다고 평가 / evalsha 증분 및 가능한 세트 사이에 아무것도 변화하므로, 다른 서버 요청과 경쟁하지 않는 (ScriptEvaluate 이른바이다). 이 방법은 우리는 등의 논리 복잡한 시계가 필요하지 않습니다.
여기에 거래 / 제약 API를 통해 (! 나는 생각한다) 동일합니다 :
static int IncrementAndLoopToZero(IDatabase db, RedisKey key, int max) { int result; bool success; do { RedisValue current = db.StringGet(key); var tran = db.CreateTransaction(); // assert hasn't changed - note this handles "not exists" correctly tran.AddCondition(Condition.StringEqual(key, current)); if(((int)current) > max) { result = 0; tran.StringSetAsync(key, result, flags: CommandFlags.FireAndForget); } else { result = ((int)current) + 1; tran.StringIncrementAsync(key, flags: CommandFlags.FireAndForget); } success = tran.Execute(); // if assertion fails, returns false and aborts } while (!success); // and if it aborts, we need to redo return result; }
복잡, 응? 여기에 간단한 성공 사례는 다음입니다 :
GET {key} # get the current value WATCH {key} # assertion stating that {key} should be guarded GET {key} # used by the assertion to check the value MULTI # begin a block INCR {key} # increment {key} EXEC # execute the block *if WATCH is happy*
이는입니다 ... 아주 작품의 비트, 그리고 멀티플렉서에 파이프 라인 스톨을 포함한다. 더 복잡한 경우 (주장 실패, 시계 장애, 랩 - 어라운드)는 약간 다른 결과를 가지고,하지만 작동합니다.
-
==============================
2.당신은 시계 명령을 사용할 수 있습니다 - 이런 식으로, 값이 변경되면, 당신은 알림을받을 수 있습니다
당신은 시계 명령을 사용할 수 있습니다 - 이런 식으로, 값이 변경되면, 당신은 알림을받을 수 있습니다
from https://stackoverflow.com/questions/34871567/redis-distributed-increment-with-locking by cc-by-sa and MIT license
'REDIS' 카테고리의 다른 글
[REDIS] SQL과 같은 디자인 레디 스 데이터베이스 테이블? (0) | 2020.01.05 |
---|---|
[REDIS] 레디 스 직렬화 및 역 직렬화 (0) | 2020.01.05 |
[REDIS] ELK 스택 레디 스의 점은 무엇인가? (0) | 2020.01.05 |
[REDIS] 잠금 및 레디 스 (0) | 2020.01.05 |
[REDIS] 레일 레디 스 펍 / 하위 (0) | 2020.01.05 |