Dalam serangkaian beberapa artikel, saya akan menyajikan terjemahan adaptasi saya dari bagian
Praktik Terbaik Redis dari situs web resmi Redis Labs.
Redis dapat digunakan dalam banyak cara, namun, ada beberapa pola yang dapat digunakan untuk memecahkan masalah umum. Kami telah mengumpulkan kumpulan pola umum yang kami anggap
praktik terbaik untuk menyelesaikan masalah ini. Koleksi ini tidak lengkap dan tampaknya bukan satu-satunya cara untuk menggunakan Redis, tetapi kami berharap ini akan berfungsi sebagai titik awal untuk menyelesaikan masalah menggunakan Redis.
Kami membagi panduan ini ke praktik terbaik menjadi beberapa bab dan sub-bab sesuai kebutuhan (Catatan oleh penerjemah: beberapa sub-bab pendek, jadi saya akan menggabungkannya menjadi satu):
- dalam bab "Pola Pengindeksan," kita akan melihat cara untuk melampaui akses nilai kunci yang biasa dengan Redis. Ini termasuk cara untuk menggunakan pola utama secara cerdas menggunakan berbagai tipe data Redis untuk membantu tidak hanya menemukan data, tetapi juga mengurangi kompleksitas akses;
- Bab Pola Interaksi berfokus pada pola Redis yang memindahkan data melintasi infrastruktur. Dalam hal ini, Redis tidak bertindak sebagai repositori, tetapi lebih sebagai panduan untuk data;
- bab "Pola Penyimpanan Data" menjelaskan metode untuk menyimpan representasi data yang kompleks di Redis. Kami akan menghitung skrip dokumen kompleks yang dapat digeneralisasi menjadi cara yang sederhana dan kompleks;
- pola mengenai data yang disimpan sementara dijelaskan dalam bab "Pola Rangkaian Waktu";
- batas kecepatan sering digunakan dalam Redis. Dalam bab "Pola dasar pembatasan kecepatan" kita akan beralih ke dasar-dasar kasus penggunaannya;
- Filter Bloom telah lama dilihat dalam Redis, dan dalam bab "Pola dengan Filter Bloom" kita melihat struktur data probabilistik dan bagaimana mereka berbeda dari analog yang luar biasa;
- konter adalah penerimaan yang sangat dalam. Dalam bab terpisah, kami mengeksplorasi cara menghitung aktivitas dan elemen unik dengan cara komputasi yang efisien;
- akhirnya, kita akan berbicara tentang bagaimana memanfaatkan Lua untuk membuat Redis berbuat lebih banyak dengan lebih sedikit.
Panduan ini tidak konsisten, jadi Anda bisa memulainya dengan bab apa saja. Anda juga dapat menggunakan navigasi di awal setiap posting untuk menemukan sesuatu yang cocok.
Pola pengindeksan
Secara konseptual, Redis adalah basis data yang didasarkan pada paradigma kunci / nilai, ketika setiap bagian data dikaitkan dengan kunci tertentu. Jika Anda ingin mendapatkan data untuk sesuatu selain kunci, Anda perlu menerapkan indeks yang menggunakan salah satu dari banyak tipe data yang tersedia di Redis.
Pengindeksan di Redis sangat berbeda dari apa yang disajikan dalam database lain, jadi skenario dan data penggunaan Anda sendiri akan menentukan strategi pengindeksan terbaik. Dalam bab ini, kita akan melihat beberapa strategi pengambilan data umum selain pengambilan kunci / nilai sederhana:
- set diurutkan sebagai indeks;
- indeks leksikografis;
- indeks geospasial;
- Geolokasi IP
- pencarian teks lengkap;
- indeks terpartisi.
Set yang diurutkan sebagai indeks
Kumpulan yang disortir (ZSET) adalah tipe data standar dalam Redis yang mewakili banyak objek unik (pengulangan tidak disimpan), di mana setiap objek ditugaskan ke nomor (disebut "hitungan"), yang bertindak sebagai mekanisme penyortiran alami. Dan meskipun objek tidak dapat diulang, beberapa objek dapat memiliki jumlah yang sama. Dengan kompleksitas waktu yang relatif rendah untuk menambah, menghapus, dan mendapatkan rentang nilai (berdasarkan peringkat atau jumlah), set yang diurutkan cukup cocok untuk dijadikan indeks. Sebagai contoh, ambillah negara-negara di dunia, yang diperingkat berdasarkan populasi:
> ZADD countries-by-pop 1409517397 china > ZADD countries-by-pop 146573899 russia > ZADD countries-by-pop 81456724 germany > ZADD countries-by-pop 333016381 usa > ZADD countries-by-pop 1 mars > ZADD countries-by-pop 37290812 afghanistan > ZADD countries-by-pop 1388350202 india
Mendapatkan 5 negara teratas akan mudah:
> ZRANGE countries-by-pop 0 4 1) "mars" 2) "afghanistan" 3) "germany" 4) "russia" 5) "india"
Dan membuat negara-negara dengan populasi antara 10.000.000 dan 1.000.000:
> ZRANGEBYSCORE countries-by-pop 10000000 1000000000 1) "afghanistan" 2) "germany" 3) "russia"
Anda dapat membuat beberapa indeks untuk menunjukkan berbagai cara penyortiran data. Dalam contoh kita, kita dapat menggunakan objek yang sama, tetapi alih-alih jumlah orang, ambil kepadatan populasi, ukuran geografis, jumlah pengguna Internet, dll. Ini akan membuat indeks kinerja tinggi untuk berbagai aspek. Selain itu, dengan membagi nama objek dengan data tentangnya disimpan baik di Redis (di Hash, misalnya) atau di penyimpanan data lain, proses sekunder dapat memperoleh informasi tambahan tentang setiap elemen yang diperlukan.
Indeks leksikografis
Kumpulan yang disortir (ZSET) dengan pemeringkatan berdasarkan hitungan memiliki satu properti menarik yang dapat digunakan untuk membuat mekanisme penyortiran alfabet kasar. Properti adalah bahwa objek dengan skor yang sama dapat dikembalikan dalam urutan leksikografis dan dengan nilai batas. Ambil data berikut:
> ZADD animal-list 0 bison 0 boa 0 dog 0 emu 0 falcon 0 alligator 0 chipmunk
Perintah ini akan menambahkan beberapa hewan ke kunci daftar hewan. Setiap objek memiliki skor 0. Setelah menjalankan perintah ZRANGE dengan argumen 0 dan -1, kita melihat urutan yang aneh:
> ZRANGE animal-list 0 -1 1) "alligator" 2) "bison" 3) "boa" 4) "chipmunk" 5) "dog" 6) "emu" 7) "falcon"
Meskipun elemen tidak ditambahkan secara alfabetis, mereka dikembalikan diurutkan berdasarkan abjad. Urutan ini adalah hasil dari perbandingan string biner, byte-by-bit. Ini berarti bahwa karakter ASCII akan dikembalikan dalam urutan abjad. Ini menyarankan hal-hal berikut:
- karakter dalam huruf kecil dan huruf besar tidak akan dikenali sebagai sama;
- karakter multibyte tidak akan diurutkan seperti yang diharapkan.
Redis juga menyediakan beberapa fitur canggih untuk mempersempit pencarian leksikografis. Misalnya, kami ingin mengembalikan hewan yang dimulai dengan
b dan diakhiri dengan
e . Kita dapat menggunakan perintah berikut:
> ZRANGEBYLEX animal-list [b (f 1) "bison" 2) "boa" 3) "chipmunk" 4) "dog" 5) "emu"
Argumen
(f bisa sedikit membingungkan. Ini adalah poin penting, karena Redis tidak tahu tentang pemahaman literal huruf-huruf alfabet. Ini berarti bahwa kita harus memperhitungkan bahwa segala sesuatu yang dimulai dengan
e akan selalu berdiri sebelum segala sesuatu dimulai dengan
f , terlepas dari huruf-huruf berikutnya. Catatan lain adalah bahwa kurung siku menunjukkan pencarian dengan penyertaan, dan kurung bundar menunjukkan pencarian tanpa penyertaan. Dalam kasus kami, jika kami kueri dengan
b , ini akan dimasukkan dalam daftar, sementara
f tidak akan muncul dalam pemilihan. Jika Anda perlu semua elemen sampai akhir, gunakan dikodekan simbol terakhir (255 atau 0xFF):
> ZRANGEBYLEX animal-list [c "[\xff" 1) "chipmunk" 2) "dog" 3) "emu" 4) "falcon"
Perintah ini juga dapat dibatasi, sehingga memastikan pagination:
> ZRANGEBYLEX animal-list [b (f LIMIT 0 2 1) "bison" 2) "boa" > ZRANGEBYLEX animal-list [b (f LIMIT 2 2 1) "chipmunk" 2) "dog"
Satu-satunya jebakan adalah bahwa kompleksitas waktu akan meningkat ketika indentasi meningkat (argumen pertama setelah LIMIT). Oleh karena itu, jika Anda memiliki 1 juta objek dan Anda mencoba untuk mendapatkan dua yang terakhir, ini akan membutuhkan perayapan hanya satu juta.
Indeks Geospasial
Redis memiliki beberapa tim pengindeksan geospasial (tim GEO), tetapi tidak seperti tim lain, tim ini tidak memiliki tipe data sendiri. Perintah-perintah ini sebenarnya melengkapi jenis set yang diurutkan. Ini dicapai dengan menyandikan lintang dan bujur ke dalam skor set yang diurutkan menggunakan algoritma geohash.
Menambahkan elemen ke geo-indeks itu mudah. Misalkan Anda melacak sekelompok mobil yang berkendara di sepanjang jalan. Kami menyebut set mobil ini hanya "mobil". Katakanlah mesin khusus Anda dapat diidentifikasi sebagai objek "mobil saya" (kami menggunakan istilah "objek" karena geo-indeks hanyalah bentuk set). Untuk menambahkan mesin ke set, kita dapat menjalankan perintah:
> GEOADD cars -115.17087 36.12306 my-car
Argumen pertama adalah set yang kita tambahkan, yang kedua adalah garis lintang, yang ketiga adalah garis bujur, dan yang keempat adalah nama objek.
Untuk memperbarui lokasi mesin, Anda hanya perlu menjalankan perintah lagi dengan koordinat baru. Ini berfungsi karena geo-indeks hanyalah set di mana elemen duplikat tidak diperbolehkan.
> GEOADD cars -115.17172 36.12196 my-car
Tambahkan mobil kedua ke "mobil". Kali ini Volodya membimbingnya:
> GEOADD cars -115.171971 36.120609 volodias-car
Melihat koordinat, Anda dapat mengatakan bahwa mobil-mobil ini cukup dekat satu sama lain, tetapi berapa banyak? Anda dapat mendefinisikan ini dengan perintah GEODIST:
> GEODIST cars my-car volodias-car "151.9653"
Ini berarti bahwa dua kendaraan berjarak sekitar 151 meter. Anda juga dapat menghitung di unit lain:
> GEODIST cars my-car robins-car ft "498.5737"
Ini mengembalikan jarak yang sama dalam beberapa langkah. Anda juga dapat menggunakan mil (ml) atau kilometer (km).
Sekarang mari kita lihat siapa yang berada dalam radius titik tertentu:
> GEORADIUS cars -115.17258 36.11996 100 m 1) "volodias-car"
Ini mengembalikan semua orang dalam radius 100 meter di sekitar titik yang ditentukan. Anda juga dapat meminta semua orang dalam radius objek apa pun dari set:
> GEORADIUSBYMEMBER cars volodias-car 152 m 1) "volodias-car" 2) "my-car"
Kami juga dapat mengaktifkan jarak dengan menambahkan argumen WITHDIST opsional (ini berfungsi untuk GEORADIUS atau GEORADIUSBYMEMBER):
> GEORADIUSBYMEMBER cars volodias-car 152 m WITHDIST 1) 1) "volodias-car" 2) "0.0000" 2) 1) "my-car" 2) "151.9653"
Argumen opsional lain untuk GEORADIUS dan GEORADIUSBYMEMBER adalah WITHCOORD, yang mengembalikan koordinat setiap objek. WITHDIST dan WITHCOORD dapat digunakan bersama atau secara terpisah:
> GEORADIUSBYMEMBER cars volodias-car 152 m WITHDIST WITHCOORD 1) 1) "volodias-car" 2) "0.0000" 3) 1) "-115.17197102308273315" 2) "36.12060917648089031" 2) 1) "my-car" 2) "151.9653" 3) 1) "-115.17171889543533325" 2) "36.12196018285882104"
Karena indeks geospasial hanyalah alternatif untuk set yang disortir, beberapa operator yang terakhir dapat digunakan. Jika kita ingin menghapus "mobil saya" dari set "mobil", kita dapat menggunakan perintah dari set ZREM yang diurutkan:
> ZREM cars my-car
Redis menyediakan seperangkat alat yang kaya untuk bekerja dengan geospasial, dan dalam bagian ini kami hanya memeriksa yang dasar.
Geolokasi IP
Menemukan lokasi sebenarnya dari layanan yang terhubung dapat sangat berguna. Tabel geolokasi IP biasanya cukup besar dan sulit dikelola secara efektif. Kita dapat menggunakan set diurutkan untuk mengimplementasikan layanan geolokasi IP cepat dan efisien.
IPv4 paling sering dirujuk dalam notasi desimal (74.125.43.99, misalnya). Namun, layanan jaringan melihat alamat yang sama ini sebagai nomor 32-bit, dengan setiap byte mewakili satu dari empat angka dalam bentuk desimal. Contoh di atas adalah 0x4A7D2B63 dalam heksadesimal atau 1249717091 dalam desimal.
Dataset geolokasi IP tersedia secara luas dan biasanya berbentuk tabel sederhana dengan tiga kolom (mulai, akhir, lokasi). Awal dan akhir adalah representasi desimal dari IPv4. Di Redis, kita dapat mengadaptasi set yang diurutkan ke format ini, karena tidak ada "lubang" dalam rentang IP, oleh karena itu, kita dapat dengan aman berasumsi bahwa akhir dari satu rentang adalah awal dari yang lain.
Untuk contoh sederhana, tambahkan beberapa rentang ke set diurutkan:
> ZADD ip-loc 1249716479 us:1 > ZADD ip-loc 1249716735 taiwan:1 > ZADD ip-loc 1249717759 us:2 > ZADD ip-loc 1249718015 finland:1
Argumen pertama adalah kunci dari himpunan kami, yang kedua adalah representasi desimal dari akhir rentang IP, dan yang terakhir adalah objek itu sendiri. Perhatikan bahwa objek yang ditetapkan memiliki angka setelah titik dua. Ini hanya untuk memudahkan contoh. Tabel IP asli memiliki pengidentifikasi unik untuk setiap rentang (dan informasi tambahan lebih dari sekadar nama negara).
Untuk kueri tabel untuk alamat IP yang diberikan, kita bisa menggunakan perintah ZRANGEBYSCORE dengan beberapa argumen tambahan. Ambil alamat IP dan ubah menjadi desimal. Ini dapat dilakukan dengan menggunakan bahasa pemrograman Anda. Pertama, gunakan alamat dari contoh aslinya 74.125.43.99 (1249717091). Jika kita mengambil nomor ini sebagai titik referensi dan tidak menentukan maksimum, dan kemudian membatasi hasilnya hanya untuk objek pertama, kita akan menemukan geolokasi-nya:
> ZRANGEBYSCORE ip-loc 1249717091 +inf LIMIT 0 1 1) "us:2"
Argumen pertama adalah kunci dari set kami yang diurutkan, yang kedua adalah representasi desimal dari alamat IP, yang ketiga (+ inf) memberitahu Redis untuk meminta tanpa batas atas, dan tiga argumen terakhir hanya menunjukkan bahwa kami hanya ingin mendapatkan hasil yang pertama.
Pencarian Teks Lengkap
Sebelum munculnya modul, pencarian teks lengkap dilaksanakan menggunakan perintah asli Redis. Modul RedisSearch jauh lebih produktif daripada pola ini, namun, di beberapa lingkungan tidak tersedia. Selain itu, pola ini sangat menarik dan dapat digeneralisasi ke beban kerja lain di mana RedisSearch tidak akan ideal.
Misalkan kita memiliki beberapa dokumen teks yang perlu dicari. Ini mungkin bukan kasus penggunaan yang jelas untuk Redis, karena menyediakan akses utama, tetapi di sisi lain, Redis dapat digunakan sebagai mesin pencari teks lengkap yang benar-benar baru.
Pertama, mari kita ambil beberapa sampel teks dalam dokumen:
"Redis sangat cepat""Cheetah cepat"โCheetah punya bintik-bintikโKami membaginya menjadi set kata, dipisahkan oleh ruang untuk kesederhanaan:
> SADD ex1 redis is very fast > SADD ex2 cheetahs are very fast > SADD ex3 cheetahs have spots
Perhatikan bahwa kami menempatkan setiap baris di set sendiri. Tampaknya kita hanya menambahkan seluruh baris - SADD adalah variabel dan mengambil beberapa elemen sekaligus sebagai argumen. Kami juga mengonversi semua kata menjadi huruf kecil.
Maka kita perlu membalikkan indeks ini dan menunjukkan kata mana yang terkandung dalam dokumen mana. Untuk melakukan ini, kita akan membuat satu set untuk setiap kata dan meletakkan nama dokumen sebagai objek:
> SADD redis ex1 > SADD is ex1 > SADD very ex1 ex2 > SADD fast ex1 ex2 > SADD cheetahs ex2 ex3 > SADD have ex3 > SADD spots ex3
Untuk kejelasan, kami membagi ini menjadi perintah yang berbeda, tetapi semua perintah biasanya dijalankan secara atom di blok MULTI / EXEC.
Untuk menanyakan indeks teks lengkap kecil kami, kami menggunakan perintah SINTER (persimpangan set). Temukan dokumen dengan "sangat" dan "cepat":
> SINTER very fast 1) "ex2" 2) "ex1"
Jika tidak ada dokumen yang cocok dengan permintaan, kami akan mendapatkan hasil kosong:
> SINTER cheetahs redis (empty list or set)
Untuk konsistensi, lebih baik menggunakan SUNION daripada SINTER:
> SUNION cheetahs redis 1) "ex2" 2) "ex1" 3) "ex3"
Menghapus objek dari indeks sedikit lebih rumit. Pertama, dapatkan kata yang diindeks dari dokumen, lalu hapus pengidentifikasi dokumen dari setiap kata:
> SMEMBERS ex3 1) "spots" 2) "have" 3) "cheetahs" > SREM have ex3 > SREM cheetahs ex3 > SREM spots ex3
Redis tidak memiliki operator terpisah untuk melakukan semua langkah ini dengan satu perintah, jadi pertama-tama Anda harus melakukan kueri dengan perintah SMEMBERS, lalu hapus setiap objek secara berurutan menggunakan SREM.
Tentu saja, ini adalah pencarian teks lengkap yang sangat disederhanakan. Anda dapat melakukan lebih lanjut dengan menggunakan set yang disortir daripada yang biasa. Dalam hal ini, jika sebuah kata muncul lebih dari satu kali dalam sebuah dokumen, Anda dapat memeringkatnya lebih tinggi dari pada dokumen yang muncul sekali. Pola yang diuraikan di atas kurang lebih sama, dengan pengecualian pada jenis set yang digunakan.
Indeks yang Dipartisi
Satu instance (atau pecahan) Redis sangat memungkinkan, tetapi ada beberapa kondisi di mana Anda mungkin memerlukan indeks yang didistribusikan di beberapa instance. Misalnya, untuk meningkatkan throughput dengan memparalelkan indeks yang lebih besar dari ruang kosong sebuah instance. Katakanlah Anda ingin melakukan operasi pada beberapa tombol. Cara efektif untuk memisahkan (mempartisi) kunci-kunci ini adalah untuk memastikan distribusi kunci yang merata di setiap partisi, melakukan operasi apa pun di setiap partisi secara paralel, dan kemudian menggabungkan hasilnya di akhir.
Untuk mencapai distribusi kunci yang seragam, kami akan menggunakan algoritma hashing non-kriptografi. Setiap fungsi hash cepat akan dilakukan, tetapi kami menggunakan CRC-32 yang terkenal sebagai contoh. Dalam kebanyakan kasus, algoritma ini mengembalikan hasilnya dalam heksadesimal (untuk "dokumen-keren-ku" CRC-32 akan mengembalikan F9FDB2C9). Representasi heksadesimal lebih sederhana untuk mesin, tetapi itu hanyalah representasi lain dari bilangan bulat desimal, yang berarti bahwa Anda dapat melakukan perhitungan pada nilai-nilai ini.
Selanjutnya, Anda perlu menentukan jumlah partisi - ini harus setidaknya x2 dari jumlah salinan. Ini selanjutnya berkontribusi pada penskalaan.
Katakanlah kita memiliki 3 salinan dan 6 partisi. Partisi tempat dokumen dikirim dapat dihitung dengan operasi berikut:
CRC32(โmy-cool-documentโ) = F9FDB2C9 (16) 4194153161 (10) 4194153161 mod 6 = 5
Di Redis Enterprise, Anda dapat mengontrol partisi milik kunci tersebut, menggunakan ekspresi reguler yang telah ditentukan sebelumnya, atau dengan membungkus bagian kunci dengan kurung kurawal. Jadi untuk contoh kita, kita dapat mengatur kunci untuk dokumen sebagai berikut:
idx: my-cool-document {5}Kemudian kami memiliki dokumen lain yang mengeluarkan partisi dengan nomor 3, oleh karena itu, kuncinya akan terlihat seperti ini:
idx: my-other-document {3}Jika Anda memiliki kunci tambahan yang perlu Anda kerjakan dan yang terkait dengan dokumen ini, Anda harus berada di partisi yang sama sehingga Anda dapat melakukan operasi dengan kedua kunci secara bersamaan tanpa menemukan banyak kesalahan. Untuk melakukan ini, Anda perlu menambahkan nomor partisi yang sama ke kunci sebagai dokumen.
Melihat data Anda dari jarak jauh, Anda akan melihat bahwa indeks Anda didistribusikan secara merata di seluruh partisi. Anda dapat memparalelkan tugas yang perlu dilakukan untuk setiap partisi. Ketika Anda memiliki tugas yang perlu dilakukan melalui seluruh indeks, aplikasi Anda harus melakukan logika yang sama untuk setiap partisi, mengembalikan hasilnya dan menggabungkan seperti yang diperlukan dalam aplikasi.
Tentang ini, artikel pertama berakhir. Berikutnya akan menjadi terjemahan dari subpos "Pola Interaksi" dan "Pola Penyimpanan Data".