0

유형 (예 : 절대 또는 슬라이딩 만료)에 따라 보존 정책을 정의하는 팩토리를 사용하여 자작 나무 데이터 엔터티 저장소를 만들었습니다. 또한 정책은 캐시 유형을 httpcontext 요청, 세션 또는 응용 프로그램으로 지정합니다. MemoryCache는 3 가지 캐시 유형 모두에서 캐싱 프록시에 의해 유지 관리됩니다. 어쨌든, 나는 데이터 엔티티 (data entity) 서비스를 우리의 주 데이터 엔티티를로드하고 저장하는 저장소에 묶어 둔다. 아이디어는 엔티티 리포지토리를 사용하고 엔티티가 데이터 소스 (이 경우 db)에서 캐싱되거나 검색되는 경우주의 할 필요가 없습니다.MemoryCache를 사용하는 데이터 저장소

데이터 원본에서 엔터티를로드하기 전에 캐싱 된 엔터티를 저장해야하므로로드/저장 이벤트를 동기화해야한다는 것은 분명한 가정입니다.

그래서 나는 내가 읽은 :)

오늘은 MemoryCache 및 발사 CacheItemRemovedCallback 이벤트 (기본 20에서 제거되는 엔티티 사이 좋은 길이 차이가있을 수 있습니다 ... 오늘 생산 데이터 무결성 문제를 조사했다 초). 로드 주변에있는 간단한 잠금 장치와 데이터 저장 작업이 부족했습니다. 또한 CacheItemRemovedCallback은 HttpContext 외부의 자체 컨텍스트에 있었기 때문에 재미있었습니다. 그것은 잠재적으로 이벤트에 폐기 된 인스턴스를 할당 할 때 콜백 함수를 정적으로 만들어야한다는 것을 의미했습니다.

한때 나는 데이터 엔티티가 더 이상 캐시에 존재하지 않았지만 데이터 소스에 저장되지 않았을 수 있으므로 틈이 생길 가능성이 있다는 것을 깨달았습니다. 5000의 잘못된 주문을 설명 할 수 있습니다. 기본 데이터 엔티티에서 정책의 20 분 슬라이딩 만기를 초과하는 작업을 쉽게 수행 할 수 있습니다. 즉, 같은 만료 시점에로드 (요청 컨텍스트를 통한)와 저장 (캐시 만료 콜백을 통한) 간의 흥미로운 경쟁 조건이 발생하는 경우를 의미합니다.

간단한 잠금 장치로 주사위를 굴려서이기거나 저장할 수 있습니까? 데이터 소스 (db)의 다음로드 전에 저장해야합니다. 이상적으로 항목이 캐시에서 만료되면 원자 적으로 데이터 소스에 기록됩니다. 엔티티가 캐시에서 사라졌지만 만료 된 콜백이 아직 실행되지 않으면로드 조작이 적용될 수 있습니다.이 경우 엔티티가 캐시에서 발견되지 않으므로 데이터 소스에서로드가 기본값이됩니다. 그러나 저장 작업이 시작되지 않아서 데이터 무결성 손상이 발생하고 저장된 캐시 데이터가 손상 될 수 있습니다.

동기화를 수행하려면 명명 된 신호 잠금이 필요하므로 EventWaitHandle에 착수했습니다. 사용자마다 이름이 지정된 잠금이 생성됩니다 (즉, <000). 이로 인해로드가 만료 된 이벤트의 신호를 기다리는 동안로드가 엔터티 (HttpContext 외부의 자체 컨텍스트에 스레드가 있음)를 저장합니다. 따라서 저장시 기존 이름 핸들을 잡고 저장이 완료되면로드가 계속됨을 알리는 것이 쉽습니다.

또한 저장 작업으로 각 10 초 블록을 시간 초과 및 기록하는 중복성이 있습니다. 앞에서 말했듯이 기본값은 MemoryCache 형식에서 제거되는 엔티티와 해당 엔티티를 저장하는 이벤트를 발생시키는 엔티티 사이에 20 초가되는 것을 의미합니다.

내 말을 따랐던 모든 분들께 감사드립니다. 동기화 요구 사항의 특성을 감안할 때 EventWaitHandle은 최상의 솔루션을 잠그고 있습니까?

+0

아마 MemoryCache를 사용하면이 방법이 아주 좋은 디자인이 아닙니다. –

+0

특정 수준의 복잡성을 지나치게 나쁜 디자인을 부르는 것이 항상 유혹적입니다. 그러나 스레드간에 캐싱을 처리하는 것은 무리가 아니며 해당 스레드를 동기화해야하는 것은 무리라고 주장합니다. MemoryCache에 관해서는, 나는 더 나은 것을 발명하려고 노력할 가치가있을 것이라고 생각하지 않습니다. 나는 반대로, 또는 대안에 대한 논거, 또는 더 나은 동기화 메커니즘에 대해 듣고 싶다. – codinglifestyle

+0

[redis] (https://redis.io/topics/introduction)가 도움이 될 수 있습니다. –

답변

0

나는이 문제를 해결하기 위해 무엇을했는지 게시하고 싶습니다. 필자는 디자인을 여러 번 변경하여 이름이 지정된 동기화 객체가 필요없는 간단한 솔루션을 만들었으며 간단한 잠금을 대신 사용할 수있었습니다.

먼저 데이터 엔티티 리포지토리는 요청 캐시에 저장된 싱글 톤입니다. 저장소의 프런트 엔드는 캐시 자체에서 분리됩니다.대신 세션 캐시에 위치하도록 변경 했으므로 아래에서 중요해질 것입니다.

두 번째 만료 된 엔티티가 위의 데이터 엔티티 리포지토리를 통해 라우팅하도록 이벤트를 변경했습니다.

세 번째로 MemoryCache 이벤트를 RemovedCallback에서 UpdateCallback **으로 변경했습니다.

마지막으로 우리는 데이터 세션 저장소 인 일반 엔티티 저장소와 함께 잠금 장치를 연결하고로드 및 저장 (만료) 작업을 처리 할 수있는 잠금을 허용하는 틈새없는 만료 이벤트를 연결합니다.


은 **이 이벤트는 항목이 캐시에서 제거되기 전에 UpdateCallback이라고합니다) 모두와 B에 등록 할 수 없습니다)하는 재미 있지만 명시 적 (항목을 제거 할 때이 호출되지 않습니다 일명 myCache.Remove (엔티티)는 이벤트를 호출하지 않지만 UpdateCallback은 호출합니다. 항목이 캐시에서 강제 제거되는 경우 우리는 결정을 내 렸습니다. 이는 사용자가 회사를 변경하거나 쇼핑 목록을 지울 때 발생합니다. 따라서 이러한 시나리오는 엔티티가 결코 DB의 캐시 테이블에 저장되지 않도록 이벤트를 시작하지 않습니다. 디버깅 목적으로는 좋았지 만, 100 % 적용 범위를 갖는 RemovedCallback을 사용하려면 엔티티 존재의 림보 상태를 처리 할만한 가치가 없습니다.