01_Redis
📍 Redis(REmote DIctionary Server)
메모리(RAM)에 데이터를 저장하는 키-값(key-value) 데이터 저장소
여러 서버에서 공유할 수 있고 빠름(일반 변수는 빠르지만 서버 간 공유x. RDBMS는 공유되지만 느림)
- 디스크: 일반적인 RDBMS. 느림. 용량 많음. 복잡한 쿼리 가능.
- 메모리: Redis. 디스크보다 훨씬 빠름. 용량 제약. 복잡한 쿼리 약함.
| 활용 사례 | 설명 |
| 캐시(Cache) | DB 조회 결과를 잠시 저장해 다음 요청 때 DB 대신 Redis에서 빠르게 조회 |
| 세션 저장소 | 로그인 세션을 저장 (특히 여러 서버를 운영할 때) |
| 토큰 저장 | JWT Refresh Token, 인증번호, 비밀번호 재설정 토큰 등 |
| 분산 락(Distributed Lock) | 동시에 같은 자원에 접근하는 것을 막기 위한 락 |
| 순위표(Leaderboard) | 게임 점수, 인기 게시글 순위 등 |
| 메시지 큐(Pub/Sub) | 채팅, 알림 등 실시간 메시지 전달 |
| 속도 제한(Rate Limit) | 1분에 N번 이상 요청 시 차단 |
키 네이밍 컨벤션
콜론(:)으로 계층 구분: category:id 또는 domain:type:id 형식
명확한 prefix 사용
소문자와 하이픈
📍 Redis 자료구조
String
키 하나에 값 하나 대응
단일 값 저장
활용 예) 인증번호, 토큰, 카운터 등
SET email-code:hongildong@example.com 123456
GET email-code:hongildong@example.com
> "123456"
List
값을 순서대로 저장
큐(Queue)나 스택(Stack)처럼 사용 가능
활용 예) 최근 검색어, 메시지 큐, 알림 목록
LPUSH messages "안녕"
LPUSH messages "반가워"
LRANGE messages 0 -1
> "반가워", "안녕"
Set
순서 없이 중복을 허용하지 않는 집합
활용 예) 좋아요 누른 사용자 목록, 태그 관리, 친구 목록 등
SADD tags "spring"
SADD tags "redis"
SADD tags "spring" // 중복은 추가되지 않음
SMEMBERS tags
> "spring", "redis"
Sorted Set (정렬된 집합, ZSet)
Set과 비슷하지만 각 값에 점수(score)가 붙어 점수 기준으로 자동 정렬
활용 예) 랭킹 시스템, 인기 게시글 등
ZADD ranking 100 "화연"
ZADD ranking 85 "민수"
ZADD ranking 92 "유진"
ZRANGE ranking 0 -1 WITHSCORES
> "민수" 85, "수진" 92, "유진" 100
Hash
하나의 키 안에 여러 필드-값 쌍 저장
활용 예) 사용자 정보, 상품 정보 등 객체 형태의 데이터
HSET user:1 name "홍길동" age 23 email "hong@example.com"
HGET user:1 name
> "화연
02_Redis 설치
📍 로컬 설치(MacOS)
Homebrew 설치되어 있어야 함
brew install redis
brew services start redis
📍 Linux (Ubuntu) 설치
sudo apt update
sudo apt install redis-server
sudo systemctl start redis
📍 Docker 설치
docker run -d \ # -d: 백그라운드 실행
--name my-redis # 컨테이너 이름 지정
-p 6379:6379 # 호스트의 6379 포트를 Redis 기본 포트 6379에 연결
redis:7.2 # Redis 이미지 버전
📍 Redis CLI
- 설치 확인
redis-cli ping
> PONG
PONG이 떨어지면 Redis 서버 정상 작동 상태
- Redis 접속
redis-cli
| 명령어 | 설명 |
| SET key value | 키-값 저장 |
| GET key | 값 조회 |
| DEL key | 키 삭제 |
| EXISTS key | 키 존재 여부 (1: 있음, 0: 없음) |
| EXPIRE key seconds | 만료 시간 설정 |
| TTL key | 남은 만료 시간 조회 |
| KEYS * | 모든 키 조회 (운영 환경에서는 절대 사용 금지) |
| FLUSHDB | 현재 DB의 모든 키 삭제 (위험!) |
03_Spring Boot에서 Redis 연동
📍 의존성 추가
build.gradle
dependencies{
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
application.yml
spring:
data:
redis:
host: localhost
port: 6379
# 비밀번호가 있는 경우
# password: your-password
보안 운영 환경에서는 비밀번호 설정할 것!
📍 RedisTemplate
Spring Data Redis는 RedisTemplate, StringRedisTemplate 템플릿 제공
- RedisTemplate: 키/값 타입 객체(직렬화 필요), 객체 통째로 저장할 때
- StringTemplate: String 전용. 키와 값 모두 문자열일 때
@Configuration
public class RedisConfig {
// 키와 값 모두 String인 경우 사용
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
// 키는 String, 값은 JSON으로 직렬화
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
🔍 코드 설명
- StringRedisTemplate: 키와 값이 모두 문자열인 경우 사용
- RedisTemplate<String, Object>: 객체를 JSON으로 직렬화해 저장하고 싶을 때 사용
- 서비스에서 사용 시
@Service
@RequiredArgsConstructor
public class RedisService {
private final StringRedisTemplate redisTemplate;
// 저장
public void save(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
// 만료 시간과 함께 저장
public void saveWithTtl(String key, String value, Duration ttl) {
redisTemplate.opsForValue().set(key, value, ttl);
}
// 조회
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
// 삭제
public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
// 존재 여부 확인
public boolean exists(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
}
🔍 코드 설명
- opsForValue(): String 타입을 다루는 연산. 다른 자료구조는 opsForList(), opsForSet(), opsForZSet(), opsForHash() 사용
- set(key, value, ttl): 저장과 동시에 TTL 설정. 별도로 expire를 호출하지 않아도 된다.
- hasKey, delete는 Boolean을 반환하므로 null 안전 처리(Boolean.TRUE.equals(...))를 해주는 것이 좋다.
TTL(Time To Live)
키가 살아있는 시간
TTL을 설정해두고 설정 시간이 되면 Redis가 자동으로 키 삭제
TTL이 만료되어 자동 삭제된 키를 조회하면 null 반환 → null 체크해야 함
// 5분 동안 유효한 인증번호 저장
redisTemplate.opsForValue().set(
"email-code:hong@example.com",
"123456",
CODE_TTL,
TimeUnit.MINUTES
);
📍 GETDEL
get으로 값을 조회한 후 delete로 삭제하는 로직의 경우, 이 두 단계 사이에 다른 요청이 끼어들 수 있음
→ TOCTOU(Time Of Check to Time Of Use) 문제 발생
→ 원자적(atomic) 연산 사용
→ GETDEL은 값을 조회하면서 동시에 삭제하는 단일 명령어
public boolean verify(String email, String inputCode) {
String key = KEY_PREFIX + email;
// 조회와 삭제를 원자적으로 수행
String storedCode = redisTemplate.opsForValue().getAndDelete(key);
return storedCode != null && storedCode.equals(inputCode);
}
📍 KEYS, SCAN
KEYS * 같이 모든 키를 조회하는 명령어는 운영 환경에서 절대 사용하면 안 됨
Redis는 단일 스레드로 동작하기 때문에 키가 수백만 개일 경우 그동안 다른 요청 전부 멈춤
→ SCAN 명령어 사용(키를 나눠서 조회하므로 서버 멈춤x)
'Back-end > SpringBoot' 카테고리의 다른 글
| [Spring Boot] Swagger 적용 (0) | 2026.06.28 |
|---|---|
| [Spring Boot] 헬스 체크(Health Check) 구현 (0) | 2026.06.26 |
| [Spring Boot] 공통 응답 처리 구현 (0) | 2026.06.26 |
| [Spring Boot] 공통 예외처리 구현 - CustomException, GlobalExceptionHandler (0) | 2026.06.25 |
| [Spring Boot] JPA Auditing으로 BaseTimeEntity 구현 (0) | 2026.06.25 |