Redis
 sql >> Teknologi Basis Data >  >> NoSQL >> Redis

Redis `SCAN`:bagaimana menjaga keseimbangan antara kunci baru yang mungkin cocok dan memastikan hasil akhirnya dalam waktu yang wajar?

Pertama beberapa konteks, solusi di akhir :

Dari perintah SCAN> Jaminan penghentian

Algoritme SCAN dijamin untuk berhenti hanya jika ukuran koleksi yang diulang tetap dibatasi pada ukuran maksimum yang diberikan, jika tidak, mengulangi koleksi yang selalu bertambah dapat mengakibatkan SCAN tidak pernah mengakhiri iterasi penuh.

Ini mudah dilihat secara intuitif:jika koleksi bertambah, ada lebih banyak dan lebih banyak pekerjaan yang harus dilakukan untuk mengunjungi semua elemen yang mungkin, dan kemampuan untuk menghentikan iterasi bergantung pada jumlah panggilan ke SCAN dan nilai opsi COUNT dibandingkan dengan rate di yang koleksinya bertambah.

Tetapi dalam opsi COUNT dikatakan:

Penting:tidak perlu menggunakan nilai COUNT yang sama untuk setiap iterasi. Penelepon bebas mengubah hitungan dari satu iterasi ke iterasi lainnya sesuai kebutuhan, selama kursor yang dilewatkan pada panggilan berikutnya adalah yang diperoleh pada panggilan sebelumnya ke perintah.

Penting untuk diingat, dari jaminan Pindai:

  • Elemen tertentu dapat dikembalikan beberapa kali. Terserah aplikasi untuk menangani kasus elemen duplikat, misalnya hanya menggunakan elemen yang dikembalikan untuk melakukan operasi yang aman ketika diterapkan kembali beberapa kali.
  • Elemen yang tidak selalu ada dalam koleksi selama iterasi penuh, dapat dikembalikan atau tidak:tidak ditentukan.

Kunci solusi ada di kursor itu sendiri. Lihat Memahami kursor SCAN Redis. Adalah kemungkinan untuk menyimpulkan persentase kemajuan pemindaian Anda karena kursor benar-benar merupakan bit-dibalik indeks ke ukuran tabel.

Menggunakan DBSIZE atau INFO keyspace perintah Anda bisa mendapatkan berapa banyak kunci yang Anda miliki setiap saat:

> DBSIZE
(integer) 200032
> info keyspace
# Keyspace
db0:keys=200032,expires=0,avg_ttl=0

Sumber informasi lain adalah DEBUG htstats index yang tidak berdokumen , hanya untuk merasakan:

> DEBUG htstats 0
[Dictionary HT]
Hash table 0 stats (main hash table):
 table size: 262144
 number of elements: 200032
 different slots: 139805
 max chain length: 8
 avg chain length (counted): 1.43
 avg chain length (computed): 1.43
 Chain length distribution:
   0: 122339 (46.67%)
   1: 93163 (35.54%)
   2: 35502 (13.54%)
   3: 9071 (3.46%)
   4: 1754 (0.67%)
   5: 264 (0.10%)
   6: 43 (0.02%)
   7: 6 (0.00%)
   8: 2 (0.00%)
[Expires HT]
No stats available for empty dictionaries

Ukuran tabel adalah pangkat 2 mengikuti jumlah kunci Anda:Kunci:200032 => Ukuran tabel:262144

Solusinya:

Kami akan menghitung COUNT yang diinginkan argumen untuk setiap pemindaian.

Katakanlah Anda akan memanggil SCAN dengan frekuensi (F dalam Hz) dari 10 Hz (setiap 100 ms) dan Anda ingin menyelesaikannya dalam 5 detik (T dalam s). Jadi Anda ingin ini selesai di N = F*T panggilan, N = 50 dalam contoh ini.

Sebelum pemindaian pertama Anda, Anda tahu kemajuan Anda saat ini adalah 0, jadi persentase yang tersisa adalah RP = 1 (100%).

Sebelum setiap SCAN panggilan (atau setiap jumlah panggilan yang ingin Anda sesuaikan COUNT Anda jika Anda ingin menghemat Waktu Pulang Pergi (RTT) dari DBSIZE panggilan), Anda memanggil DBSIZE untuk mendapatkan jumlah kunci K .

Anda akan menggunakan COUNT = K*RP/N

Untuk panggilan pertama, ini COUNT = 200032*1/50 = 4000 .

Untuk panggilan lainnya, Anda perlu menghitung RP = 1 - ReversedCursor/NextPowerOfTwo(K) .

Misalnya, Anda sudah melakukan 20 panggilan, jadi sekarang N = 30 (jumlah panggilan yang tersisa). Anda menelepon DBSIZE dan dapatkan K = 281569 . Ini berarti NextPowerOfTwo(K) = 524288 , ini adalah 2^19.

Kursor Anda berikutnya adalah 14509 dalam desimal =000011100010101101 dalam biner. Karena ukuran tabel adalah 2^19, kami merepresentasikannya dengan 18 bit.

Anda membalikkan bit dan mendapatkan 101101010001110000 dalam biner =185456 dalam desimal. Ini berarti kita telah membahas 185456 dari 524288. Dan:

RP = 1 - ReversedCursor/NextPowerOfTwo(K) = 1 - 185456 / 524288 = 0.65 or 65%

Jadi Anda harus menyesuaikan:

COUNT = K*RP/N = 281569 * 0.65 / 30 = 6100

Jadi di SCAN Anda berikutnya panggilan Anda menggunakan 6100 . Masuk akal itu meningkat karena:

  • Jumlah kunci telah meningkat dari 200032 menjadi 281569.
  • Meskipun kami hanya memiliki 60% dari perkiraan awal panggilan yang tersisa, kemajuannya terlambat karena 65% dari ruang kunci menunggu untuk dipindai.

Semua ini dengan asumsi Anda mendapatkan semua kunci. Jika Anda mencocokkan pola , Anda perlu menggunakan masa lalu untuk memperkirakan jumlah kunci yang tersisa untuk ditemukan. Kami menambahkan sebagai faktor PM (persen kecocokan) ke COUNT perhitungan.

COUNT = PM * K*RP/N

PM = keysFound / ( K * ReversedCursor/NextPowerOfTwo(K))

Jika setelah 20 panggilan, Anda hanya menemukan keysFound = 2000 kunci, lalu:

PM = 2000 / ( 281569 * 185456 / 524288) = 0.02

Ini berarti hanya 2% dari kunci yang cocok dengan pola kita sejauh ini, jadi

COUNT = PM * K*RP/N = 0.02 * 6100 = 122

Algoritme ini mungkin dapat ditingkatkan, tetapi Anda mengerti.

Pastikan untuk menjalankan beberapa tolok ukur pada COUNT nomor yang akan Anda gunakan untuk memulai, untuk mengukur berapa milidetik SCAN Anda menerima, karena Anda mungkin perlu memoderasi ekspektasi Anda tentang berapa banyak panggilan yang Anda butuhkan (N ) untuk melakukan ini dalam waktu yang wajar tanpa memblokir server, dan sesuaikan F . Anda dan T sesuai.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Docker gagal memulai Rails

  2. Bagaimana cara mengubah antara database redis?

  3. Laravel - Hapus semua kunci cache / redis yang berisi string tertentu

  4. Memanggil Redis zunionstore dari Lua dengan variabel KEYS

  5. Apa perbedaan utama antara Redis dan Membase?