처리 속도와 성능이 중요시되는 서비스에선 RDBMS는 한계를 마주칠 수 있다.
데이터베이스에서 저장과 조회는 저장장치로 I/O가 발생한다.
캐시는 In-memory 방식을 활용하여 데이터를 저장하기 때문에 영속성은 보장되지 않지만 저장장치의 I/O보단 훨씬 빠르게 동작할 수 있다.
따라서 자주 사용되는 데이터는 캐시 서버에 저장해두고 우선 조회하고 없다면 데이터베이스에서 조회하면 DB 접근 횟수를 효과적으로 줄일 수 있다.
또는 쿼리가 복잡하거나 시간이 오래 걸리는 경우엔 쿼리 결과를 미리 Redis에 저장해두고 값만 조정 (+, -) 해주는 식으로 활용하는 것도 성능 개선에 효과적일 것이다.

Redis는 key-value 기반의 비정형 데이터베이스 (NoSQL) 로서 다양한 자료구조 형태로 value에 저장할 수 있다.
redis java client는 lettuce와 jedis가 있는데 jedis는 동기 방식으로 작동하여 Blocking 이슈가 발생 가능하다는 단점이 있고, lettuce는 동기와 비동기 방식 모두를 지원하여 non-blocking하게 요청을 처리할 수 있고 확장성이 뛰어나다는 장점이 있다.
스프링부트 환경에서 레디스 의존성은 다음과 같다
implementation('org.springframework.boot:spring-boot-starter-data-redis')
그 다음 Redis Configuration을 작성해줘야 한다.
package com.goormy.hackathon.redis.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
return redisTemplate;
}
}
LettuceConnectionFactory를 빈으로 등록하기 위해 LettuceConnectionFactory를 써줬다.
또 레디스를 다루는 방식은 많은데 RedisTemplate이 binary value를 주고 받는데 높은 수준의 추상화와 직렬화를 제공해주기 때문에 사용하기가 편하다고 한다. 또 다양한 Redis 명령어를 쉽게 사용할 수 있다는 장점도 있다. 따라서 RedisTemplate도 빈으로 등록해준다.
공식 문서에서는 RedisTemplate <String, String> 으로 되어있지만 String에 국한되지 않게 Object로 바꿔서 사용하는 것이 일반적이다.
또 직렬화/역직렬화 관련 설정이 보이는데, set, hash, list 등 다양한 자료구조를 사용할 수 있는 레디스의 특성상 직렬화 설정을 해두면 데이터 타입이 자동으로 맞춰지기 때문에 신경 쓸 필요가 없다.
ValueOperations 객체를 반환하며, 문자열 값을 처리하는 데 사용된다.
ValueOperations<String, String> ops = redisTemplate.opsForValue();
ops.set("key", "value");
String value = ops.get("key");
ListOperations 객체를 반환하며, 리스트 값을 처리하는 데 사용된다.
ListOperations<String, String> ops = redisTemplate.opsForList();
ops.leftPush("myList", "value1");
ops.rightPush("myList", "value2");
List<String> values = ops.range("myList", 0, -1);
SetOperations 객체를 반환하며, 세트 값을 처리하는 데 사용된다.
SetOperations<String, String> ops = redisTemplate.opsForSet();
ops.add("mySet", "value1", "value2");
Set<String> values = ops.members("mySet");
ZSetOperations 객체를 반환하며, 정렬된 세트 값을 처리하는 데 사용된다.
ZSetOperations<String, String> ops = redisTemplate.opsForZSet();
ops.add("myZSet", "value1", 1);
ops.add("myZSet", "value2", 2);
Set<String> values = ops.range("myZSet", 0, -1);
HashOperations 객체를 반환하며, 해시 값을 처리하는 데 사용된다.
HashOperations<String, String, String> ops = redisTemplate.opsForHash();
ops.put("myHash", "field1", "value1");
ops.put("myHash", "field2", "value2");
Map<String, String> values = ops.entries("myHash");
키를 Redis에서 삭제한다.
redisTemplate.delete("key");
주어진 키가 Redis에 존재하는지 확인한다.
boolean exists = redisTemplate.hasKey("key");
redis java client 중에서 redisson 이란 친구도 있는데 그 친구랑 친해지면 좋다고 하더라구요~