ehcache

Posted by : at

Category : study


In-Memory Computing

인-메모리 컴퓨팅이란 Application이 운영을 위한 데이터를 하드 디스크가 아닌 메인 메모리에서 수행하는 것을 말한다.

즉, 연산을 위한 영역으로만 여겨졌던 메모리 영역을 대량의 데이터를 저장하여 처리할수 있는 공간으로 사용하는 것이다.

기술적/비용적 측면에서는

과거 Main Memory의 가격이 상대적으로 높았기 때문에 Memory 영역을 사용하는 것이 불가능/비효율적이었지만,

Memory의 가격이 낮아진 오늘 날에는 가능해지고, 보편화된 기술이 되었다.

In-Memory 컴퓨팅/아키텍쳐는 데이터의 절대적인 양과 종류가 폭발적으로 증가한 빅데이터 시대에 데이터 처리 속도를 향상시킬 수 있는 핵심 기술로 평가받고 있다.

Cache(캐시)란 데이터의 원본이나 원본 데이터를 통해 연산된 값을 미리 저장(복사)해두는 임시 저장소를 의미한다.

즉, 데이터의 읽기(Read) 성능을 개선시키기 위해 DB와 같은 영구 저장소로부터 로드된 데이터를 빠르게 읽어올 수 있는 Memory 영역에 저장해두는 방식인 것이다.

스프링 부트 캐시 적용하는 가장 쉬운 방법

@EnableCaching, @Cacheable, @CacheEvict

  • spring-boot-starter-cache 라이브러리 불러온다.
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
   </dependency>
  • 캐시 기능을 사용하고 싶은 프로젝트에 @EnableCaching을 쓴다.
    @EnableCaching
    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
  • 캐시하고 싶은 메서드에 @Cacheable, 캐시를 제거하고자하는 메서드에는 @CacheEvict를 쓴다.
@Service
public class TestService {
    private List<String> list;
    
    @PostConstruct
    public void init() {
        list = new ArrayList<>();
    }
    
    @Cacheable(value="test")
    public String getInformation(String info) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return list.stream().filter(x->x.equals(info)).findFirst().get();
    }
    
    @CacheEvict(value="test")
    public void createInformation(String info) {
        list.add(info);
    }
}

spring boot에서 캐시 기능을 추상화 시켜놨기 때문에 spring-boot-starter-cache 라이브러리를 불러오기만하면 아주 쉽게 사용이 가능하다. 즉, Anotation을 적용하는 것만으로도 캐시 기능을 사용할 수 있게 했다.

특히 스프링부트에서 자주 쓰는 캐시엔진(?)에 대해서는 자동으로 적용되게 해놨다. (Redis, Encache, ConcurrentMap, …)

spring-boot-starter-cache 라이브러리를 불러왔으면 @EnableCaching으로 해당 애플리케이션에서 캐시를 사용할 것임을 알린다. 그 후 캐시가 적용될 메서드에는 @Cacheable(value=”XXXX”)를 적용한다.

그러면 해당 메서드가 최초 1회 이후 호출될때마다 메서드의 파라미터가 같은 값이면 메서드를 호출하지 않고 결과값을 캐시에서 꺼내 리턴해준다.

redis 적용한 cache

  • dispatcher-servlet 설정 ```xml

## RedisTemplate
```java
//spring-boot parent 2.2이상 버전에서는 자동 설정에 의해서 redis template 빈이 4개가 생성됩니다.

    @Autowired RedisTemplate redisTemplate;

    @Autowired StringRedisTemplate stringRedisTemplate;

    @Autowired ReactiveRedisTemplate reactiveRedisTemplate;

    @Autowired ReactiveStringRedisTemplate reactiveStringRedisTemplate;

@EnableAutoConfiguration(exclude={RedisReactiveAutoConfiguration.class})로 reactive redis template은 자동 설정을 disable시킬 수 있습니다.

redisTemplate와 stringRedisTemplate의 차이는 Serializer(직렬화)입니다. redisTemplate의 key, value serializer는 JdkSerializationRedisSerializer이고 stringRedisTemplate의 serializer StringRedisSerializer입니다. 직렬화 방식이 다르기 때문에 혼용해서 사용하는 건 안 됩니다.

@Test
public void test() {

    redisTemplate.opsForValue().set("key", "hello");
    log.debug("redisTemplate get value => {}", redisTemplate.opsForValue().get("key"));
    //==> "hello"
    log.debug("stringRedisTemplate get value => {}", stringRedisTemplate.opsForValue().get("key"));
    //==> null
  • 만약 다른 직렬화 방식을 사용한다면 RedisTemplate bean을 생성해야 합니다. (RedisConnectionFactory은 자동 설정에 의해 생성된 빈을 주입받아 사용)
      @Bean
      public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory factory) {
          RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
          redisTemplate.setConnectionFactory(factory);
          redisTemplate.setKeySerializer(RedisSerializer.string());
          redisTemplate.setValueSerializer(RedisSerializer.java());
          redisTemplate.setHashKeySerializer(RedisSerializer.string());
          redisTemplate.setHashValueSerializer(RedisSerializer.java());
          return redisTemplate;
      }
    
  • bean 네임을 “redisTemplate”로 하면 자동 설정(RedisAutoConfiguration)이 redisTempate은 생성하지 않는다.
    public class RedisAutoConfiguration {
     
      @Bean
      @ConditionalOnMissingBean(
          name = {"redisTemplate"}
      )
      public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
          RedisTemplate<Object, Object> template = new RedisTemplate();
          ....
    
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
	updateCheck="false">

	<diskStore path="java.io.tmpdir" />
    <sizeOfPolicy maxDepth="100000" maxDepthExceededBehavior="continue"/>
<!-- 캐시 정의 -->
 <!-- 
     name : 캐시의 이름이다. @Cacheable("캐시의 이름") 와 일치시켜줘야한다. 
    diskExpiryThreadIntervalSeconds : 디스크에 저장된 캐시들에 대해 만료된 항목을 제거하기 위한 스레드를 실행할 주기 설정 
    diskSpoolBufferSizeMB : 디스크 캐시에 쓰기 모드로 들어갈 때 사용될 비동기 모드의 스폴 버퍼 크기 설정 (OutOfMemory 발생시 수치 낮추도록 함) 
    diskPersistent : VM이 재기동할 때 캐싱된 객체를 계속 유지할지 여부 
    eternal : 한번 캐시하면 영원히 유지할 것인지의 여부 
    maxElementsInMemory : 메모리에 캐싱될 최대 객체 수 
    maxEntriesLocalHeap : 힙메모리 최대량 
    overflowToDisk : 메모리저장공간이 부족할때 Disk 사용여부 
    memoryStoreEvictionPolicy : 최대 개수에 도달할 때, 제거 알고리즘 
    - FIFO : 먼저 저장된 데이터를 우선 삭제 
    - LFU : 데이터의 이용 빈도 수를 기준으로 이용 빈도가 가장 낮은 것부터 삭제 
    - LRU : 데이터의 접근 시점을 기준으로 최근 접근 시점이 오래된 데이터부터 삭제 
    overflowToDisk : maxElementsInMemory이 옴계량에 가까우면 오버플로우되는 객체들을 디스크에 저장할지 결정 
    timeToIdleSeconds : 다음 시간동안 유휴상태 후 갱신할지 결정 (데이터가 지정된 시간(초단위)동안 재호출되지 않으면 휘발됨) 
    timeToLiveSeconds : 한번 저장된 데이터의 최대 저장 유지 시간(초단위) 
    maxBytesLocalHeap : 최대 로컬 힙메모리 사용량 설정 (사용 시 maxEntriesLocalHeap 사용 불가) 
    maxBytesLocalDisk : maxBytesLocalHeap에 설정된 캐시 사용 이후 디스크 스토리지 한계 설정 -->

	<!--
        maxElementsInMemory="1000"    // 메모리에 유지되는 최대 캐시 수
        name="INTERFACE_CACHE"        // 캐시 이름
        eternal="false"               // 캐시 항목 유지 true:캐시 만료 안됨, false:설정에 따라 만료됨
        timeToIdleSeconds="120"       // 캐시가 마지막으로 사용된지 얼마 후에 소멸? default:0
        timeToLiveSeconds="120"       // 캐시 만료 시간, default : 0 (영원히 안 지움)
        overflowToDisk="false"         // 메모리가 꽉 찼을때 디스크에 저장 여부
        diskSpoolBufferSizeMB="100"   
        diskPersistent="false"        // VM 종료 대비 캐시를 디스크에 저장(백업 개념), default:120초
        diskExpiryThreadIntervalSeconds="120"    // 자바 GC랑 비슷한 역할, default:120초
    -->
	
	<defaultCache
            maxEntriesLocalHeap="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskSpoolBufferSizeMB="30"
            maxEntriesLocalDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
	
	
	<!-- /frontweb/src/main/resources/sql/display/displayCategorySql.xml -->
    <cache
        name="displayCategorySql.getDisplayCategoryList" 
        eternal="false" 
		maxEntriesLocalHeap="100000"
        overflowToDisk="false"
        diskPersistent="false"
		timeToIdleSeconds="0"
		timeToLiveSeconds="86400" 
		memoryStoreEvictionPolicy="LFU" />
</ehcache>
/* pom.xml*/ 
<!-- redis cache --> 
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.8.23.RELEASE</version>
</dependency>

<dependency>
    <groupId>biz.paluch.redis</groupId>
    <artifactId>lettuce</artifactId>
    <version>4.5.0.Final</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>redis information</comment>
	<entry key="redis.maxRedirects">2</entry>
	<entry key="redis.host1">hostip</entry>
	<entry key="redis.port1">port</entry>
</properties> 

About Ghosts
Ghosts

Hi I a Ghosts, a Web Developer and Designer.

Email : memories109@gmail.com

Website : https://ghostsdev.github.io/

About Ghosts

개인정보 공유, 포트폴리오 제작 , 블러그 관리, 하루 일상, 사진 갤러리

Star
Useful Links