Redis란 무엇인가?
Redis(Remote Dictionary Server)로 오픈 소스 기반의 인 메모리 데이터 저장소입니다.
Redis의 특징
- 메모리 내 데이터 저장
- Key : Value 타입
- 다양한 데이터 구조지원
- 메시징 큐 구현 가능
- 싱글 스레드 방식
Redis 사용 용도
일반적으로는 캐싱, 세션 관리, 풀링, 메시지 브로커, 게임 랭킹 등 다양한 영역에서 사용됩니다.
Redis의 장점
- Key:Value로 이뤄져 있는 만큼 빠른 속도로 데이터를 검색할 수 있습니다.
- 비관계형 데이터베이스로 확장성에 있어서 이점이 있습니다.
- in-memory 방식으로 디스크 방식보다 빠릅니다.
Redis의 단점
- 데이터 일관성, 동시성 제어를 위한 기능이 미약합니다.
Redis 캐싱 서버 적용하기
Redis의 서버를 적용하게 된 이유는 Member.class
는 유저의 권한이 필요한 경우 매번 DB를 조회하게 되는데
이 것은 DB에 많은 부하를 줍니다. DB를 조회하기 전에 캐싱서버에서 Member 클래스를 가져올 수 있게 하면 좋겠다 생각 되어 적용하게 되었습니다.
주의 사항
위의 예시를 한번 들어보겠습니다. Member 클래스를 자주 업데이트 하는 상황이 발생하면 Update가 될때마다 업데이트 된 유저의 데이터를 Redis에 적용해 주어야 합니다.
작성 리스트
- redis build.gradle 추가
- redis configuration 빈 등록하기
- Member Cache DAO 생성하기
- Member 서비스단에서 Caching OR DB조회
- 로그인시 redis에 캐싱
Redis build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
data-redis 의존성을 추가해줍니다.
Redis Configuration 빈 등록하기
@Configuration
@EnableRedisRepositories
@RequiredArgsConstructor
public class RedisConfiguration {
private final RedisProperties properties; //1
@Bean
public RedisConnectionFactory redisConnectionFactory(){
RedisURI redisURI = RedisURI.create(properties.getUrl());
org.springframework.data.redis.connection.RedisConfiguration configuration = LettuceConnectionFactory.createRedisConfiguration(redisURI);
LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration);
factory.afterPropertiesSet();
return factory;
}
@Bean
public RedisTemplate<String, Member> redisTemplate() {
RedisTemplate<String, Member> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new Jackson2JsonRedisSerializer<Member>(Member.class));
return template;
}
- properties는 yml에서 적용해주는 spring.data.redis 에 설정한 값들을 가져오는 클래스입니다.
redisConnectionFactory는 스프링과 Redis가 동작할 수 있게 연결해주는 설정들입니다.
RedisTemplate은 JpaRepository를 만드는 것처럼 RedisRepository를 만드는 겁니다.
redis 템플릿에 Factory 설정을 해주고 key 설정과 Value 설정을 해주고 반환해줍니다.
Member Cache DAO 생성하기
@Slf4j
@Repository
@RequiredArgsConstructor
public class MemberCacheRepository {
private final RedisTemplate<String, Member> template;
private final Duration expiredTime = Duration.ofDays(3);
public void setMember(Member member) {
String key = getKey(member.getName());
log.info("Set Member Redis {} : {}", key, member);
template.opsForValue().set(key, member, expiredTime);
}
public Optional<Member> getMember(String username) {
Member member = template.opsForValue().get(getKey(username));
log.info("Get member Redis: {}", username);
return Optional.ofNullable(member);
}
private String getKey(String userName){
return "UID:"+userName;
}
}
Redis에서 getMember 메소드와 setMember 메소드를 만들었습니다.
ExpiredTime을 3일로 설정해서 3일뒤에 데이터를 소멸하게 설정했습니다.
Member 서비스단에서 Caching OR DB조회
public Member loadMemberByMemberName(String userName) {
return cacheRepository.getMember(userName)
.orElseGet(
() -> memberRepository.findByName(userName).map(Member::fromEntity).orElseThrow(() ->
new SnsException(Errorcode.NOT_EXISTS_USERNAME, String.format("%s not founded", userName)))
);
}
캐시 서버에 Member의 관한 정보가 없으면 DB를 조회하는 코드입니다.
로그인시 redis에 캐싱
public String login(String username, String password) {
// username 유저 가져오기
Member member = loadMemberByMemberName(username);
// 비밀번호 체크
if (!encoder.matches(password, member.getPassword())){
throw new SnsException(Errorcode.NOT_MATCH_PASSWORD);
}
// 멤버 캐싱
cacheRepository.setMember(member);
// 토큰 생성
return JwtTokenUtils.generateToken(username, secretKey, expiredTimeMs);
}
로그인을 할 때 Member의 정보를 캐싱해주는 로직입니다.
사실 Redis를 적용하고 테스트 코드에도 적용하기 위해서 많이 찾아봤지만 나중에 기회되면 포스팅하겠습니다.
긴글 봐주셔서 감사합니다. (_ _)
'SpringBoot' 카테고리의 다른 글
주문내역을 내려줄 때 가격 멱등성에 대한 고민 (0) | 2023.10.29 |
---|---|
프레임워크, 라이브러리의 차이 (0) | 2023.07.19 |
[Spring Boot] @WithMockUser 테스트 시 getPrincipal Null (0) | 2023.05.02 |
[SpringBoot] Transaction 커밋 적용 (0) | 2023.04.20 |
[SpringBoot] 스프링부트 터미널 build 실행 오류 (1) | 2023.04.04 |