Redis는 키-값 쌍으로 데이터를 저장하는 인 메모리 데이터베이스로 유명하다.
기본적으로 메모리에 데이터를 저장하므로 휘발성이지만, RDB와 AOF 기능을 이용하여 데이터를 디스크에 영구적으로 저장할 수 있다.
Redis에 저장될 수 있는 데이터 유형에는 문자열, 리스트, 집합, 정렬된 집합 등이 존재한다.
데이터 유형에 대한 자세한 내용은 문서에서 확인할 수 있다.
Spring Data Redis는 Spring 애플리케이션에서 Redis를 사용하기 위한 손쉬운 설정과 접근방법을 제공하는 모듈이다.
우선 환경테스트를 진행하기 위해서는 Redis 서버가 구동중인 상태여야 한다.
작성자는 윈도우 환경에서 WSL2를 이용하여 Redis 서버를 설치하고 구동했다
기본적인 Redis 구동 포트는 6379 다
Redis 통신을 위한 핵심적인 인터페이스는 RedisConnection
과 이를 생성하는 RedisConnectionFactory
다.
RedisConnection
는 Redis와의 상호작용을 수행한다.
RedisConnectionFactory
는 이러한 RedisConnection
을 생성하는 팩토리 클래스이며, PersistenceExceptionTranslator
인터페이스를 구현하기 때문에 데이터 접근 중에 발생하는 예외를 Spring 예외 계층으로 변환해주는 역할도 수행한다.
RedisConnection
은 기본적으로 스레드 안전하지 않다.
따라서, 멀티 스레드 환경에서 이를 공유하려 한다면 native connection을 획득하고, redis 클라이언트 API를 직접 사용해야한다.
RedisConnectionFactory
를 사용하기 위해서는 Spring의 IoC 컨테이너를 이용하여 적절한 접근 Connector를 주입받아야 한다.
대표적으로 사용되는 Redis Connector는 Lettuce
와 Jedis
가 있다.
Lettuce
는 Netty 기반의 오픈소스 커넥터다.
LettuceConnectionFactory
을 통해 LettuceConnection
을 생성해내며,
기본적으로 non-blocking, non-transactional 작업에 대해 스레드 안전한 native 연결을 공유한다.
즉, LettuceConnection
객체는 동일한 Redis 연결을 공유하며 스레드 안전하게 관리된다.
@Configuration
class AppConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
}
}
Jedis
는 커뮤니티 기반의 커넥터다.
JedisConnectionFactory
을 통해 JedisConnection
을 생성해내며,
기본적으로 비동기방식을 사용하지 않기때문에, 비동기 작업을 위해서는 별도의 클러스터나 비동기 API를 사용해야한다.
@Configuration
class RedisConfiguration {
@Bean
public JedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("server", 6379);
return new JedisConnectionFactory(config);
}
}
Redis가 동작할 수 있는 여러가지의 실행 모드들을 의미하며, 각 모드에서는 섹션별로 소개되는 특정한 구성이 필요하다.
가장 쉽게 시작할 수 있는 방법으로, 단일 Redis 서버와 함께 사용된다.
아래와 같이 LettuceConnectionFactory
나 JedisConnectionFactory
를 구성한다
@Configuration
class RedisStandaloneConfiguration {
/**
* Lettuce
*/
@Bean
public RedisConnectionFactory lettuceConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
}
/**
* Jedis
*/
@Bean
public RedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
}
}
데이터를 여러 노드에 복제하여 읽기 성능을 향상시킬 수 있는 방법이다.
자동 failover는 지원하지 않지만, 데이터를 더 많은 노드에 안전하게 복사하므로 읽기성능을 분산시킬 수 있다.
또한, Lettuce
를 사용하면 Master에 쓰기를 푸시하는 동안 Replica에서 데이터를 읽을 수 있다.
아래 코드처럼 LettuceConnectionFactory
를 사용하여 읽기/쓰기 전략을 선택할 수 있다.
@Configuration
class WriteToMasterReadFromReplicaConfiguration {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(REPLICA_PREFERRED)
.build();
RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration("server", 6379);
return new LettuceConnectionFactory(serverConfig, clientConfig);
}
}
고가용성 Redis를 처리하기 위한 방법으로, RedisSentinelConfiguration
를 사용한 Redis Sentinel을 지원한다.
이 모드는 Master/Replica와 다르게 자동 failover를 지원하므로, Master 노드에 문제가 생기면 새로운 Master 노드가 선택된다.
Sentinel 노드의 과반수 이상이 Master 노드의 이상을 감지하면 Master 노드가 변경된다
/**
* Lettuce
*/
@Bean
public RedisConnectionFactory lettuceConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("127.0.0.1", 26379)
.sentinel("127.0.0.1", 26380);
return new LettuceConnectionFactory(sentinelConfig);
}
/**
* Jedis
*/
@Bean
public RedisConnectionFactory jedisConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("127.0.0.1", 26379)
.sentinel("127.0.0.1", 26380);
return new JedisConnectionFactory(sentinelConfig);
}
프로퍼티 파일에 관련 정보를 작성한 경우,
RedisSentinelConfiguration.of(PropertySource)
를 통해 객체를 생성하는 것도 가능하다. 관련 정보
센티넬 중 하나와 직접 상호작용 해야하는 경우,
RedisConnectionFactory.getSentinelConnection()
나 RedisConnection.getSentinelCommands()
를 사용하여 첫 번째 활성 센티넬에 접근할 수 있다.
데이터 분산과 자동 failover를 지원하는 설정으로, 여러 노드를 통한 수평적 확장과 해시 슬롯이 주요 특징이다.
여러개의 Master 노드를 보유할 수 있으며, 16384개의 해시 슬롯으로 key 공간을 나누어 관리한다.
Spring Data Redis에서의 구성방식은 아래와 같다.
@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {
/*
* spring.redis.cluster.nodes[0] = 127.0.0.1:7379
* spring.redis.cluster.nodes[1] = 127.0.0.1:7380
* ...
*/
List<String> nodes;
/**
* Get initial collection of known cluster nodes in format {@code host:port}.
*
* @return
*/
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}
@Configuration
public class AppConfig {
/**
* Type safe representation of application.properties
*/
@Autowired ClusterConfigurationProperties clusterProperties;
public @Bean RedisConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(
new RedisClusterConfiguration(clusterProperties.getNodes()));
}
}