TIL(Today I Learned)

[TIL] 마이페이지 성능 최적화 : 로컬 캐시(Ehcache) 적용

yunseohhe 2024. 11. 1. 19:33

목적

  • 마이페이지 조회 시 반복적으로 DB를 조회하게 되어 성능 저하가 발생
  • 이를 개선하기 위해 로컬 캐시(Ehcache)를 적용하여 DB 조회 횟수를 줄이고 응답 속도를 최적화하고자 함

캐시 선택 (Ehcache vs Redis)

  • Ehcache 선택 이유
    • 로컬 캐시로, 외부 캐시 서버를 별도로 두지 않아도 돼서 설정이 간단하고 비용 절감
    • 응답 속도가 빠르며, 애플리케이션 서버에 직접 캐싱하여 네트워크 요청이 필요 없음
    • 지속적으로 갱신되는 마이페이지 데이터 특성상, 짧은 TTL 설정으로 캐시 활용도와 일관성 유지
  • Redis와의 비교
    • Redis분산 캐시로 여러 서버 간 캐시 일관성을 보장하고 큰 데이터 세트도 효과적으로 캐싱 가능
    • Ehcache는 분산되지 않기 때문에 서버 로컬 캐시용으로 적합하며, 데이터 일관성을 관리하기 쉬움
    • Redis에 비해 설정 및 유지 관리가 간편하고 서비 비용을 절감할 수 있어 작은 프로젝트나 분산 필요가 없는 서비스에 적합

준비 단계

  1. 더미데이터 생성할 클래스 파일 작성(DataInitializer 클래스 파일)
package com.sparta.doguin.config;

import com.sparta.doguin.domain.user.entity.User;
import com.sparta.doguin.domain.user.enums.UserRole;
import com.sparta.doguin.domain.user.enums.UserType;
import com.sparta.doguin.domain.user.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class DataInitializer {

    @Bean
    public CommandLineRunner loadData(UserRepository userRepository) {
        return args -> {
            for (int i = 1; i <= 1000; i++) {
                BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
                String encodedPassword = passwordEncoder.encode("password!!!" + i);

                User user = User.createUser(
                        null,
                        "user" + i + "@example.com",
                        encodedPassword,
                        "User" + i,
                        UserType.INDIVIDUAL,
                        UserRole.ROLE_USER,
                        "profile" + i + ".png",
                        "Hello, I am User" + i,
                        "Address " + i,
                        "https://github.com/user" + i,
                        "https://blog.example.com/user" + i
                );
                userRepository.save(user);
            }
            System.out.println("더미데이터 저장 완료.");
        };
    }
}

더미데이터 생성 완료

 

2. 더미데이터를 만들고 “캐시 적용 전” 테스트를 한다.(저는 포스트맨으로 진행하였습니다.)

 

 

3. 캐시 적용을 위해 의존성을 추가한다.

    // Encache
    implementation 'org.ehcache:ehcache:3.10.0'
    implementation 'javax.cache:cache-api:1.1.1'
    implementation 'org.springframework.boot:spring-boot-starter-cache'

 

4. xml 환경변수 설정(기존에 있는 xml에 추가해준다.)

    <cache alias="mypageCache">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.Object</value-type>
        <expiry>
            <ttl unit="minutes">7</ttl>
        </expiry>
        <resources>
            <heap unit="entries">50</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache>

 

5. 애플리케이션 시작파일에서 @EnableCaching이 있는지 확인해준다.

 

6. 적용할 서비스 로직에 캐시를 적용한다.

    @Cacheable(value = MAPAGE_CACHE, key = "'마이페이지조회'+(#authUser != null ? #authUser.userId : 'anonymous')")

@Cacheable 적용 모습

 

7. 이제 캐시 적용 후의 성능 비교를 한다.

 

 

적용 결과

  • 성능 테스트 결과
    • 적용 전 
        1차 - 첫 번째 요청 88.03 ms   2차 - 두 번째 요청 15.59 ms

 

  • 적용 후
      1차 - 첫 번째 요청 116.73 ms

         2차 - 두 번째 요청 3.82 ms