Apa algoritme untuk item yang kedaluwarsa dalam penyimpanan nilai kunci?

10

Saya sedang memikirkan bagaimana penyimpanan nilai kunci saat ini menerapkan "tanggal kedaluwarsa" untuk item. Saat ini saya memiliki 2 varian untuk itu dalam pikiran saya:

  1. mereka tidak melakukan apa-apa (menyimpan data kadaluarsa), dan hanya memeriksa ketika Anda melakukannya, misalnya, DAPATKAN oleh beberapa kunci. Masalahnya di sini adalah bahwa jika Anda terbatas dalam memori, item kadaluarsa tidak akan dihapus.
  2. mereka menyimpan struktur data tambahan untuk bisa "paling awal untuk kedaluwarsa". Saya melihat hal itu dapat dilakukan dengan sesuatu seperti ini:

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

Jawaban:

6

Masalah menghapus entri yang sudah kadaluwarsa dalam cache sangat mirip dengan pengumpulan sampah , dikurangi seluruh kerumitan penghitungan referensi.

Orang-orang di Nasza-Klasa telah mengusulkan algoritma O (1) untuk Memcache sebagai berikut:

Tampaknya banyak orang percaya karena alasan tertentu bahwa membebaskan entri yang kadaluwarsa tidak dapat dilakukan di O (1), atau bahkan itu membutuhkan operasi Omega (N). Menggunakan heap, atau struktur data antrian prioritas lainnya jelas dapat memberi Anda O (log N), tetapi tambalan di bawah ini bertujuan O (1). Ini dicapai dengan memiliki satu ember untuk setiap detik, dan dengan menempatkan setiap entri dalam ember yang tepat dengan melihat waktu kedaluwarsa. Kemudian pada setiap detik kita hanya membebaskan elemen dari ember berikutnya. Ini jelas O (1) waktu diamortisasi, tetapi bisa terjadi bahwa Anda memiliki banyak elemen yang kedaluwarsa pada saat yang sama, sehingga tambalan menawarkan batas tetap untuk jumlah operasi yang ingin Anda lakukan per satu permintaan, untuk membuat pengumpulan sampah berjalan lebih lancar.

Lihat seluruh proposal dengan kode terlampir .

vartec
sumber
Terima kasih. Saya juga memikirkan solusi "ember" sebagai satu cara. Juga tidak ada masalah dengan "terlalu banyak item dalam ember" karena Anda dapat menggunakan algoritme "ambil ember yang tidak Anda ambil terakhir kali, dan kembalilah setelah selesai".
Kostiantyn Rybnikov
@ k_bx: itu sebabnya mereka mengusulkan daftar ditautkan ganda, sehingga Anda dapat kembali ke keranjang sebelumnya.
vartec
Jika bucket seperti detik, maka Anda tidak perlu daftar yang ditautkan sama sekali. Untuk pergi sebelumnya, Anda hanya mengurangi kunci :)
Kostiantyn Rybnikov
@ k_bx: kurangi key sebanyak berapa? satu detik? bagaimana jika ember sebelumnya tidak sepenuhnya dikosongkan adalah 5 menit yang lalu? menurun dengan langkah 1s 300 kali?
vartec
Pada permulaan server pertama, Anda init variabel yang disebut current_expire_bucket ke beberapa nilai. Kemudian, Anda menjalankan pembersihan mulai dari current_expire_bucket, mengakhiri detik saat ini. Setelah pembersihan berakhir, Anda tidur sebentar. Jika server berhenti, Anda akan melalui "masa berakhir ember" yang sama lagi, ya, tetapi seharusnya hanya terjadi pada server yang berhenti.
Kostiantyn Rybnikov
7

Saya menganggap penyimpanan kunci-nilai terlalu besar untuk hanya mengulangi semua pasangan kv untuk mencari tahu mana yang dapat kedaluwarsa. Saya juga berasumsi bahwa setiap akses baca menyegarkan stempel waktu kedaluwarsa, jadi hanya item yang belum diakses selama beberapa waktu yang kedaluwarsa.

Tantangannya adalah untuk secara efisien menemukan semua catatan yang dapat kedaluwarsa (setiap kali pembersihan harus dilakukan), tetapi juga secara efisien menyegarkan cap waktu kedaluwarsa pada setiap akses baca (jadi kita harus menemukan kunci dalam struktur yang digunakan untuk kedaluwarsa).

Proposal saya: kelompok expiry_timestamps ke dalam ember; misalnya, jika barang hidup selama 8 jam, buat satu ember per jam. Ember itu disimpan dalam daftar tertaut; ketika kedaluwarsa terjadi, ember pertama dikosongkan dan daftar berkurang. Jumlah bucket adalah rentang umur / pembersihan. Setiap ember berisi hashSet dari semua kunci yang harus kadaluwarsa. Iterasi atas semua kunci dalam hashset cukup efisien.

Selama akses baca, program memeriksa ember mana yang saat ini menjadi kunci dan ember mana yang sekarang menjadi miliknya. Dalam kebanyakan kasus, ini adalah ember yang sama, jadi tidak ada tindakan lebih lanjut yang diperlukan. Kalau tidak, hapus kunci dari ember lama (menghapus dari hash set efisien) dan masukkan ke dalam ember baru.

   +--------------+   +--------------+   +--------------+
-->+ Expiry 08:00 +-->+ Expiry 09:00 +-->+ Expiry 10:00 +
   | KeySet       |   | KeySet       |   | KeySet       |
   +--------------+   +--------------+   +--------------+
pengguna281377
sumber