Redis 왜 쓸까? 그리고 스프링부트 프로젝트에 Redis 설정까지

wisdom·2022년 9월 17일
0

백엔드 개발자라면?

목록 보기
33/42

Redis

  • key-value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 DBMS
  • Database, Cache, Message Broker 로 사용되며, 인메모리 데이터 구조를 가진 저장소다.

Database 가 있는데 Redis를 사용하는 이유가 뭘까?

  • 데이터베이스는 데이터를 물리디스크에 직접 사용하기 때문에 서버에 장애가 발생해 다운되더라도 데이터가 손실되지 않지만, 매 번 디스크에 접근해야 해서, 사용자가 많아질수록 부하가 심해지고 느려진다.
  • 물론, 서비스 운영 초반이거나 규모가 작은 서비스의 경우 "Web Server-WAS-DB" 의 구조로도 데이터베이스에 무리가 가진 않는다.
  • 하지만 사용자가 늘어날수록 데이터베이스가 과부하가 될 수 있기 때문에, Cache Server를 도입하여 사용해야 한다. 이때 이 캐시서버로 이용 가능한 것이 Redis 다.

Cache

  • 한번 읽어온 데이터를 임의의 공간에 저장하여 다시 읽어올 때 빠르게 결과값을 받을 수 있도록 도와주는 공간이다.
  • 즉 같은 요청이 여러 번 들어와도 매번 데이터베이스를 거치는 것이 아닌 캐시 서버에서 첫 번째 요청 이후 저장된 결과값을 바로 내려주기 때문에 데이터베이스의 부하를 줄이고 서비스 속도도 느려지지 않는 장점이 있다.

Cache Server 흐름

Look Aside Cache Pattern

    1. Client가 데이터를 요청.
    1. Web Server가 Cache Server 에 데이터 존재하는 지 확인.
    1. 없다면, DB를 조회하여 Cache Server에 저장 후 결과값을 Client에게 반환(=Cache Miss)
    1. 있다면, DB를 조회하지 않고, Cache Server에 있는 결과값을 Client에게 바로 반환(=Cache Hit)

Write Back Pattern

    1. Web server가 모든 데이터를 Cache에 저장.
    1. Cache Server에 특정 시간 동안 데이터가 저장.
    1. Cache Server에 있는 데이터를 DB에 저장.
    1. DB에 저장된 Cache Server의 데이터 삭제.

Write Back Pattern?
Insert Query를 한번씩 많이 날리는 것보다 Insert Query 여러개를 붙여 한번에 날리는 것이 더 효율적인 원리이다.
때문에 들어오는 데이터들이 저장되기 전 메모리 공간에 머무르는 동안 서버에 장애가 발생하여 다운된다면 데이터가 손실될 수도 있다.

Redis 특징

  • Key-Value 구조로 Query를 사용하지 않아도 된다.
  • 데이터를 디스크에 쓰는 구조가 아닌, 메모리에서 데이터를 처리하기 때문에, 속도가 매우 빠르다.
  • String, List, Set, Sorted Set, Hash 자료 구조를 지원한다.
  • Single Threaded이다. 즉, 한 번에 하나의 명령만 처리할 수 있다. 때문에, 중간에 처리 시간이 긴 명령어가 들어오면 그 뒤에 명령어들은 대기가 필요하다. (단, get, set 명령어의 경우 초당 10만개 이상 처리할 수 있을만큼 빠름.)

Redis 주의 사항

  • 서버에 장애 발생 시 그에 대한 운영 계획이 필요하다.
  • 메모리 관리가 중요하다.
  • 싱글 스레드의 특성상, 처리하는데 오래 걸리는 요청, 명령은 피해야 한다.

Spring Boot + Redis

docker reids 설치 및 실행

  • redis 같은 infra 는 docker 로 설치하는게 좋다. 추후 rabbitmq 도 docker 로 설치할 예정.
  • 그래야 인프라의 동일성으로 인해 일관성이 있는 개발이 가능하다.
docker pull redis

docker ps

docker exec -it [CONTAINER ID] redis-cli

스프링부트 프로젝트에 Redis 설정하기

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'

RedisConfig.java

import org.springframework.beans.factory.annotation.Value;
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.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;

    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        RedisStandaloneConfiguration redisStandaloneConfiguration
                = new RedisStandaloneConfiguration(redisHost,redisPort);

        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public <T> RedisTemplate<String, T> redisTemplate(){
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();

        //아래 메서드들이 빠지면 스프링에서 조회할 땐,
        //값이 정상으로 보이나 redis-cli로 보면 값이 이상하게 나온다.
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory());

        return redisTemplate;
    }
}
profile
문제를 정의하고, 문제를 해결하는

1개의 댓글

comment-user-thumbnail
2024년 5월 6일

배포된 프로젝트에 레디스를 추가하기때문에 도커로 설치하신건가요? 현재 저는 로컬환경에서 레디스 도입을 연습중인데 저같은 경우에는 brew를 활용해서 로컬에 설치 후 테스트 해도 되는건가요??

답글 달기