2014-12-18 3 views
4

내 서비스 끝점은 시간 스탬프와 함께 매분의 메트릭 목록을받습니다. 메트릭이 특정 조건을 통과하면 캐시에 저장해야 나중에 액세스 할 수 있습니다. 이 서비스에 대한 액세스 기능은 다음과 같습니다 -타임 스탬프를 기반으로 축출을 통한 캐싱

List<Metrics> GetAllInterestingMetrics5Mins(); 
List<Metrics> GetAllInterestingMetrics10Mins(); 
List<Metrics> GetAllInterestingMetrics30Mins(); 

내 curent 솔루션은 5로 설정 시간을 기준으로 퇴거 3 구아바 캐시, 10 & 15 분 사용하는 것입니다. 누군가 위의 함수 중 하나를 호출하면 relant 캐시에서 모든 메트릭을 반환합니다. 값이 캐시에 넣어 (또는 설정에 따라 액세스) 경우에 따라 퇴거

  1. 구아바 캐시 개시 타이밍 -

    이 2 문제가 있습니다. 이제 메트릭이 지연 될 수 있으므로 타임 스탬프는 메트릭이 캐시에 저장되는 시간보다 빠릅니다.

  2. 3 개의 캐시를 만들어야하는데 30 분이 걸리는 캐시 하나 만 있으면 충분하므로 캐시 처리에서 메모리 공간과 복잡성이 증가합니다.

구아바 또는 상자 밖의 캐싱 솔루션에서 이러한 2 가지 문제를 해결할 수있는 방법이 있습니까?

답변

1

:

그냥 (!) 참고 : 만료 및 퇴거를 혼동하지 마십시오. 만료는 항목이 캐시에 의해 더 이상 반환되지 않을 수 있으며 지정된 시점 또는 기간 후에 발생할 수 있음을 의미합니다. 축출은 자원을 비우기위한 조치이며, 항목은 캐시에서 제거됩니다. 만료 후 동시에 또는 나중에 퇴거가 발생할 수 있습니다.

모든 일반적인 캐시 제품은 일명 "특정 시점"만료를 지원하지 않습니다. 우리는 우리의 응용 프로그램에서 자주 사용법을 필요로하므로 이것을 지원하기 위해 cache2k과 약간의 노력을했습니다. 당신이 메트릭 객체의 시간 기준이있는 경우

static class MetricsEntry { 

    long nextUpdate; 
    List<Metrics> metrics; 

} 

static class MyEntryExpiryCalculator implements EntryExpiryCalculator<Integer, MetricsEntry> { 
    @Override 
    public long calculateExpiryTime(Integer _key, MetricsEntry _value, long _fetchTime, CacheEntry _oldEntry) { 
    return _value.nextUpdate; 
    } 
} 

Cache createTheCache() { 
    Cache<Integer, MetricsEntry> cache = 
    CacheBuilder.newCache(Integer.class, MetricsEntry.class) 
     .sharpExpiry(true) 
     .entryExpiryCalculator(new MyEntryExpiryCalculator()) 
     .source(new MySource()) 
     .build(); 
    return cache; 
} 

, 당신은 그것을 사용할 수 있습니다 및 추가 항목 클래스를 생략 할 수 있습니다 : 여기

는 cache2k의 청사진이다. sharpExpiry(true)은 cache2k에 정확한 만기를 지시합니다. 이 값을 지정하지 않으면 만료 시간이 수 밀리 초이지만 액세스 시간은 약간 더 빠릅니다. 주제 2에 관한

:

직선 앞으로 접근 방식은 캐시 키와 간격 분을 사용하는 것입니다. 당신이 요청을 할 경우 05 :

static class MySource implements CacheSource<Integer, MetricsEntry> { 
    @Override 
    public MetricsEntry get(Integer interval) { 
    MetricsEntry e = new MetricsEntry(); 
    boolean crossedIntervalEnd; 
    do { 
     long now = System.currentTimeMillis(); 
     long intervalMillis = interval * 1000 * 60; 
     long startOfInterval = now % (intervalMillis); 
     e.metrics = calculateMetrics(startOfInterval, interval); 
     e.nextUpdate = startOfInterval + intervalMillis; 
     now = System.currentTimeMillis(); 
     crossedIntervalEnd = now >= e.nextUpdate; 
    } while (crossedIntervalEnd); 
    return e; 
    } 
} 

(10)에 대한 메트릭을 반환 : 00-10 여기

엄격하게 이전 구간의 통계를 반환 (캐시 로더 일명) 캐시 소스 10:07라고 말하십시오.

방금 ​​즉시 과거 간격의 측정을 계산하려면

는, 그것은 간단하다 :

static class MySource implements CacheSource<Integer, MetricsEntry> { 
    @Override 
    public MetricsEntry get(Integer interval) { 
    MetricsEntry e = new MetricsEntry(); 
    long intervalMillis = interval * 1000 * 60; 
    long startOfInterval = System.currentTimeMillis(); 
    e.metrics = calculateMetrics(startOfInterval, interval); 
    e.nextUpdate = startOfInterval + intervalMillis; 
    return e; 
    } 
} 

캐시 소스의 사용은 put()을 통해 장점이있다. cache2k가 블로킹 중이므로 하나의 메트릭에 대해 여러 요청이 들어 오면 하나의 메트릭 계산 만 시작됩니다.

밀리 초에 대한 정확한 만료가 필요하지 않으면 다른 캐시도 사용할 수 있습니다. 캐시 값 내에 메트릭을 계산하는 데 걸리는 시간을 저장 한 다음 이에 따라 만료 시간을 수정해야합니다.

좋은 점이 있습니다!

1

대신 Deque과 같은 것을 사용 해본 적이 있습니까? 메트릭을 대기열에 넣고 마지막 N 분에 대한 메트릭을 검색하려면 가장 최근의 추가로 끝에서 시작하여> N 분 전의 항목을 찾을 때까지 모든 항목을 가져옵니다. 유사한 방법으로 상대방과 너무 오래 된 항목을 제거 할 수 있습니다. (Cache의 키/값 측면이 귀하의 문제와 어떤 관련이 있는지 명확하지 않습니다.)

+0

그런데 주기적으로 이전 항목을 제거하는 스레드를 작성해야합니다. 상자 밖으로 벗어나는 상자를 사용하는 것이 전체 캐시를 피하는 것이 아닌가? 이 문제에 키/값 측면이 없다는 것이 맞습니다. 방금 키로 해시 코드를 사용했기 때문에 대기열을 기반으로하는 시간을 찾을 수 없었습니다. –

+1

새 항목을 추가하거나 항목을 읽는 방법 중 하나가 호출되었을 때 만료 된 항목을 삭제할 수 없습니까? 이것이 본질적으로 '캐시 (Cache)'가하는 것입니다 : 모든 쓰기 (어쨌든 쓰여지는 세그먼트의 경우) 및 가끔 읽는 경우 제거 된 항목을 제거합니다. – ColinD

+2

@Rohitchauhan 캐시에서 제거하는 것은 캐싱에 "작은 추가 기능"일 뿐이며 효율적으로 구현할 수는 없습니다. 요점은 캐싱입니다. 키가 부족하다는 것은 캐시를 사용할 이유가 없다는 것을 의미합니다. 먼저 30 분 캐시와 필터를 수동으로 사용하도록 제안하고 싶었지만 'Deque'또는 'PriorityQueue'가 훨씬 더 의미가있는 것처럼 보입니다. 퇴거를 추가하는 것은 사소한 일입니다. – maaartinus

2

Guava 및 EHCache와 같은 솔루션을 캐싱하는 것과 구현하려고 시도하는 것과는 특별한 차이가 있습니다. 이러한 캐시의 유일한 목적은 getter 함수가 작동하는 것과 같은 방식으로 작동하는 것입니다. 따라서 캐시는 키로 단일 요소를 검색하여 나중에 사용하기 위해 저장합니다. 사용이 중지 된 후에 그것을 철회합니다.

예. 캐시에서 개체의 전체 집합을 얻는 이유

@Cacheable 
public Object getter(String key){ 
... 
} 

캐시 원래 목적과 다르게 작동 할 퇴거 정책을 강요 같은 작은 느낌.

Guava 캐시 (또는 다른 캐싱 솔루션) 대신 필요한 것은 타이머 기능으로 한꺼번에 제거 할 수있는 컬렉션입니다. 슬프게도, 구아바는 지금 그걸 제공하지 않습니다. 기존의 모든 요소를 ​​캐시에서 제거하는 응용 프로그램에서 제공하는 타이머 기능이 여전히 필요합니다.

그래서, 내 제안 될 것이다 다음

을 구아바는 당신이, 당신은 당신이 정말로 가치있는 구아바를 만드는 기능을 사용하지 않는 것을 발견 할 것이다 원하는 방식으로 행동하는 것이 가능하다하더라도 , 당신은 다르게 행동하도록 "강요"합니다. 따라서 Guava 구현을 잊어 버리고 예를 들어 AbstractMap 클래스의 특수화와 N 초마다 내용을 제거하는 타이머 함수를 사용하는 것을 고려해보십시오.

이렇게하면 모든 항목을 단일 캐시에 넣을 수 있고 타임 스탬프와 항목이 캐시에 추가 된 시간 사이의 불일치에 대해 걱정할 필요가 없습니다.주제 1에 관한

관련 문제