키-값 저장에서 항목을 만료하는 알고리즘은 무엇입니까?


10

현재 키-값 저장소가 항목에 대해 "만료 날짜"를 구현하는 방법에 대해 생각하고있었습니다. 현재 내 마음에는 두 가지 변형이 있습니다.

  1. 그들은 아무것도하지 않고 (만료 된 데이터 유지) 예를 들어 어떤 키로 GET을 수행 할 때만 확인합니다. 여기서 문제는 메모리가 제한되어 있으면 만료 된 항목은 삭제되지 않는다는 것입니다.
  2. 추가 데이터 구조를 유지하여 "가장 빨리 만료"될 수 있습니다. 나는 다음과 같이 할 수 있음을 보았다.

    storage_data = dict(key -> [value, expire_timestamp])
    expire_tree = SomeBinaryLikeTree(expire_timestamp -> [keys])
    

답변:


6

캐시에서 만료 된 항목을 삭제하는 문제는 가비지 수집 과 거의 동일 하며 참조 계산의 전체 복잡성을 뺀 것입니다.

Nasza-Klasa의 사람들은 다음과 같이 Memcache에 O (1) 알고리즘을 제안했습니다.

많은 사람들이 어떤 이유로 인해 만료 된 항목을 해제하는 것이 O (1)에서 수행 될 수 없거나 심지어 Omega (N) 작업이 필요하다고 생각하는 것 같습니다. 힙 또는 다른 우선 순위 큐 데이터 구조를 사용하면 분명히 O (log N)을 줄 수 있지만 아래 패치는 O (1)을 목표로합니다. 이는 초당 1 개의 버킷을 보유하고 만료 시간을 확인하여 각 항목을 적절한 버킷에 배치함으로써 달성됩니다. 그런 다음 매 초마다 다음 버킷에서 요소를 해제합니다. 이것은 명백히 O (1) 상각 된 시간이지만, 당신은 같은 순간에 만료되는 많은 요소를 가질 수 있으므로 패치는 한 요청 당 수행하고자하는 작업 수에 대한 고정 된 제한을 제공합니다. 가비지 수집을보다 원활하게 수행 할 수 있습니다.

첨부 된 코드와 함께 전체 제안을 참조하십시오 .


감사. 또한 "버킷"솔루션을 한 가지 방법으로 생각했습니다. 또한 "버킷에 너무 많은 항목"에 문제가 없습니다. "마지막에 가져 오지 않은 버킷을 가져 와서 완료되면 다시 가져옵니다"알고리즘을 사용할 수 있기 때문입니다.
Kostiantyn Rybnikov

@k_bx : 그렇기 때문에 이중 연결 목록을 제안하므로 이전 버킷으로 돌아갈 수 있습니다.
vartec

버킷이 초와 같으면 링크 된 목록이 전혀 필요하지 않습니다. 이전으로 가려면 키를 줄이십시오 :)
Kostiantyn Rybnikov

@k_bx : 키를 얼마만큼 줄입니까? 일초? 이전에 완전히 비우지 않은 버킷이 5 분 전에 있었다면 어떻게합니까? 1 초에 300 번씩 감소?
vartec

첫 번째 서버 시작시 current_expire_bucket이라는 변수를 어떤 값으로 초기화합니다. 그런 다음 current_expire_bucket에서 시작하여 정리를 실행하고 현재 초를 종료합니다. 정리가 끝나면 잠깐 동안 잠을 자게됩니다. 서버가 중지되면 동일한 "만료 버킷"을 다시 통과하게되지만 서버 중지시에만 발생합니다.
Kostiantyn Rybnikov

7

키-값 스토리지가 너무 커서 모든 kv 쌍을 반복하여 만료 될 수있는 것을 찾기에는 너무 큽니다. 또한 각 읽기 액세스가 만료 타임 스탬프를 새로 고치므로 일정 시간 동안 액세스하지 않은 항목 만 만료된다고 가정합니다.

문제는 정리가 완료 될 때마다 만료 될 수있는 모든 레코드를 효율적으로 찾고 모든 읽기 액세스에서 만료 타임 스탬프를 효율적으로 새로 고치는 것입니다 (따라서 만료에 사용 된 구조에서 키를 찾아야 함).

내 제안 : expiry_timestamps를 버킷으로 그룹화하십시오. 예를 들어 품목이 8 시간 동안 지속되는 경우 시간당 하나의 버킷을 만듭니다. 이러한 버킷은 연결된 목록으로 유지됩니다. 만료가 발생하면 첫 번째 버킷이 비워지고 목록이 줄어 듭니다. 버킷 수는 수명 / 정리 간격입니다. 각 버킷에는 만료되어야하는 모든 키의 hashSet이 포함되어 있습니다. 해시 셋의 모든 키에 대한 반복은 충분히 효율적입니다.

읽기 액세스 중에 프로그램은 현재 키가있는 버킷과 현재 속한 버킷을 확인합니다. 대부분의 경우 동일한 버킷이므로 추가 조치가 필요하지 않습니다. 그렇지 않으면 이전 버킷에서 키를 제거하고 (해시 세트에서 제거하는 것이 효율적 임) 새 버킷에 삽입하십시오.

   +--------------+   +--------------+   +--------------+
-->+ Expiry 08:00 +-->+ Expiry 09:00 +-->+ Expiry 10:00 +
   | KeySet       |   | KeySet       |   | KeySet       |
   +--------------+   +--------------+   +--------------+
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.