Guava LoadingCache
을 사용하여 데이터를 채우고 1 분 간격으로 LoadingCache
에서 모든 항목을 제거하고 싶습니다.Guava LoadingCache에서 레코드를 안전하게 삭제하는 방법은 무엇입니까?
public class MetricHolder {
private final ExecutorService executor = Executors.newFixedThreadPool(2);
private final LoadingCache<String, AtomicLongMap<String>> clientIdMetricCounterCache =
CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES)
.removalListener(RemovalListeners.asynchronous(new SendToDatabase(), executor))
.build(new CacheLoader<String, AtomicLongMap<String>>() {
@Override
public AtomicLongMap<String> load(String key) throws Exception {
return AtomicLongMap.create();
}
});
private static class Holder {
private static final MetricHolder INSTANCE = new MetricHolder();
}
public static MetricHolder getInstance() {
return Holder.INSTANCE;
}
private MetricHolder() {}
public void increment(String clientId, String name) throws ExecutionException {
clientIdMetricCounterCache.get(clientId).incrementAndGet(name);
}
public LoadingCache<String, AtomicLongMap<String>> getClientIdMetricCounterCache() {
return clientIdMetricCounterCache;
}
private static class SendToDatabase implements RemovalListener<String, AtomicLongMap<String>> {
@Override
public void onRemoval(RemovalNotification<String, AtomicLongMap<String>> notification) {
String key = notification.getKey();
AtomicLongMap<String> value = notification.getValue();
System.out.println(key);
System.out.println(value);
// sending these key/value to some other system
}
}
}
나는 다중 스레드 방식의 코드에서 다른 장소의 많은에서 increment
메소드를 호출하고 있습니다. 따라서 1 분 동안 많은 측정 항목을 clientIdMetricCounterCache
에 채 웁니다. 이제 1 분마다 모든 메트릭 을 안정적으로에 놓고 모든 메트릭을 데이터베이스에 보내려고합니다.
내 경우에는 가끔 increment
메서드에 쓰기가 매우 느릴 수 있지만 1 분마다 모든 항목을 삭제하고이 캐시에 전혀 읽지 않고 그냥 쓰고 그 다음에 삭제합니다. 다른 시스템으로 보내 레코드. 아래는 내가 "자동"는 구아바에 정리를 수행하고 값을 퇴거하지 않는 CacheBuilder로 구축 wiki
캐시를 보았다 또는 즉시 값이 만료 된 후, 또는 종류의 어떤 것입니다. 대신, 쓰기 조작 중에 또는 8 기 수가 희박한 경우 8 분의 읽기 조작 중에 소량의 유지 보수를 수행합니다.
그럼 expireAfterWrite
은 어떻게 작동합니까? 그것은 1 분마다 실행하고 모든 항목을 거기에 뭐든지간에 clientIdMetricCounterCache
에 삭제하고 다시 1 분 후 일어나서 동일한 캐시에서 모든 항목을 삭제하고 계속 그런 스케줄러처럼 작동합니까? 위키를 읽은 후, 나는 그것이 위와 같이 작동하는지 의심 스럽다. 만약 그렇지 않다면 어떻게하면 1 분마다 그 레코드를 안전하게 삭제하고 다른 시스템으로 보낼 수 있습니까? 필자의 글은 당분간 희귀 할 수 있습니다.
Guava TimeLimiter
인터페이스와 SimpleTimeLimiter
을 사용해야 할 수도 있고, 통화를 안정적으로 시간 초과하고 항목을 삭제하려면 ScheduledExecutorService
일 수 있습니다. 그렇다면, 현재 예제에서 어떻게 작동할까요?
'TimeLimiter'와는 아무런 관계가 없지만, 인용 한 문서가 정기적으로'Cache.cleanUp()'을 호출하는 백그라운드 스레드를 생성합니다. – shmosel
캐시 된 값을 바꾸는 대신 캐시 된 값을 수정하기 때문에 다른 스레드가 정리하려는 'AtomicLongMap'에 대한 참조를 가지고 있으면 제거 수신기에서 동시 업데이트가 손실 될 수 있습니다. – shmosel
@shmosel 그래, 위키에서 그걸 봤어. 내가 가지고있는 혼란은 배경 스레드에서해야 할 일입니다. 정기적으로'clientIdMetricCounterCache.cleanUp()'를 의미하는'Cache.cleanUp()'을 호출하면됩니까? 예제를 제공 할 수 있다면, 이렇게하면 혼란 스러울 것입니다. – john