문제

"컴퓨터 과학에는 두 가지 어려운 문제가 있습니다 : 캐시 무효화 및 이름 지정."

Phil Karlton

캐시를 무효화하는 일반적인 해결책이나 방법이 있습니까? 항목이 부실한시기를 알기 위해 항상 새로운 데이터를 얻을 수 있습니까?

예를 들어 함수를 고려하십시오 getData() 파일에서 데이터를 얻습니다. 파일의 마지막 수정 시간을 기준으로 캐시를 사용하며 호출 할 때마다 확인합니다.
그런 다음 두 번째 함수를 추가합니다 transformData() 데이터를 변환하고 다음에 함수가 호출 될 때 결과를 캐시합니다. 파일에 대한 지식이 없습니다. 파일이 변경되면이 캐시가 유효하지 않다는 종속성을 어떻게 추가합니까?

당신은 전화 할 수 있습니다 getData() 매번 transformData() 호출되고 캐시를 빌드하는 데 사용 된 값과 비교하지만 비용이 많이들 수 있습니다.

도움이 되었습니까?

해결책

당신이 말하는 것은 평생 의존성 체인입니다. 한 가지는 통제의 제어 외부에서 수정할 수있는 다른 것에 의존한다는 것입니다.

indempotent 기능이있는 경우 a, b 에게 c 어디에, if a 그리고 b 그때 동일합니다 c 동일하지만 점검 비용 b 당신보다 높습니다 :

  1. 언젠가는 날짜가 아닌 정보로 운영되며 항상 확인하지 마십시오. b
  2. 확인을 위해 최선을 다하십시오 b 최대한 빨리

당신은 당신의 케이크를 가지고 먹을 수 없습니다 ...

추가 캐시를 기준으로 계층화 할 수있는 경우 a 상단에서 이것은 초기 문제에 영향을 미치지 않습니다. 당신이 1을 선택했다면 당신은 당신이 자신에게주는 자유가 있고, 따라서 더 캐시 할 수 있지만, 캐시 된 가치의 유효성을 고려해야한다는 것을 기억해야합니다. b. 2를 선택하면 여전히 확인해야합니다 b 매번 캐시에 다시 떨어질 수 있습니다. a 만약에 b 체크 아웃.

캐시를 계층화하는 경우 결합 된 동작의 결과로 시스템의 '규칙'을 위반했는지 여부를 고려해야합니다.

당신이 그것을 알고 있다면 a 항상 타당성이 있습니다 b 그렇다면 캐시와 같은 캐시를 배열 할 수 있습니다 (pseudocode) :

private map<b,map<a,c>> cache // 
private func realFunction    // (a,b) -> c

get(a, b) 
{
    c result;
    map<a,c> endCache;
    if (cache[b] expired or not present)
    {
        remove all b -> * entries in cache;   
        endCache = new map<a,c>();      
        add to cache b -> endCache;
    }
    else
    {
        endCache = cache[b];     
    }
    if (endCache[a] not present)     // important line
    {
        result = realFunction(a,b); 
        endCache[a] = result;
    }
    else   
    {
        result = endCache[a];
    }
    return result;
}

분명히 연속적인 레이어링 (예 : x) 각 단계에서 새로 추가 된 입력의 유효성이 a:b 관계 x:b 그리고 x:a.

그러나 유효성이 전적으로 독립적 인 (또는 주기적) 3 개의 입력을 얻을 수 있으므로 레이어링이 불가능할 수 있습니다. 이것은 // 중요한 선이 변경되어야한다는 것을 의미합니다.

if (endCache [a 만료 또는 존재하지 않음)

다른 팁

캐시 무효화의 문제점은 우리가 알지 못하고 물건이 바뀌는 것입니다. 따라서 어떤 경우에는, 그것에 대해 알고 우리에게 알릴 수있는 다른 것이 있다면 해결책이 가능합니다. In the given example, the getData function could hook into the file system, which does know about all changes to files, regardless of what process changes the file, and this component in turn could notify the component that transforms the data.

문제를 해결하기위한 일반적인 마법 수정이 있다고 생각하지 않습니다. 그러나 많은 실용적인 경우에는 "폴링"기반 접근 방식을 "인터럽트"기반 접근 방식으로 변형시킬 수있는 기회가 매우 좋을 수 있으며, 이는 문제를 단순히 사라질 수 있습니다.

변환을 할 때마다 getData ()를 얻으려면 캐시의 전체 이점을 제거했습니다.

예를 들어, 변환 된 데이터를 생성 할 때 파일 이름과 마지막 수정 된 파일을 저장하기위한 솔루션처럼 보입니다. 데이터가 생성 된 파일 (GetData가 반환 한 데이터 구조에 이미 저장되었습니다). ), 따라서 해당 레코드를 transformData ()에 의해 반환 된 데이터 구조로 복사 한 다음 transformData ()를 다시 호출하면 파일의 마지막 수정 된 시간을 확인하십시오.

IMHO, 기능적 반응성 프로그래밍 (FRP)은 캐시 무효화를 해결하는 일반적인 방법입니다.

이유는 다음과 같습니다. FRP 용어의 오래된 데이터는 결함. FRP의 목표 중 하나는 결함이 없음을 보장하는 것입니다.

FRP는 이것에 대해 더 자세히 설명합니다 'FRP의 본질'대화 그리고 이것에서 그러니 대답.

에서 말하다 그만큼 Cells는 캐시 된 물체/엔티티를 나타냅니다 Cell 의존성 중 하나가 새로 고침되면 새로 고침됩니다.

FRP는 종속성 그래프와 관련된 배관 코드를 숨기고 부실하지 않은지 확인합니다 Cell에스.


내가 생각할 수있는 또 다른 방법 (FRP와 다름)은 계산 된 값을 래핑하는 것입니다. b) 어떤 종류의 작가 모나드로 Writer (Set (uuid)) b 어디 Set (uuid) (Haskell Exation) 계산 된 값에 대한 돌연변이 값의 모든 식별자가 포함됩니다. b 의존합니다. 그래서, uuid 계산 된 변이 가능한 값/변수 (데이터베이스의 행)를 식별하는 일종의 고유 식별자입니다. b 의존합니다.

이 아이디어를 이런 종류의 작가 모나드에서 작동하는 콤비네이터와 결합 하여이 콤비네이터를 사용하여 새를 계산하는 경우 일반적인 캐시 무효화 솔루션으로 이어질 수 있습니다. b. 그러한 조합 자 (예 : 특수 버전 filter) 작가 모나드를 가져 가십시오 (uuid, a)-입력으로 a 변이 가능한 데이터/변수로 식별됩니다 uuid.

그래서 "원본"데이터를 변경할 때마다 (uuid, a) (데이터베이스에서 정규화 된 데이터를 말하면 b 계산 된 유형의 계산 된 값 b 그러면 포함 된 캐시를 무효화 할 수 있습니다 b 값을 돌려받는 경우 a 계산 된 b 값은에 따라 다릅니다 Set (uuid) 작가 모나드에서는 이런 일이 언제 발생하는지 알 수 있습니다.

그래서 당신은 주어진 사람으로 무언가를 돌연변이 할 때마다 uuid, 당신은이 돌연변이를 모든 캐시 -S에 방송하고 값을 무효화합니다. b 이는 Said로 식별 된 변이성 값에 따라 다릅니다 uuid 작가 모나드 왜 b 랩핑 된 지 알 수 있습니다 b Said에 따라 다릅니다 uuid 아니면 아니에요.

물론, 이것은 당신이 쓰는 것보다 훨씬 더 자주 읽는 경우에만 돈을 지불합니다.


세 번째의 실용적인 접근 방식은 데이터베이스에서 구체화 된보기를 사용하여 캐시 -ES로 사용하는 것입니다. Afaik 그들은 또한 무효화 문제를 해결하는 것을 목표로합니다. 물론 이것은 변이 가능한 데이터를 파생 데이터에 연결하는 작업을 제한합니다.

나는 지금 당장 접근 방식을 연구하고 있습니다 포스트 쇼트 그리고 추억 기능. 나는 멘토를 지나서 그것을 실행했고, 그는 그것이 내용의 비수성 방식으로 캐싱을 잘 구현했다는 데 동의합니다.

모든 함수에는 만료 기간을 지정하는 속성이 표시 될 수 있습니다. 이러한 방식으로 표시된 각 함수는 메모 화되고 결과는 캐시에 저장되며 기능 호출 해시와 키로 사용되는 매개 변수가 있습니다. 사용 중입니다 속도 백엔드의 경우 캐시 데이터의 분포를 처리합니다.

항목이 부실한시기를 알기 위해 캐시를 작성하는 일반적인 솔루션이나 방법이 있습니까? 따라서 항상 새로운 데이터를 얻을 수 있습니까?

아니요, 모든 데이터가 다르기 때문에. 일부 데이터는 1 분 후에, 일부는 1 시간 후에 "오래된"일 수 있으며, 일부는 며칠 또는 몇 달 동안 괜찮을 수 있습니다.

특정 예제와 관련하여 가장 간단한 솔루션은 파일에 대한 '캐시 확인'기능을 갖는 것입니다. getData 그리고 transformData.

일반적인 해결책은 없지만 :

  • 캐시는 프록시 (풀) 역할을 할 수 있습니다. 누군가가 전화 할 때 캐시가 마지막 원점 변경의 타임 스탬프를 알고 있다고 가정합니다. getData(), 캐시는 원산지에 마지막 변경의 타임 스탬프를 요청합니다. 동일하면 캐시를 반환하고 그렇지 않으면 컨텐츠를 소스로 업데이트하고 컨텐츠를 반환합니다. (변형은 클라이언트가 요청에 따라 타임 스탬프를 직접 보내는 것입니다. 소스는 타임 스탬프가 다른 경우에만 콘텐츠를 반환합니다.)

  • 여전히 알림 프로세스 (푸시)를 사용할 수 있으며, 캐시는 소스를 관찰하고 소스가 변경되면 캐시에 알림을 보낸 다음 "더러운"으로 표시됩니다. 누군가 전화하면 getData() 캐시가 먼저 소스로 업데이트되고 "더러운"플래그를 제거합니다. 그런 다음 콘텐츠를 반환하십시오.

일반적으로 말하는 선택은 다음에 따라 다릅니다.

  • 빈도 : 많은 사람들이 전화를 겁니다 getData() gettimestamp 함수에 의해 소스가 범람하는 것을 피하기 위해 푸시를 선호합니다.
  • 소스에 대한 액세스 : 소스 모델을 소유하고 있습니까? 그렇지 않은 경우 알림 프로세스를 추가 할 수 없습니다.

참고 : 타임 스탬프를 사용하는 것이 HTTP 프록시가 작동하는 전통적인 방법이므로 다른 접근 방식은 저장된 컨텐츠의 해시를 공유하는 것입니다. 두 개체가 함께 업데이트되는 유일한 방법은 내가 당신을 부르거나 (풀) 또는 당신이 나를 부르는 것입니다… (푸시) 그게 전부입니다.

캐시는 다음을 고려해야하기 때문에 어렵다 : 1) 캐시는 다중 노드이며, 합의가 필요합니다.

이것은 좋은 독서입니다 :https://www.confluent.io/blog/turning-the-database-inside-out-with-apache-samza/

아마도 캐시-거부 알고리즘은 가장 빠른 캐시를 사용하고 거기에서 계속 이동하기 때문에 가장 일반적인 알고리즘 (또는 적어도 하드웨어 구성에 따라 다름) 일 것입니다. 여기에 대한 MIT 강의가 있습니다. 캐시 망각 알고리즘

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top