본문 바로가기
Spring

Redis 부숴버리기(3) 캐싱

by windy7271 2024. 5. 13.
728x90
반응형

레디스의 기능중에 캐싱 기능이 있었는데

 

캐싱기능을 사용하면 레디스에 저장하고 데이터가 레디스에 담겨있으면 꺼내오는식으로 이루어진다.

 

 

캐시란 데이터를 미리 복사해 놓은 임시 저장소를 말한다. 이러한 캐시 기능을 사용하면 성능향상에 큰 이점을 주고 db에 접근하는것을 최대한 막아준다.

 

캐시를 적용해 보도록 하겠다. 

이번에는 Redis 부숴버리기(2) 에 설정과는 좀 다르고 (1)과 설정이 비슷하다.

 

 

configuration 

@Configuration
@EnableRedisRepositories
@Slf4j
@EnableCaching
public class RedisConfig{
    @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private int redisPort;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        log.info("redisConnectionFactory : 등록");
        return new LettuceConnectionFactory(redisHost, redisPort);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
    @Bean
    public CacheManager cacheManager() {
        log.info("CacheManager 등록 ");
//        RedisCacheManager 생성
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory());
//        default로 설정을 한다.
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
//                키와 밸류 값 직렬화 방식을 정한다.
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
//                cache: 이름으로 시작하고, 시간 30분
                .computePrefixWith(cacheName -> "prefix::" + cacheName + "::")
                .entryTtl(Duration.ofMinutes(30));
        builder.cacheDefaults(configuration);

        return builder.build();
    }
}

 

CacheManager 을 선언하고 조작해줘야한다.

중요한 것은 

cacheName -> "prefix::" 이 부분인데, 나는 지금 employeeList 부분만 캐싱을 했다. 근데 만약에 다른 부분도 캐싱하고 싶으면 그것을 구분하기 위해 저렇게 사용하였고.

TTl (time to live) 시간을 30분으로 설정한다.

cachedefaults 설정에 configuration을 등록한다라고 이해 하면 될것 같다.

 

그러면 설정은 완료했고.

사용하는 곳 Service단에도 설정을 해준다.

 

@Service
@Transactional
@Slf4j
@CacheConfig(cacheNames = "Employees")
public class EmployeeService {

...

# 캐싱 키추가, 상세보기는 value = #id 처럼 추가 가능
@Cacheable(key = "'all'")
public List<EmployeeResDto> findAll(EmployeeSearchDto employeeSearchDto, Pageable pageable) {
    Specification<T> specification =
            EmployeeSpecification.likeName(employeeSearchDto.getName())
                    .and(EmployeeSpecification.likeEmployeeId(employeeSearchDto.getEmployeeId()))
                    .and(EmployeeSpecification.equalDepartment(employeeSearchDto.getDepartmentCode()))
                    .and(EmployeeSpecification.equalTeamName(employeeSearchDto.getTeamCode()));

    Page<Employee> employeePage = employeeRepository.findAll(specification, pageable);
    List<Employee> employeeList = employeePage.getContent();
    List<String> employeeIdList = new ArrayList<>();
    for(Employee employee: employeeList){
        employeeIdList.add(employee.getEmployeeId());
    }
    List<EmployeeStatusDto> employeeStatusDtos = totalClient.getStatus(employeeIdList);

    Map<String, EmployeeStatusDto> employeeStatusMap = employeeStatusDtos.stream()
            .collect(Collectors.toMap(EmployeeStatusDto::getEmployeeId, Function.identity()));

    List<EmployeeResDto> employeeResDtos = employeeList.stream()
            .map(e -> {
                EmployeeStatusDto status = employeeStatusMap.getOrDefault(e.getEmployeeId(), null);
                return EmployeeResDto.builder()
                        .employeeId(e.getEmployeeId())
                        .department(e.getDepartmentCode())
                        .team(e.getTeamCode())
                        .position(e.getPositionCode())
                        .name(e.getName())
                        .profileImagePath(e.getProfileImage())
                        .email(e.getEmail())
                        .phone(e.getPhone())
                        .status(status != null ? status.getStatusCode() : null)
                        .build();
            }).collect(Collectors.toList());
    return employeeResDtos;
}

 

이번에 프로젝트 하면서 employee 리스트를 가져오는 부분이다.

 

이렇게 하면 

prefix::Employees::all 이런식으로 나오게 된다.

 

그럼 한 번 실제로 캐싱이전과 캐싱이후 다 돌려보자.

 

 

2초 -> 200ms -> 180ms 이렇게 준다

 

총 3번 요청을 했는데 서비스를 한 번 봐보자.

 

 

 

DB에도 3번 요청을 하게 된다.

 

그러면 캐싱을 해보고 나서 테스트를 해보겠다.

 

 

이렇게 미세하게 빨라졌다.

그리도 Service도 확인해보면 1번밖에 호출안한것을 확인 할 수 있다

 

또 레디스를 확인해보면 이렇게 들어가있기 때문에

이 데이터를 가져오는 것이다.

 

 

@Cacheable 말고 다른 기능도 더 있는데 간단하게 설명하면

 

@CachePut : 캐시내용 수정, 항상 실행된다.

@CacheEvict : 캐시 삭제 담당

자세한 내용은 

https://hyeri0903.tistory.com/237

 

[Spring] 스프링 캐시 알아보기 (@Cacheable, @CachePut, @CacheEvict)

스프링 캐시 캐시란? 자주 사용되는 데이터를 저장하는 공간을 의미합니다. 자주 사용되는 데이터를 매번 요청 때마다 생성하여 응답하는 것 보다는 생성된 데이터를 저장해놓고 똑같은 요청이

hyeri0903.tistory.com

https://baeldung.com/spring-cache-tutorial

 

이 분들 의 블로그를 보면 될거같다.

반응형

댓글