728x90

들어가면서

spring Boot 프로젝트에서 Ehcache 대신 Caffeine을 사용하면 성능을 향상시킬 수 있습니다.

Coffine이란 무엇인가?

Caffeine은 인기있는 오픈 소스 자바 캐시 라이브러리이며, Google이 개발하고 있습니다. Caffeine은 Java 8 이상을 지원하며, 최신 JVM의 기능을 활용하여 캐시 퍼포먼스를 높이고 메모리 사용을 최적화합니다.

Coffine은 Guava 캐시 라이브러리의 대체 제품입니다. Coffine은 Guava 캐시의 기능을 대부분 포함하고 있으며, 더 나은 쓰기 성능과 더 적은 메모리 사용량을 제공합니다.

어떤특징들이 있는가?

Caffeine은 다음과 같은 특징을 가지고 있습니다.

  1. 빠른 접근 및 응답 속도: Caffeine은 인-메모리 캐시를 사용하며, ConcurrentHashMap 및 ConcurrentLinkedHashMap과 같은 최신 자바 컬렉션을 활용하여 데이터에 대한 빠른 액세스 및 응답 속도를 제공합니다.
  1. 최신 JVM 최적화: Caffeine은 최신 JVM의 기능을 활용하여 캐시 퍼포먼스를 최적화합니다.
  1. 캐시 유효 기간 및 최대 크기 제한: Caffeine은 캐시 항목의 유효 기간 및 최대 크기 제한을 설정할 수 있습니다. 이러한 설정을 통해 메모리 사용을 최적화하고 캐시 데이터의 최신 상태를 유지할 수 있습니다.
  1. 스레드 안전성: Caffeine은 스레드 안전성을 보장하기 위해 synchronized 블록을 사용하지 않고 최신 자바 동시성 라이브러리를 활용합니다.

Caffeine 외 기타 library들에 대한 간단한 비교자료

라이브러리기능성능기타
Ehcache분산 캐싱, 대규모 데이터 처리높음Spring Boot에서 기본적으로 제공됨
Caffeine쓰기 성능이 뛰어나며, 메모리 사용량이 적음매우 높음Guava 캐시의 대체제
Redis분산 캐싱, Pub/Sub 메시징, Set 처리높음NoSQL 데이터베이스
Hazelcast분산 캐싱, 대규모 데이터 처리높음장애 복구 및 확장성이 뛰어남
Infinispan분산 캐싱, 대규모 데이터 처리높음JBoss에서 개발됨

Coffine의 장점

  • Guava 캐시의 대체제로서 Guava 캐시의 대부분의 기능을 포함하고 있음
  • 쓰기 성능이 더 뛰어나며, 메모리 사용량이 더 적음

Coffine의 단점

  • Guava 캐시와 달리, 캐시 다시 로드를 지원하지 않음

Coffine을 Spring Boot 3.0에 적용하는 코드 설정

1. Gradle 파일에 의존성 추가

dependencies {
    implementation("com.github.ben-manes.caffeine:caffeine:3.0.0")
    implementation("com.github.ben-manes.caffeine:caffeine-jcache:3.0.0")
}

2. Coffine 캐시 매니저 설정

@Configuration
@EnableCaching
public class CachingConfig extends CachingConfigurerSupport {

    @Bean
    @Override
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeineCacheBuilder());
        return cacheManager;
    }

    Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
                .expireAfterWrite(5, TimeUnit.MINUTES)
                .maximumSize(100)
                .weakKeys()
                .recordStats();
    }
}

Coffine을 적용한 CRUD 작성하기

1. application.yml 파일에 MySQL 정보 기재

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/{database_name}?serverTimezone=UTC
    username: {username}
    password: {password}
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true

2. JPA 적용

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    // getters and setters
}

3. Coffine을 적용한 Repository 구현

@Repository
public class UserRepositoryImpl implements UserRepository {

    @Autowired
    private EntityManager entityManager;

    @Cacheable(value = "users")
    public List<User> findAll() {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> cq = cb.createQuery(User.class);
        Root<User> root = cq.from(User.class);
        cq.select(root);
        TypedQuery<User> query = entityManager.createQuery(cq);
        return query.getResultList();
    }

    @Cacheable(value = "users", key = "#id")
    public User findById(Long id) {
        return entityManager.find(User.class, id);
    }

    @CachePut(value = "users", key = "#user.id")
    public User save(User user) {
        entityManager.persist(user);
        return user;
    }

    @CacheEvict(value = "users", key = "#id")
    public void deleteById(Long id) {
        User user = entityManager.find(User.class, id);
        entityManager.remove(user);
    }
}

JUnit6를 사용하여 테스트 코드 작성

@SpringBootTest
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void testFindAll() {
        List<User> userList1 = userRepository.findAll();
        List<User> userList2 = userRepository.findAll();
        assertEquals(userList1, userList2);
    }

    @Test
    public void testFindById() {
        User user1 = userRepository.save(new User("John", "john@example.com"));
        User user2 = userRepository.findById(user1.getId());
        assertEquals(user1.getName(), user2.getName());
        assertEquals(user1.getEmail(), user2.getEmail());
    }

    @Test
    public void testSave() {
        User user1 = new User("John", "john@example.com");
        userRepository.save(user1);
        User user2 = userRepository.findById(user1.getId());
        assertEquals(user1.getName(), user2.getName());
        assertEquals(user1.getEmail(), user2.getEmail());
    }

    @Test
    public void testDeleteById() {
        User user1 = userRepository.save(new User("John", "john@example.com"));
        userRepository.deleteById(user1.getId());
        assertNull(userRepository.findById(user1.getId()));
    }
}


내저장소 바로가기 luxury515

+ Recent posts