이 기사는 주로 다음과 같이 높은 처리량 및 스레드 안전 LRU 캐시의 관련 내용을 연구합니다.
몇 년 전, 키워드에 대한 ID를 찾기 위해 LRU 캐시를 구현했습니다. 필요한 처리량은 많은 locks 및 synchronized 키워드로 인한 성능 문제를 제거 할 수있을 정도로 크기 때문에 데이터 구조는 매우 흥미 롭습니다. 응용 프로그램은 Java로 구현됩니다.
일련의 원자 참조 할당은 LRU와 LRU 순서를 ConsurenTashMap에서 유지할 것이라고 생각했습니다. 처음에, 나는 값을 항목으로 감았습니다. 항목에는 이중 연결 목록의 LRU 체인에 노드가 있습니다. 체인의 꼬리는 최근에 사용 된 항목을 유지하고 헤드 노드는 캐시가 특정 크기에 도달 할 때 지워질 수있는 항목을 저장합니다. 각 노드는 찾는 데 사용되는 항목을 가리 킵니다.
키를 통해 값을 찾으면 캐시는 먼저이 값이 존재하는지 맵을 찾아야합니다. 존재하지 않으면 로더에 따라 데이터 소스의 값을 읽을 수있는 방식으로 읽고 "누락 된 경우 추가"에서 맵에 추가합니다. 높은 처리량을 보장하는 데 어려움은 LRU 체인을 효과적으로 유지하는 것입니다. 이 동시 해시 맵은 세분화되고 스레드 레벨은 특정 레벨에 있습니다 (맵을 구축 할 때 동시 레벨을 지정할 수 있음)는 너무 많은 스레드 경쟁을 경험하지 않습니다. 그러나 LRU 체인이 같은 방식으로 나눌 수 없습니까? 이 문제를 해결하기 위해 작업 청소를위한 보조 대기열을 도입했습니다.
캐시에는 6 가지 기본 방법이 있습니다. 캐시 히트의 경우 검색에는 두 가지 기본 작업의 기본 작업이 포함되어 있으며 거친 손실에는 4 가지 기본 방법이 있습니다 : Get, Load, Put 및 Offer. PUT 방법에서는 명확한 작업을 추적해야 할 수도 있습니다. 캐시가 발생하면 정제 작업이라는 LRU 체인에서 수동적으로 청소합니다.
GET : Key에 의해지도에서 조회 항목
로드 : 데이터 소스에서로드 값
풋 : 항목을 만들고 키에 매핑하십시오
제안 : 최근에 액세스 한 항목을 나타내는 LRU 목록의 꼬리에 노드를 추가하십시오.
퇴거 : 목록의 헤드에서 노드를 제거하고 맵에서 관련 항목을 제거합니다 (캐시가 특정 크기에 도달 한 후)
PURGE : LRU 목록에서 사용하지 않은 노드 삭제 - 우리는 이러한 노드를 구멍이라고합니다.
청소 작업 및 정제 작업은 모두 큰 배치의 처리 데이터입니다. 각 작업의 세부 사항을 살펴 보겠습니다.
Get 작업은 다음과 같이 작동합니다.
get (k) -> v key k key k key k k key k e eptry e 제안 e 제안 e 제안 e e evice e vere v v for key k 만들기 e < - (k, v) 입력 엔드 리턴 값 ev를 시도해보십시오.
키가 존재하는 경우 LRU 체인의 꼬리에 새 노드를 제공하여 이것이 최근에 사용 된 값임을 나타냅니다. Get and Offer의 실행은 원자 연산이 아니기 때문에 (여기서 잠금 없음), 우리는 이것이 가장 최근에 사용 된 노드 포인트가 가장 최근에 사용 된 엔티티를 포인트한다고 말할 수는 없지만 동시에 실행할 때 가장 최근에 사용 된 엔티티입니다. 우리는 처리량을 제한 할 수 있으므로 스레드간에 순서를 실행하도록 강요하고 제안하지 않습니다. 노드를 제공 한 후 값을 지우고 리턴하기 위해 일부 작업을 수행하려고합니다. 아래의 제안 및 퍼지 운영을 자세히 살펴 보겠습니다.
캐시 손실이 발생하면 로더를 호출 하여이 키의 값을로드하고 새 엔티티를 작성하여 맵에 넣으면 풋 작업은 다음과 같습니다.
put (e) -> e 기존 항목 ex <-map.putifabsent (ek, e)가없는 경우 제안 e; 크기가 evict-reshold에 도달하면 일부 항목 종료 엔드 리턴 항목 E else, 기존 항목 Ex reture entry ex End가 있습니다.
보시다시피, 둘 이상의 스레드가 엔티티를지도에 넣을 때 경쟁이있을 수 있지만 하나의 성공 만 허용되며 제안이 호출됩니다. LRU 체인의 꼬리에 노드를 제공 한 후 캐시가 임계 값에 도달했는지 확인해야합니다. 이는 배치 클리어 작업을 시작하는 데 사용하는 식별자입니다. 이 특정 응용 프로그램 시나리오에서 임계 값 설정은 용량보다 작습니다. 청소 작업은 모든 엔티티가 추가 될 때보다 작은 배치에서 발생합니다. 캐시 용량이 용량에 도달 할 때까지 여러 스레드가 청산 작업에 참여할 수 있습니다. 잠금은 쉽지만 스레드는 안전 할 수 있습니다. LRU 체인의 헤드 노드를 지우려면 제거가 필요하므로 맵에서 멀티 스레드 제거 작업을 피하기 위해 신중한 원자 연산이 필요합니다.
이 제안 운영은 매우 흥미 롭습니다. 항상 노드를 만들려고하지만 더 이상 LRU에서 사용되지 않는 노드를 제거하고 삭제하려고 시도하지 않습니다.
(e) 테일 노드가 항목을 할당하지 않는 경우, 전류 노드 c <-en 새 노드 n (e)을 할당하는 경우, 새 노드 참조는 enther e에 대한 새로운 노드 기준기 e에 대한 nold ce, ce, c, null set act to null에 n을 추가하지 않으면 nold ce를 추가하십시오.
먼저, 체인의 꼬리에있는 노드가 액세스 된 엔티티를 가리키지 않음을 확인합니다. 모든 스레드가 동일한 키 값 쌍에 자주 액세스하지 않는 한 다르지 않습니다. 체인의 꼬리에 새 노드가 생성됩니다. 이 엔티티가 다르면 새 노드를 제공하기 전에 엔티티를 비교하고 작동하는 것을 설정하려고 시도하므로 여러 스레드가 동일한 작업을 수행하지 못하게됩니다.
노드를 성공적으로 할당하는 스레드는 LRU 체인의 끝에 새 노드를 제공합니다. 이 작업은 ConcurrentLinkedQueue의 찾기와 동일합니다. 종속성 알고리즘은 다음 기사에 설명되어 있습니다. 단순하고 빠르며 실용적인 비 차단 및 차단 동시 대기열 알고리즘. 그런 다음 스레드는 엔티티가 이전에 다른 노드와 관련이 있는지 확인합니다. 그렇다면 이전 노드는 즉시 삭제되지 않지만 구멍으로 표시됩니다 (엔티티에 대한 참조는 비어 있습니다).
위의 내용은 고 처리량 및 스레드 안전 LRU 캐시에 대한이 기사에 대한 자세한 설명이며 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!