Redis란?
The open-source, in-memory data store used by millions of developers as a cache, vector database, document database, streaming engine, and message broker.
레디스는 key-value 구조의(즉 NoSQL) in-memory 데이터베이스로, 캐싱, 백터 DB 등에 사용된다. 여기서는 SpringBoot 애플리케이션에서, RDB의 데이터를 캐싱하고 조회하는 데에 사용하려고 한다.
로컬에 Redis 설치
(윈도우) 아래에서 3.0.504 버전의 .msi
확장자 Redis 설치 프로그램을 다운로드한다.
설치 프로그램을 실행해준다. 레디스 설치 경로는 기본 세팅으로 놔둔다.
레디스 실행 포트도 기존인 6379로
놔둔다.
메모리 리미트는 설정하지 않는다.
install 버튼을 눌러서 설치한다. 설치가 완료된 후, 설치된 경로로 가서 redis-cli.exe
를 실행한다.
ping
명령어를 보내면 PONG
으로 정상적으로 답변이 오는 것을 볼 수 있다.
같이 사용할 DB 설치
레디스의 캐싱을 테스트하려면 DB가 설치되어 있어야 한다. 여기서는 간단하게 H2 database를 설치하는 것으로 한다.
build.gradle에 종속성 추가
다음과 같이 종속성을 추가한다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
application.yml 설정
아래와 같이 localhost, 6379로 설정한다.
spring:
data:
redis:
host: localhost
port: 6379
RedisConfig.java 설정
LettuceConnectionFactory(host, port)
는 아주 기본적인 설정 방식이고, RedisStandaloneConfiguration
과 LettuceClientConfiguration
는 좀 더 세부적인 설정이 가능한 방식이다.
import java.time.Duration;
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
/* Use Lettuce for Redis(Jedis has been deprecated since Springboot 2.0) */
@Bean
public RedisConnectionFactory redisConnectionFactory() {
/* Most basic configuration */
//return new LettuceConnectionFactory(host, port);
/* Detailed configuration */
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration(host, port);
LettuceClientConfiguration clientConfig =
LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(1)) //No longer than 1 second
.shutdownTimeout(Duration.ZERO) //Immediately shutdown after application shutdown
.build();
return new LettuceConnectionFactory(redisConfig, clientConfig);
}
}
방법 1: RedisRepository 사용
Spring Data Redis를 사용하여 구현된 리포지토리(repository)는 RDB(관계형 데이터베이스)에 저장하는 동시에 Redis에도 저장된다. 따라서 리포지토리를 통해 데이터를 저장하면 RDB에 저장되는 동시에 Redis에도 저장된다.
또한, 서비스(service)에서 데이터를 조회할 때에도 Spring Data Redis는 Redis 캐시를 먼저 확인한다. 이 경우 Redis에 해당 데이터가 캐시되어 있다면, RDB에 대한 추가적인 요청을 보내지 않고 캐시된 데이터를 반환한다. 이는 데이터베이스 액세스 비용을 줄이고 성능을 향상시킬 수 있다.
SampleRedisEntity.java 생성
@Getter
@RedisHash(value = "entity", timeToLive = 30)
//Value will be redis keyspace
//timeToLive will be seconds
public class SampleRedisEntity {
/*Redis Key = keyspace:id */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Builder
public SampleRedisEntity(Long id){
this.id = id;
}
}
CrudRepository.java 생성
public interface SampleRedisRepository extends CrudRepository<SampleRedisEntity, Long> {
}
SampleRedisRepositoryTest.java 생성
@SpringBootTest
class SampleRedisRepositoryTest {
@Autowired
SampleRedisRepository sampleRedisRepository;
@Test
void test() {
//Use Redis as same as JPA.
SampleRedisEntity sampleRedisEntity = SampleRedisEntity.builder().build();
sampleRedisRepository.save(sampleRedisEntity);
// Get 'keyspace:id'
sampleRedisRepository.findById(sampleRedisEntity.getId());
// Get number of key in @RedisHash's keyspace(entity)
sampleRedisRepository.count();
sampleRedisRepository.delete(sampleRedisEntity);
}
}
redis-cli에서 DB 내용 확인
keys
명령어로 레디스에 저장된 키를 확인한다.
# 모든 키(Key) 리스트 출력
keys *
# 문자열 패턴으로 조건부 키(Key) 리스트 출력
keys prefix*
keys *surfix
특정 키가 존재하는지는 exists
명령어로 확인 가능하다.
# 'entity'라는 키가 저장되어 있는지 확인(1, 0 반환)
exists test
값을 보고 싶으면 get
또는 mget
명령어를 사용한다. (단, string 타입 값일 경우에만)
# 'entity'라는 키에 저장된 값
get entity
# 'entity1', 'entit2', 'entity3' 라는 키에 저장된 값 모두 불러오기
mget entity1, entit2, entity3
데이터를 삭제하고 싶으면 del
명령어를 삭제하면 된다. (데이터 타입 상관없음)
# 'entity'라는 키와 값 모두 삭제
del entity
# 'entity1', 'entit2', 'entity3' 라는 키에 저장된 값 모두 삭제
mget entity1, entit2, entity3
🎯트러블슈팅
JpaRepository와 RedisRepository 동시 사용 불가
JpaRepository를 CrudRepository로 변경해서 해결했다.
Description:
The bean 'sampleRedisRepository', defined in cathy.redisspringboot.infra.redis.repository.SampleRedisRepository defined in @EnableRedisRepositories declared on RedisRepositoriesRegistrar.EnableRedisRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in cathy.redisspringboot.infra.redis.repository.SampleRedisRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
Failed to configure a DataSource
redis와 같이 사용할 데이터베이스를 존재하게 만들어줘야 한다. H2 데이터베이스를 설치하고 연결해서 해결했다.
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
Unable to connect to Redis
레디스가 로컬에 존재하지 않을 때 생기는 문제이다. 로컬에 설치해서 해결했다.
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1805)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1736)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1538)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.lambda$getConnection$0(LettuceConnectionFactory.java:1518)
(error) WRONGTYPE Operation against a key holding the wrong kind of value
레디스는 5가지 데이터 타입을 제공하고 있고, 이에 맞게 쿼리를 날려야 한다.
- string:
get <key>
- hash:
hgettall <key>
- lists:
lrange <key> <start> <end>
- sets:
smembers <key>
- sorted sets:
zrangebyscore <key> <min> <max>