DB/Redis
Spring boot와 도커에서 Redis 적용
동그리담
2024. 6. 20. 16:48
Redis란?
시스템 메모리를 사용하는 키-값 데이터 스토어
인메모리 상태에서 데이터를 처리함으로써 빠르고 가볍다는 장점이 있음
필자는 현 Redis를 JWT 토큰 중 리프래쉬 토큰의 관리와 블랙토큰, 게시글 어뷰징 방지를 위해 적용했습니다.
JWT의 로그아웃과 리프레쉬토큰을 구현하면서 Redis를 알게돼었고
추가로 배포시 Redis에 관련된 설정에서 애를 먹어서 글로 정리하게 되었습니다.
Build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.properites (아래의 값은 default value)
spring.data.redis.host=localhost
spring.data.redis.port=6379
Repository
package com.trioshop.repository.redis;
import io.jsonwebtoken.lang.Arrays;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import static java.lang.String.*;
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private static final String BLACKLIST_PREFIX = "blacklist:";
private final RedisTemplate<String, Object> redisTemplate;
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> valueOperations;
public void deleteToken(String userId) {
redisTemplate.delete(userId);
}
public void save(String userId, String refreshToken) {
valueOperations.set(userId, refreshToken);
}
public void viewSave(Long userCode, Long boardCode){
String board;
if(redisTemplate.hasKey(valueOf(userCode))) {
board = (String) valueOperations.get(valueOf(userCode))+boardCode + "_";
}else {
board = boardCode + "_";
}
valueOperations.set(valueOf(userCode), board, 2, TimeUnit.HOURS);
}
public String findById(String userId ) {
if (userId == null) {
return null;
}
return (String) valueOperations.get(userId);
}
public void addTokenToBlacklist(String token, long expirationTime) {
valueOperations.set(BLACKLIST_PREFIX + token, "true", expirationTime, TimeUnit.MILLISECONDS);
}
public Boolean isTokenBlacklisted(String token) {
return redisTemplate.hasKey(BLACKLIST_PREFIX + token);
}
public Boolean isCodeBoardView(Long userCode, Long boardCode) {
String boards = (String) valueOperations.get(valueOf(userCode));
if(Objects.nonNull(boards)) {
String[] boardArr = boards.split("_");
String boardCodeStr = valueOf(boardCode);
for (String s : boardArr) {
if (s.equals(boardCodeStr)) {
return false;
}
}
}
return true;
}
}
이후 필요한 곳에서 상속 받아 사용하면 됩니다.
AWS EC2에 도커 컨테이너로 배포시 Redis 설정
저희 프로젝트 팀은 War 파일을 패키징해서 도커 컨테이너에 올려서 배포하는 방안을 채택 하였습니다.
이 과정에서 Redis 연결이 되지않아 문제를 해결하는데 시간을 투자했습니다.
이러한 문제 해결 과정에서 알게 된 사실 몇가지가 있습니다.
기존 Dockerfile만으로 배포시
1. 같은 네트워크 범주 안에 들어가지 않음, 두개를 각 각 실행해줘야함 그러므로 localhost(127.0.0.1)로 접근 불가
이에 대한 해결방안으로 docker-compose를 이용하였습니다.
하지만 이렇게해도 localhost로 접근이 불가능 하였고 그래서 redis에 네트워크 명을 지정해주었습니다.
docker-compose.yml
version: '3.8'
services:
trioshop:
image: kkgg0522/trioshop
container_name: trioshop
ports:
- "443:8443"
environment:
SPRING_REDIS_HOST: redis
SPRING_REDIS_PORT: 6379
SERVER_SSL_KEY_STORE: /app/trio.keystore
SERVER_SSL_KEY_STORE_PASSWORD: tanadmin
SERVER_SSL_KEY_STORE_TYPE: PKCS12
SERVER_SSL_KEY_ALIAS: tomcat
TZ: "Asia/Seoul"
volumes:
- ./trio.keystore:/app/trio.keystore
depends_on:
- redis
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
hostname: redis
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
application.propertise 변경
spring.data.redis.host=redis