본문 바로가기

DataBase/Redis

[Redis] Spring Boot로 Redis 실행해보기

Spring Boot 프로젝트 세팅

Board.java

@Entity
@Table(name = "boards")
@Getter
@Setter
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String title;

    private String content;

    @CreatedDate
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime createdAt;
    
}

 

BoardRepository.java

public interface BoardRepository extends JpaRepository<Board, Integer> {
    Page<Board> findAllByOrderByCreatedAtDesc(Pageable pageable);
}

 

BoardService.java

@Service
@RequiredArgsConstructor
public class BoardService {
    private final BoardRepository boardRepository;

    public List<Board> getBoards(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
        return pageOfBoards.getContent();
    }
}

 

BoardController.java

@RestController
@RequestMapping("/boards")
@RequiredArgsConstructor
public class BoardController {
    private final  BoardService boardService;

    @GetMapping()
    public List<Board> getBoards(
        @RequestParam(defaultValue = "1", name = "page") int page, 
        @RequestParam(defaultValue = "10", name = "size") int size
    ) {
        return boardService.getBoards(page, size);
    }
}

 

데이터가 얼마나 빨리 캐싱되는 지를 확인하기 위해서 디비에 더미 데이터를 넣는 작업

-- 높은 재귀(반복) 횟수를 허용하도록 설정
-- (아래에서 생성할 더미 데이터의 개수와 맞춰서 작성하면 된다.)
SET SESSION cte_max_recursion_depth = 1000000; 

-- boards 테이블에 더미 데이터 삽입
INSERT INTO boards (title, content, created_at)
WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte WHERE n < 1000000 -- 생성하고 싶은 더미 데이터의 개수
)
SELECT
    CONCAT('Title', LPAD(n, 7, '0')) AS title,  -- 'Title' 다음에 7자리 숫자로 구성된 제목 생성
    CONCAT('Content', LPAD(n, 7, '0')) AS content,  -- 'Content' 다음에 7자리 숫자로 구성된 내용 생성
    TIMESTAMP(DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 3650 + 1) DAY) + INTERVAL FLOOR(RAND() * 86400) SECOND) AS created_at -- 최근 10년 내의 임의의 날짜와 시간 생성
FROM cte;


Redis를 SpringBoot에서 적용시키기 위한 세팅

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-data-redis' -- 의존성 추가

 

application.yml

server:
    port: 4000

spring:
    profiles:
        dafault: local

    datasource:
        url: jdbc:mysql://localhost:3306/mydb
        username: [디비유저네임]
        password: [디비패스워드]
        driver-class-name: com.mysql.cj.jdbc.Driver
    
    jpa:
        hibernate:
            ddl-auto: update
        show-sql: true

    data:
        redis:
            host: localhost
            port: 6379

logging:
    level:
        org.springframework.cache: trace

 

RedisConfig.java

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

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

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        // Lettuce라는 라이브러리를 활용해 Redis 연결을 관리하는 객체를 생성하고
        // Redis 서버에 대한 정보(host, port)를 설정한다.
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
    }
}

 

RedisCacheConfig.java

@Configuration
@EnableCaching // Spring Boot의 캐싱 설정을 활성화
public class RedisCacheConfig {
        @Bean
        public CacheManager boardCacheManager(RedisConnectionFactory redisConnectionFactory) {
                RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                                .defaultCacheConfig()
                                // Redis에 Key를 저장할 때 String으로 직렬화(변환)해서 저장
                                .serializeKeysWith(
                                                RedisSerializationContext.SerializationPair.fromSerializer(
                                                                new StringRedisSerializer()))
                                // Redis에 Value를 저장할 때 Json으로 직렬화(변환)해서 저장
                                .serializeValuesWith(
                                                RedisSerializationContext.SerializationPair.fromSerializer(
                                                                new Jackson2JsonRedisSerializer<Object>(Object.class)))
                                // 데이터의 만료기간(TTL) 설정
                                .entryTtl(Duration.ofMinutes(1L));

                return RedisCacheManager.RedisCacheManagerBuilder
                                .fromConnectionFactory(redisConnectionFactory)
                                .cacheDefaults(redisCacheConfiguration)
                                .build();
        }
}

 

BoardService 수정

@Service
@RequiredArgsConstructor
public class BoardService {
    private final BoardRepository boardRepository;
	
    // Cacheable 어노테이셔을 사용해서 Cache Aside 방법을 실행시킴
    @Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager")
    public List<Board> getBoards(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
        return pageOfBoards.getContent();
    }
}

 

Postman으로 레디스 유무 체감하기

Redis를 쓰지 않았을 때

  • 평균 700ms 정도의 속도

 

Reids를 썼을 때

  • 평균 6ms 정도의 속도

 

각자의 컴퓨터 사양마다 속도는 다르겠지만 내 컴퓨터의 경우 굉장한 속도의 차이가 보였다.

대략 116배 정도의 속도가 줄었다. 이래서 다들 레디스와 디비를 함께 사용하는 것인가보다… 엄청난 위력이다.