Redis 는 어떻게 분포 식 잠 금 을 실현 합 니까?
자바 의 병렬 프로 그래 밍 에서 우 리 는 자 물 쇠 를 통 해 경쟁 으로 인 한 데이터 불일치 문 제 를 피한다.보통 우 리 는
synchronized 、Lock
으로 그것 을 사용한다.그러나 자바 의 잠 금 은 같은 JVM 프로 세 스 에서 만 실 행 될 수 있 습 니 다.분포 식 군집 환경 에서 분포 식 자물쇠 가 필요 하 다.
일반적인 분포 식 잠 금 의 실현 방식 은 redis,zookeeper 가 있 지만 보통 우리 프로그램 에 서 는 redis 를 사용 하고 redis 로 분포 식 잠 금 을 만 들 며 원 가 를 낮 출 수 있 습 니 다.
2.실현 원리
2.1 자물쇠 추가
잠 금 을 추가 하 는 것 은 실제 redis 에서 키 키 키 에 값 을 설정 하고 잠 금 을 피하 기 위해 만 료 시간 을 정 하 는 것 입 니 다.
Redis 2.6.12 및 그 전에 setnx key value(key 가 존재 하지 않 아야 설정 성공)를 통 해 값 을 설정 할 수 있 습 니 다.expire key 를 통 해 seconds 설정 만 료 시간 입 니 다.그러나 두 명령 이기 때문에 원자의 것 이 아니다.값 을 설정 한 후에 만 료 시간 을 설정 하지 못 하면 프로그램 이 끊 어 지면 이 key 는 redis 에 영원히 존재 합 니 다.
Redis 2.6.12 이후 redis 는 set key value EX seconds NX 와 set key value PX millisecond NX 를 제공 했다. 원자 적 인 설정 값 과 만 료 시간 을 설정 합 니 다.
2.2 잠 금 해제
잠 금 을 푸 는 과정 은 키 키 를 삭제 하 는 것 입 니 다.그러나 함부로 삭제 할 수도 없고 클 라 이언 트 1 의 요청 이 클 라 이언 트 2 의 자 물 쇠 를 삭제 했다 고 할 수도 없고 삭제 하기 전에 설 정 된 value 인지 아 닌 지 를 판단 해 야 한다.
잠 금 해제 작업 의 원자 성 을 확보 하기 위해 서,우 리 는 LUA 스 크 립 트 로 이 작업 을 완성 합 니 다.현재 잠 겨 있 는 문자열 이 들 어 오 는 값 과 같은 지 먼저 판단 합 니 다.그렇다면 Key 를 삭제 하고 잠 금 을 푸 는 데 성 공 했 습 니 다.LUA 스 크 립 트 는 다음 과 같 습 니 다.
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
3.RedisTemplate 를 통 해 분포 식 잠 금 실현SpringBoot 를 통 해 구 축 된 프로그램 은 일반적으로 RedisTemplate 로 캐 시 redis 를 조작 합 니 다.레 디 스 템 플 릿 을 기반 으로 분포 식 잠 금 을 실현 하 는 것 을 소개 한다.
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class RedisLockUtil {
@Autowired
private RedisTemplate redisTemplate;
//
private long timeout = 60000;
/**
*
* @param key
* @param value
* @param ms
* @return
*/
public Boolean getLock(String key, String value, Long ms) {
long startTime = System.currentTimeMillis();
while (true) {
Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, value, ms, TimeUnit.MILLISECONDS);
if (flag) {
return true;
}
//
if (System.currentTimeMillis() - startTime > timeout) {
return false;
}
try {
log.info("{} ", key);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
*
* @param key
* @param value
* @return
*/
public Boolean unLock(String key, String value) {
String script =
"if redis.call('get',KEYS[1]) == ARGV[1] then" +
" return redis.call('del',KEYS[1]) " +
"else" +
" return 0 " +
"end";
// RedisScript
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
// :redisScript, :key , :arg( )
Object result = redisTemplate.execute(redisScript, Arrays.asList(key), value);
return "1".equals(result.toString());
}
}
4.Redisson 을 통 해 실현Redisson 은 우 리 를 위해 세부 사항 을 봉 하여 상 자 를 열 고 바로 사용 할 수 있 습 니 다.
maven 의존 도입:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.14.0</version>
</dependency>
설정 클래스:
import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* redisson
*/
@Configuration
@Data
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedissonClient getRedisson(){
Config config = new Config();
config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
//
// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});
return Redisson.create(config);
}
}
redis 속성 설정:
spring:
redis:
host: 127.0.0.1
port: 6379
password: root
봉 인 된 잠 금 해제 도구 종류:
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* redis
*/
@Component
public class RedissLockUtil {
@Autowired
private RedissonClient redissonClient;
/**
*
* @param lockKey
* @return
*/
public RLock lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
/**
*
* @param lockKey
*/
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
/**
*
* @param lock
*/
public void unlock(RLock lock) {
lock.unlock();
}
/**
*
* @param lockKey
* @param timeout :
*/
public RLock lock(String lockKey, int timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, TimeUnit.SECONDS);
return lock;
}
/**
*
* @param lockKey
* @param unit
* @param timeout
*/
public RLock lock(String lockKey, TimeUnit unit , int timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
/**
*
* @param lockKey
* @param waitTime
* @param leaseTime
* @return
*/
public boolean tryLock(String lockKey, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return false;
}
}
/**
*
* @param lockKey
* @param unit
* @param waitTime
* @param leaseTime
* @return
*/
public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
}
}
레 디 스 가 분포 식 잠 금 을 어떻게 실현 하 는 지 에 대한 상세 한 설명 은 여기까지 입 니 다.레 디 스 분포 식 잠 금 내용 에 대해 서 는 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부탁드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
그래프 구조를 무상으로 취급할 수 없는 것은 싫기 때문에, redisgraph를 WSL2에 극치고 설치해 보았습니다.제목은 만우절이므로. 그렇다, 역시, 앞으로는 그래프 구조 데이터베이스라고 생각했다. 생각한 것은 몇 년 전인가. 전부터 Neo4j는 시험하고 있지만, 영업 분들로부터 상용 라이센스가 높다고 가르쳐 주었으므로, 전전...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.