티스토리 뷰
오늘은 SpringBoot에서 Redis와 EHCache를 동시에 활용해 캐싱을 구현하는 방법에 대해 간단히 알아보겠습니다.
1. Redis 란?
Redis는 인메모리 데이터 저장소로 빠른 읽기/쓰기 성능을 제공하는 NoSQL 입니다. 키-값 저장 구조를 사용하며, 원격 서버에서 실행 가능해 분산 환경에 적합합니다.
사용처
- 세션 관리: 사용자 세션 데이터를 빠르게 저장/조회
- 캐싱: 자주 조회되는 데이터를 메모리에 저장해 DB 부하 감소
- 실시간 데이터 처리: 순위표, 실시간 분석 등
2. EHCache 란?
EHCache는 JVM내에서 동작하는 인메모리 캐싱 라이브러리로, JCache(JSR-107) 표준을 지원합니다. 로컬 환경에서 가볍고 빠르게 캐싱을 구현할 수 있습니다.
사용처
- 로컬 캐싱: 서버 내에서 빠르게 접근해야 하는 데이터 저장
- 소규모 애플리케이션: 외부 캐시 서버 없이 간단한 캐싱 필요 시
- Spring 통합: @Cacheable, @CachePut 어노테이션으로 쉽게 캐싱 적용
3. Redis vs EHCache
- Redis: 외부 서버로 실행되며, 분산 환경과 대규모 데이터에 강력. 네트워크 오버헤드가 있음.
- EHCache: JVM 내에서 동작해 빠르고 가볍지만, 로컬 환경에 국한. 메모리 사용량 주의 필요.
4. 예제 소스 작성
build.gradle
dependencies {
// Spring Boot Starters
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-cache'
// Cache Providers
implementation 'org.ehcache:ehcache:3.10.8'
implementation 'javax.cache:cache-api:1.1.1'
// Lombok
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
// Testing
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
- SpringBoot 3.5.5 와 JDK 21을 기반으로 Redis와 EHCache 그리고 Lombok 에 관련된 의존성을 추가합니다.
SpringBootApplication
package com.cache.cachemanager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CacheManagerApplication {
public static void main(String[] args) {
SpringApplication.run(CacheManagerApplication.class, args);
}
}
- 어플리케이션 소스에 @EnableCaching 을 추가하여 캐싱을 활성화 합니다.
application.yml
server:
port: 1220
spring:
data:
redis:
host: 127.0.0.1
port: 6379
cache:
type: none # Redis 와 EHCache 를 수동으로 설정
- Redis 정보를 정의하고, cache-type 을 none 으로 설정합니다.
RedisConfig.java
package com.cache.cachemanager.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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 {
// RedisConnectionFactory 생략 => application.yml 의 spring.data.redis 설정 기반 자동 제공
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer()); // Key 는 문자열로 직렬화
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // Value 는 JSON 형식으로 직렬화
return redisTemplate;
}
}
- RedisConnectionFatory 를 주입받아 Redis 서버에 연결하고 키는 String, 값은 Json 형식으로 직렬화합니다.
EHCacheConfig.java
package com.cache.cachemanager.config;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.jsr107.Eh107Configuration;
import org.ehcache.jsr107.EhcacheCachingProvider;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.cache.CacheManager;
import javax.cache.Caching;
import java.time.Duration;
@Configuration
public class EHCacheConfig {
@Bean
public JCacheCacheManager ehCacheManager(){
EhcacheCachingProvider provider =
(EhcacheCachingProvider) Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider"); // Provider 를 통해 EHCache 를 JCache 로 연결
CacheManager cacheManager = provider.getCacheManager(); // CacheManager 생성
// EHCache 설정 : 힙 메모리 100개 엔트리, TTL 5분
CacheConfiguration<String, String> ehcacheConfig = CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(100)) // 캐시 설정 (Key, Value 타입 및 최대 엔트리 수)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(5)))
.build();
// JCache Configuration 으로 변환
javax.cache.configuration.Configuration<String, String> cacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(ehcacheConfig);
cacheManager.createCache("ehcache", cacheConfiguration); // 캐시 생성
return new JCacheCacheManager(cacheManager); // JCacheCacheManager 로 래핑하여 반환
}
}
- jsr107 을 명시해 JCache 프로바이더를 로드하고 "ehcache" 라는 이름으로 캐시를 생성합니다.
RedisService.java
package com.cache.cachemanager.service;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Duration;
@Service
@RequiredArgsConstructor
public class RedisCacheService {
private final RedisTemplate<String, String> redisTemplate;
public void setValue(String key, String value) {
redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(10)); // TTL 10분
}
public String getValue(String key) {
return redisTemplate.opsForValue().get(key);
}
}
- RedisTemplate 을 주입받아, set/get 함수를 작성합니다.
EHCacheService.java
package com.cache.cachemanager.service;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class EHCacheService {
@CachePut(value = "ehcache", key = "#key" ) // 캐시 이름(EHCacheConfig.java 에서 설정)과 키 지정
public String setValue(String key, String value){
// 메서드를 무조건 실행하고, 반환값을 지정된 캐시 이름과 키에 저장
return value;
}
@Cacheable(value = "ehcache", key = "#key" )
public String getValue(String key){
// 캐시에 데이터가 있으면 메서드를 실행하지 않고 캐시 값을 반환
return "No Cache"; // 캐시 미스 시
}
}
- @CachePut 을 사용하여 반환값을 지정된 캐시 이름과 키에 저장합니다.
- @Cacheable 을 사용하여 캐시된 데이터가 있으면 바로 반환하고 없다면 메서드를 수행합니다.
CacheController.java
package com.cache.cachemanager.controller;
import com.cache.cachemanager.service.EHCacheService;
import com.cache.cachemanager.service.RedisCacheService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/cache")
public class CacheController {
private final RedisCacheService redisCacheService;
private final EHCacheService ehCacheService;
@PutMapping("/redis/{key}")
public String setRedisCache(@PathVariable String key, @RequestParam String value){
redisCacheService.setValue(key, value);
return value;
}
@GetMapping("/redis/{key}")
public String getRedisCache(@PathVariable String key) {
return redisCacheService.getValue(key);
}
@PutMapping("/ehcache/{key}")
public String setEHCache(@PathVariable String key, @RequestParam String value) {
return ehCacheService.setValue(key, value);
}
@GetMapping("/ehcache/{key}")
public String getEHCache(@PathVariable String key) {
return ehCacheService.getValue(key);
}
}
- Redis PUT: /api/cache/redis/name?value=홍길동
- Redis GET: /api/cache/redis/name
- Cache PUT: /api/cache/ehcache/name?value=김철수
- Cache GET: /api/cache/ehcache/name
5. 마무리
Redis와 EHCache는 각각의 강점을 살려 캐싱 전략을 다양화할 수 있는 강력한 도구입니다. Redis는 분산 환경에서, EHCache는 로컬환경에서 유용하며, SpringBoot와 통합하면 쉽게 적용 가능합니다. 감사합니다.
'프레임워크 > SpringBoot' 카테고리의 다른 글
[SpringBoot] Supplier 와 Consumer 의 활용 (0) | 2025.09.11 |
---|---|
[SpringBoot] JPA 낙관락과 비관락으로 동시성 제어하기 (0) | 2025.09.05 |
[JPA] 더티 체킹이란? (2) | 2025.08.26 |
[SpringBoot] MyBatis 다중 Datasource 적용하기(@Qualifier) - Mapper 경로 공유 (0) | 2025.04.09 |
[SpringBoot] HTTP 요청 다루기(@RequestBody, @RequestParam, @ModelAttribute) (0) | 2025.04.08 |
최근에 올라온 글
- Total
- Today
- Yesterday