it-source

스프링 부팅 시 캐시 다시 로드/새로 고침

criticalcode 2023. 7. 25. 21:06
반응형

스프링 부팅 시 캐시 다시 로드/새로 고침

저는 스프링 부트를 사용하고 있고 캐싱에는 Ehcache를 사용하고 있습니다.지금까지 잘 작동하고 있습니다.그러나 이제 다시 로드하거나 새로 고쳐야 하므로 애플리케이션에 다운타임이 발생하지 않도록 하려면 어떻게 해야 합니까?

Spring Ehcache에서 여러 방법을 시도해 보았지만 작동하지 않거나 그렇지 않으면 스케줄러를 작성하고 데이터를 다시 로드해야 합니다.

@Override
@Cacheable(value="partTypeCache", key="#partKey")
public List<PartType> loadPartType(String partKey) throws CustomException {
        return productIdentityDao.loadPartType();
}

분명히 당신의 문제에 대한 모든 의견이 옳았습니다.CacheEvict를 사용해야 합니다.여기서 해결책을 찾았습니다. https://www.baeldung.com/spring-boot-evict-cache 은 다음과 같습니다.

당신이 해야 할 일은 e.g.라고 불리는 클래스를 만드는 것입니다.캐시 서비스 및 사용자가 가진 모든 캐시된 개체를 제거하는 메서드를 만듭니다.그런 다음 해당 방법에 @예약됨을 주석으로 표시하고 구간 비율을 입력합니다.

@Service
public class CacheService {

    @Autowired
    CacheManager cacheManager;

    public void evictAllCaches() {
        cacheManager.getCacheNames().stream()
          .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
    }

    @Scheduled(fixedRate = 6000)
    public void evictAllcachesAtIntervals() {
        evictAllCaches();
    }

}

많은 사람들이 사용하기 위해 제안한 옵션@CacheEvict맞습니다.또한 캐시(근거리)에 항상 최신 데이터가 로드되도록 하려면 데이터베이스에서 데이터가 실행 중인 앱에 대한 경계를 벗어나 업데이트되더라도 앱의 SLA와 일치하는 간격으로 전체 데이터셋을 주기적으로 다시 로드해야 합니다.위에서 제안한 솔루션에서 아래와 같이 모든 데이터를 다시 로드하는 논리를 추가합니다.

@Service
public class CacheService {

    @Autowired
    CacheManager cacheManager;

    public void refreshAllCaches() {
        cacheManager.getCacheNames().stream()
          .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
        // reload whole dataset here, dummy example here:
        dataRepository.findAll().forEach(a -> cacheManager.getCache("cache-name")).put(a.getKey(), a));
    }

    @Scheduled(fixedRate = 6000)
    public void refreshAllcachesAtIntervals() {
        refreshAllCaches();
    }

}

댓글에서도 언급했듯이 다음과 같은 방법을 사용해 보십시오.

    @Caching(evict={@CacheEvict(value="partTypeCache", key="#partKey")})
    public boolean deletePartType(String partKey) { 
      //when this method is invoked the cache is evicted for the requested key
    }

위의 답변 외에도 스케줄러 내부에서 cron을 사용할 수 있어 유연성을 높일 수 있습니다.당신은 많은 코드를 작성하지 않고 매일, 매주, 오후 12시에 스케줄러를 실행할 수 있습니다.

@서비스 공용 클래스 캐시 서비스 {}

@Autowired
CacheManager cacheManager;

public void evictAllCaches() {
    cacheManager.getCacheNames().stream()
      .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
}

@Scheduled(cron = "@weekly")
public void evictAllcachesAtIntervals() {
    evictAllCaches();
}

}

구체적으로 어떤 파트의 키를 갱신하려고 하는지 알고 계십니까?그렇지 않으면 캐시 자체에서 키를 찾아야 합니다.@CachePut을 사용하여 다운타임 없이 캐시 값을 업데이트할 수 있습니다.제 제안의 성능은 좋지 않겠지만, 정확히 당신이 원하는 것을 해야 합니다.

특히 EhCache의 경우:

public void renewCache() {
    net.sf.ehcache.EhCache cache = (net.sf.ehcache.EhCache) org.springframework.cache.CacheManager.getCache("partTypeCache").getNativeCache();
    for (Object key : cache.getKeys()) {
          updatePartTypeCache((String) key)
    }
}

@CachePut(value="partTypeCache", key="#partKey")
public List<PartType> updatePartTypeCache(String partKey) throws CustomException {
        return productIdentityDao.loadPartType();
}

이 중 가장 나쁜 부분은 기존 캐시에서 키를 가져오는 것입니다.캐시에 보관할 "핫" 부품의 짧은 목록이 있는 경우에는 해당 부품에 대해 updatePartTypeCache를 호출하면 됩니다.

요구 사항은 하나의 캐시를 X 간격으로 새로 고치고 다른 캐시를 Y 간격으로 새로 고친다는 것입니다.아래 코드를 1개의 클래스에서만 작성하면 캐시가 다시 로드되지 않습니다.


public class XXXSchedulers {

    @Autowired
    private XXXUtil util;

    @Scheduled(fixedDelay = 10 * 60 * 1000) // Running after 10 minutes
    public void clearSpecificABCCache() {
        util.clearSpecificABCCache();
        util.getABC();//Again gets value in the cache
    }

    @Scheduled(cron = "0 0 2 * * ?") //Running Everyday at 2 AM public void 
    public void clearSpecificXYZCache() {
        util.clearSpecificABCCache();
        util.getXYZ();
    }
}

@Component
public class XXXUtil {
    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private XXXService service;

    @Cacheable("abc")
    public ABC getABC() {
        ABC abc = service.getABC();
    }

    public void clearSpecificABCCache() {
        cacheManager.getCache("abc").clear();
    }

    @Cacheable("xyz")
    public XYZ getXYZCache() {
        XYZ xyz = service.getXYZCache();
    }
    
    public void clearSpecificXYZCache() {
        cacheManager.getCache("xyz").clear();
    }
  }

언급URL : https://stackoverflow.com/questions/56458748/reload-refresh-cache-in-spring-boot

반응형