Soalan dan bila ia diguna pakai
Laksanakan cache dalam ingatan di mana setiap kunci mempunyai nilai dan masa tamat tempoh. get tidak boleh sekali-kali mengembalikan nilai yang telah tamat tempoh. Terangkan jam, sempadan, pembersihan, kapasiti, keserempakan dan kerumitan.
Amazon menyenaraikan struktur data, algoritma dan pengekodan antara topik temu duga pembangunan perisian serta menekankan penerapan pengetahuan. Redis mendokumenkan semantik TTL dan EXPIRE, termasuk baki jangka hayat dan kejituan. Tidak seperti LRU atau LFU, masalah ini bertumpu pada semantik masa dan pembersihan tamat tempoh.
Perkara yang dinilai oleh penemu duga
Penemu duga mencari unit TTL dan jam yang eksplisit, sempadan tamat tempoh yang betul, pilihan pembersihan, ketekalan serempak, tingkah laku kapasiti, serta kerumitan masa dan ruang.
Soalan untuk dijelaskan sebelum menjawab
- Adakah TTL dalam saat atau milisaat? Adakah sifar tamat tempoh serta-merta?
- Adakah jam tersebut monotonik?
- Adakah entri yang tamat tempoh mesti dialih keluar serta-merta?
- Adakah terdapat kapasiti maksimum atau dasar LRU?
- Bagaimanakah set, get dan pembersihan disegerakkan?
- Adakah mengemas kini kunci akan menetapkan semula TTL?
- Adakah ketahanan (persistence) atau perkongsian merentas proses diperlukan?
- Adakah kerja pembersihan mesti dibatasi (bounded)?
Kerangka jawapan 30 saat
“Saya menyimpan nilai setiap kunci dan expiresAt mutlak dalam jadual cincangan. get memeriksa jam monotonik terlebih dahulu; jika now adalah pada atau selepas expiresAt, ia memadam dan mengembalikan miss. set menggantikan nilai dan TTL. Versi asas menggunakan pembersihan malas (lazy) dengan get O(1) terlunas dan ruang O(n). Min-heap atau imbasan terhad mengendalikan entri sejuk (cold). Kunci (locks) atau pembahagian (sharding) melindungi kemas kini cincangan dan pembersihan. Ujian merangkumi TTL sifar, kesaksamaan, pembaharuan (refresh) dan keadaan perlumbaan (race conditions).”
Jawapan mendalam, langkah demi langkah
Langkah 1: Tentukan item
Simpan value dan expiresAt; tiada TTL boleh menggunakan infiniti. Gunakan satu peraturan, now >= expiresAt, pada setiap laluan.
Langkah 2: Laksanakan get dan set
get mengembalikan miss untuk kunci yang tidak wujud. Bagi kunci yang tamat tempoh, ia memadamkannya sebelum mengembalikan miss. set mengira tamat tempoh mutlak dan mengemas kini sebarang indeks pembersihan.
Langkah 3: Pilih jam
Gunakan jam monotonik untuk masa yang berlalu supaya pelarasan jam dinding (wall-clock) tidak dapat melanjutkan TTL. Reka bentuk ketahanan dan merentas proses memerlukan asas masa dan kejituan yang eksplisit.
Langkah 4: Pilih pembersihan
Pembersihan malas adalah mudah tetapi kunci sejuk boleh menggunakan ingatan. Min-heap mengeluarkan tamat tempoh terawal dahulu; imbasan berkala mengehadkan kerja tetapi mungkin melambatkan pemadaman.
| Strategi | Faedah | Kos |
|---|---|---|
| Malas (Lazy) | Bacaan mudah dan pantas | Kunci sejuk kekal |
| Min-heap | Tamat tempoh terawal dahulu | Kemas kini menghasilkan entri lapuk dalam heap |
| Imbasan berkala | Kerja terhad bagi setiap laluan | Pemadaman tertangguh |
Langkah 5: Jadikan kemas kini selamat secara serempak
set, get, delete dan pembersihan mesti bersetuju dengan nilai dan tamat tempoh yang sama. Gunakan kunci global, kunci baca-tulis atau kunci terpecah (sharded locks). Kemas kini heap dan jadual mesti atomik bersama-sama.
Langkah 6: Asingkan kapasiti daripada TTL
TTL tidak mentakrifkan kapasiti. Pada hadnya, pilih LRU, pengusiran rawak atau tolak penulisan. Jejaki pengusiran secara berasingan daripada tamat tempoh.
Langkah 7: Nyatakan kerumitan dan kod pseudo
Sempadan teras ialah:
get(key):
item = table[key]
if item is absent: return MISS
if clock.now() >= item.expiresAt:
delete table[key]
return MISS
return item.valueget dan set malas adalah O(1) terlunas, ruang O(n). Pop pembersihan heap menelan kos O(log n).
Langkah 8: Uji sempadan
Uji TTL sifar, kesaksamaan, pembaharuan, pembersihan berulang, perubahan jam, get/set serempak, pengusiran kapasiti dan kegagalan yang disuntik. Suntik jam daripada menggunakan sleep dalam ujian.
Contoh jawapan berkualiti tinggi
“Saya mentakrifkan CacheItem(value, expiresAt) dan menyimpan item dalam jadual cincangan. set menukar TTL kepada tamat tempoh mutlak; sifar bermakna tamat tempoh serta-merta. get memeriksa jam monotonik dan memadamkannya sebelum mengembalikan miss.
Versi pertama menggunakan pembersihan malas, dengan bacaan dan penulisan O(1) terlunas. Bagi banyak kunci sejuk, saya menambah min-heap. Setiap rekod heap mempunyai versi; pembersihan mengesahkan versi sebelum memadam, jadi rekod lama tidak boleh mengalih keluar nilai yang telah dibaharui. Kunci terpecah (sharded locks) melindungi jadual dan heap. Ujian merangkumi kesaksamaan, pembaharuan, pembersihan berulang, perlumbaan dan pengusiran kapasiti.”
Kesilapan biasa
- Membiarkan TTL sifar dan kesaksamaan tidak ditakrifkan.
- Menggunakan masa jam dinding untuk TTL yang berlalu.
- Membiarkan get mengembalikan nilai yang telah tamat tempoh sehingga pekerja latar belakang berjalan.
- Mengabaikan rekod heap yang lapuk selepas pembaharuan.
- Menganggap TTL sebagai dasar kapasiti LRU.
- Memegang kunci global semasa pembersihan yang panjang.
- Menguji hanya hit dan miss, bukan keadaan perlumbaan pada sempadan.
- Meninggalkan kejituan dan kerumitan.
Soalan susulan dan cara menjawab
Soalan susulan 1: Mengapa tamat tempoh mutlak?
Ia memberikan satu peraturan perbandingan dan membolehkan pembersihan menyusun entri mengikut tamat tempoh. Pembaharuan menggantikan expiresAt.
Soalan susulan 2: Bagaimana jika jam dinding bergerak ke belakang?
Gunakan jam monotonik untuk masa yang berlalu. Cache yang tahan lama atau teragih memerlukan asas masa yang didokumenkan.
Soalan susulan 3: Tiada benang latar belakang, tetapi banyak kunci sejuk?
Laksanakan pembersihan terhad semasa bacaan atau penulisan, seperti bilangan pop heap yang tetap bagi setiap operasi, dan terima kelewatan pemadaman yang terbatas.
Soalan susulan 4: Bagaimanakah anda mengekalkan ketekalan heap dan jadual?
Gunakan satu kunci atau operasi atomik dan satu versi pada rekod heap. Padam hanya apabila versi masih sepadan.
Soalan susulan 5: Apakah yang berlaku apabila kapasiti penuh?
Alih keluar entri yang telah tamat tempoh terlebih dahulu, kemudian gunakan dasar pengusiran yang didokumenkan pada entri yang masih aktif dan jejaki sebabnya.
Soalan susulan 6: Bagaimanakah pelbagai proses berkongsi cache ini?
Cache dalam ingatan adalah untuk proses tunggal. Penggunaan merentas proses memerlukan storan luaran atau teragih dengan semantik TTL, jam dan kegagalan yang atomik.