Saya mencoba menjawab dua pertanyaan dalam daftar yang pasti:
- Apa struktur data dasar yang digunakan untuk Redis?
- Dan apa keuntungan / kerugian / penggunaan kasus utama untuk setiap jenis?
Jadi, saya sudah baca daftar Redis yang sebenarnya diimplementasikan dengan daftar tertaut. Tetapi untuk tipe lain, saya tidak dapat menggali informasi apa pun. Juga, jika seseorang tersandung pada pertanyaan ini dan tidak memiliki ringkasan pro dan kontra tingkat tinggi dalam memodifikasi atau mengakses struktur data yang berbeda, mereka akan memiliki daftar lengkap kapan sebaiknya menggunakan jenis spesifik untuk referensi juga.
Secara khusus, saya mencari garis besar semua jenis: string, daftar, set, zset, dan hash.
Oh, saya sudah melihat artikel ini, antara lain, sejauh ini:
algorithm
data-structures
redis
Homer6
sumber
sumber
Jawaban:
Saya akan mencoba menjawab pertanyaan Anda, tetapi saya akan mulai dengan sesuatu yang mungkin terlihat aneh pada awalnya: jika Anda tidak tertarik dengan Redis internal Anda tidak harus peduli tentang bagaimana tipe data diimplementasikan secara internal. Ini karena alasan sederhana: untuk setiap operasi Redis Anda akan menemukan kompleksitas waktu dalam dokumentasi dan, jika Anda memiliki serangkaian operasi dan kompleksitas waktu, satu-satunya hal lain yang Anda butuhkan adalah beberapa petunjuk tentang penggunaan memori (dan karena kami melakukan banyak optimasi yang dapat bervariasi tergantung pada data, cara terbaik untuk mendapatkan angka-angka terakhir ini adalah melakukan beberapa tes dunia nyata sepele).
Tetapi karena Anda bertanya, ini adalah implementasi mendasar dari setiap tipe data Redis.
Tetapi ketika daftar, set, dan set diurutkan kecil dalam jumlah item dan ukuran nilai terbesar, yang berbeda, pengkodean jauh lebih kompak digunakan. Pengkodean ini berbeda untuk jenis yang berbeda, tetapi memiliki fitur bahwa itu adalah kumpulan data yang padat yang seringkali memaksa pemindaian O (N) untuk setiap operasi. Karena kami menggunakan format ini hanya untuk objek kecil, ini bukan masalah; pemindaian gumpalan O (N) kecil adalah cache terlupakan sehingga secara praktis berbicara sangat cepat, dan ketika ada terlalu banyak elemen pengkodean secara otomatis beralih ke pengkodean asli (daftar terkait, hash, dan sebagainya).
Tetapi pertanyaan Anda bukan hanya tentang internal, maksud Anda adalah tipe apa yang digunakan untuk mencapai apa? .
String
Ini adalah tipe dasar dari semua tipe. Ini salah satu dari empat tipe tetapi juga tipe dasar dari tipe kompleks, karena Daftar adalah daftar string, Set adalah serangkaian string, dan sebagainya.
String Redis adalah ide bagus di semua skenario yang jelas di mana Anda ingin menyimpan halaman HTML, tetapi juga ketika Anda ingin menghindari konversi data yang sudah disandikan. Jadi misalnya, jika Anda memiliki JSON atau MessagePack, Anda dapat menyimpan objek sebagai string. Di Redis 2.6 Anda bahkan dapat memanipulasi sisi server objek semacam ini menggunakan skrip Lua.
Penggunaan string yang menarik lainnya adalah bitmap, dan secara umum array akses acak byte, karena Redis mengekspor perintah untuk mengakses rentang byte byte acak, atau bahkan bit tunggal. Sebagai contoh, periksa posting blog yang bagus ini: Fast Easy metrik waktu nyata menggunakan Redis .
Daftar
Daftar bagus ketika Anda cenderung menyentuh hanya bagian paling ekstrem dari daftar: dekat ekor, atau dekat kepala. Daftar tidak terlalu baik untuk hal paginasi, karena akses acak lambat, O (N). Jadi penggunaan daftar yang baik adalah antrian dan tumpukan sederhana, atau memproses item dalam satu lingkaran menggunakan RPOPLPUSH dengan sumber dan tujuan yang sama untuk "memutar" serangkaian item.
Daftar juga bagus ketika kita hanya ingin membuat koleksi item N yang dibatasi di mana biasanya kita mengakses item atas atau bawah, atau ketika N kecil.
Set
Set adalah kumpulan data yang tidak teratur, sehingga mereka bagus setiap kali Anda memiliki koleksi item dan sangat penting untuk memeriksa keberadaan atau ukuran koleksi dengan cara yang sangat cepat. Hal keren lainnya tentang set adalah dukungan untuk mengintip atau memunculkan elemen acak (perintah SRANDMEMBER dan SPOP).
Set juga baik untuk mewakili relasi, misalnya, "Apa yang dimaksud teman pengguna X?" Dan seterusnya. Tetapi struktur data bagus lainnya untuk hal-hal semacam ini diurutkan set seperti yang akan kita lihat.
Set mendukung operasi yang kompleks seperti persimpangan, serikat, dan sebagainya, jadi ini adalah struktur data yang baik untuk menggunakan Redis dengan cara "komputasi", ketika Anda memiliki data dan Anda ingin melakukan transformasi pada data tersebut untuk mendapatkan beberapa output.
Set kecil dikodekan dengan cara yang sangat efisien.
Hash
Hash adalah struktur data yang sempurna untuk mewakili objek, terdiri dari bidang dan nilai. Bidang hash juga bisa ditambah secara atom menggunakan HINCRBY. Ketika Anda memiliki objek seperti pengguna, posting blog, atau beberapa jenis item lainnya , hash kemungkinan adalah cara yang harus dilakukan jika Anda tidak ingin menggunakan penyandian Anda sendiri seperti JSON atau yang serupa.
Namun, perlu diingat bahwa hash kecil dikodekan dengan sangat efisien oleh Redis, dan Anda dapat meminta Redis untuk secara GET, SET, atau menambah bidang individual secara cepat.
Hash juga dapat digunakan untuk mewakili struktur data tertaut, menggunakan referensi. Sebagai contoh, periksa implementasi komentar lamernews.com.
Set Diurutkan
Kumpulan yang diurutkan adalah satu - satunya struktur data lainnya, selain daftar, untuk mempertahankan elemen yang diurutkan . Anda dapat melakukan sejumlah hal keren dengan set yang diurutkan. Misalnya, Anda dapat memiliki semua jenis daftar Sesuatu Top di aplikasi web Anda. Pengguna teratas berdasarkan skor, posting teratas menurut tampilan halaman, teratas apa pun, tetapi satu instance Redis tunggal akan mendukung banyak operasi penyisipan dan elemen-atas-per detik.
Set yang disortir, seperti set reguler, dapat digunakan untuk menggambarkan hubungan, tetapi mereka juga memungkinkan Anda untuk membuat paginasi daftar item dan mengingat urutannya. Misalnya, jika saya ingat teman pengguna X dengan set yang diurutkan saya dapat dengan mudah mengingatnya dalam urutan persahabatan yang diterima.
Kumpulan yang diurutkan baik untuk antrian prioritas.
Kumpulan yang disortir seperti daftar yang lebih kuat di mana memasukkan, menghapus, atau mendapatkan rentang dari tengah daftar selalu cepat. Tetapi mereka menggunakan lebih banyak memori, dan merupakan struktur data O (log (N)).
Kesimpulan
Saya harap saya memberikan beberapa informasi dalam posting ini, tetapi jauh lebih baik untuk mengunduh kode sumber lamernews dari http://github.com/antirez/lamernews dan memahami cara kerjanya. Banyak struktur data dari Redis digunakan di dalam Lamer News, dan ada banyak petunjuk tentang apa yang harus digunakan untuk menyelesaikan tugas yang diberikan.
Maaf untuk kesalahan ketik tata bahasa, ini tengah malam di sini dan terlalu lelah untuk meninjau pos;)
sumber
Sebagian besar waktu, Anda tidak perlu memahami struktur data dasar yang digunakan oleh Redis. Tetapi sedikit pengetahuan membantu Anda membuat pertukaran memori CPU v / s. Ini juga membantu Anda memodelkan data Anda dengan cara yang efisien.
Secara internal, Redis menggunakan struktur data berikut:
Untuk menemukan pengkodean yang digunakan oleh kunci tertentu, gunakan perintah
object encoding <key>
.1. String
Dalam Redis, String disebut Simple Dynamic Strings, atau SDS . Ini adalah pembungkus yang lebih kecil dari
char *
yang memungkinkan Anda untuk menyimpan panjang string dan jumlah byte gratis sebagai awalan.Karena panjang string disimpan, strlen adalah operasi O (1). Juga, karena panjangnya diketahui, string Redis aman untuk biner. Sangat sah jika string berisi karakter nol .
String adalah struktur data paling serbaguna yang tersedia di Redis. String adalah semua hal berikut ini:
long
yang dapat menyimpan angka. Lihat KENAIKAN , DECR , INCRBY dan DECRBY perintah.chars
,ints
,longs
atau jenis data lainnya) yang dapat memungkinkan akses acak efisien. Lihat perintah SETRANGE dan GETRANGE .2. Kamus
Redis menggunakan Kamus untuk yang berikut:
Kamus Redis diimplementasikan menggunakan Tabel Hash . Alih-alih menjelaskan implementasi, saya hanya akan menjelaskan hal-hal spesifik Redis:
dictType
untuk memperluas perilaku tabel hash. Struktur ini memiliki pointer fungsi, sehingga operasi berikut dapat diperpanjang: a) fungsi hash, b) perbandingan kunci, c) penghancur kunci, dan d) penghancur nilai.The
Set
struktur data menggunakan kamus untuk menjamin tidak ada duplikasi. TheSorted Set
menggunakan kamus untuk memetakan elemen untuk skor nya, yang mengapa ZSCORE adalah O (1) operasi.3. Daftar Tertaut Ganda
The
list
tipe data diimplementasikan dengan menggunakan Daftar Ganda Linked . Implementasi Redis adalah buku teks langsung-dari-algoritma-. Satu-satunya perubahan adalah bahwa Redis menyimpan panjang dalam struktur data daftar. Ini memastikan bahwa LLEN memiliki O (1).4. Lewati Daftar
Redis menggunakan Abaikan Daftar sebagai struktur data yang mendasari untuk Sorted Sets. Wikipedia memiliki pengantar yang bagus. Makalah William Pugh Lewati Daftar: Alternatif Probabilistik untuk Pohon Seimbang memiliki detail lebih lanjut.
Set Diurutkan menggunakan Lewati Daftar dan Kamus. Kamus menyimpan skor setiap elemen.
Implementasi Daftar Lewati Redis berbeda dari implementasi standar dalam cara-cara berikut:
5. Daftar Zip
Daftar Zip seperti daftar tertaut dua kali lipat, kecuali itu tidak menggunakan pointer dan menyimpan data inline.
Setiap node dalam daftar tertaut ganda memiliki 3 pointer - satu pointer maju, satu pointer mundur dan satu pointer untuk referensi data yang disimpan di node itu. Pointer membutuhkan memori (8 byte pada sistem 64 bit), dan untuk daftar kecil, daftar tertaut ganda sangat tidak efisien.
Daftar Zip menyimpan elemen secara berurutan dalam String Redis. Setiap elemen memiliki header kecil yang menyimpan panjang dan tipe data elemen, offset ke elemen berikutnya, dan offset ke elemen sebelumnya. Offset ini menggantikan pointer maju dan mundur. Karena data disimpan inline, kita tidak perlu pointer data.
Daftar Zip digunakan untuk menyimpan daftar kecil, set dan hash yang diurutkan. Set yang diurutkan diratakan ke dalam daftar seperti
[element1, score1, element2, score2, element3, score3]
dan disimpan dalam Daftar Zip. Hash diratakan ke dalam daftar seperti[key1, value1, key2, value2]
dll.Dengan Daftar Zip, Anda memiliki kekuatan untuk melakukan pertukaran antara CPU dan Memori. Daftar Zip hemat memori, tetapi mereka menggunakan lebih banyak CPU daripada daftar yang ditautkan (atau Hash table / Skip List). Menemukan elemen dalam daftar zip adalah O (n). Memasukkan elemen baru membutuhkan realokasi memori. Karena itu, Redis menggunakan pengodean ini hanya untuk daftar kecil, hash dan set diurutkan. Anda bisa mengubah perilaku ini dengan mengubah nilai
<datatype>-max-ziplist-entries
dan<datatype>-max-ziplist-value>
di redis.conf. Lihat Redis Memory Optimization, bagian "Pengkodean khusus tipe data agregat kecil" untuk informasi lebih lanjut.The komentar pada ziplist.c sangat baik, dan Anda dapat memahami struktur data ini benar-benar tanpa harus membaca kode.
6. Set Int
Set Int adalah nama mewah untuk "Array Integer Diurutkan".
Di Redis, set biasanya diimplementasikan menggunakan tabel hash. Untuk set kecil, tabel hash adalah memori yang tidak efisien. Ketika himpunan terdiri dari bilangan bulat saja, array seringkali lebih efisien.
Set Int adalah array integer yang diurutkan. Untuk menemukan elemen, algoritma pencarian biner digunakan. Ini memiliki kompleksitas O (log N). Menambahkan bilangan bulat baru ke array ini mungkin memerlukan realokasi memori, yang bisa menjadi mahal untuk array bilangan besar.
Sebagai optimasi memori lebih lanjut, Int Sets hadir dalam 3 varian dengan ukuran integer yang berbeda: 16 bit, 32 bit dan 64 bit. Redis cukup pintar untuk menggunakan varian yang tepat tergantung pada ukuran elemen. Ketika elemen baru ditambahkan dan melebihi ukuran saat ini, Redis secara otomatis memigrasikannya ke ukuran berikutnya. Jika sebuah string ditambahkan, Redis secara otomatis mengonversi Int Set ke set berbasis Tabel Hash biasa.
Set Int adalah pertukaran antara CPU dan Memori. Set Int sangat efisien memori, dan untuk set kecil lebih cepat dari tabel hash. Tetapi setelah sejumlah elemen tertentu, waktu pengambilan O (log N) dan biaya realokasi memori menjadi terlalu banyak. Berdasarkan percobaan, ambang batas optimal untuk beralih ke tabel hash biasa ditemukan menjadi 512. Namun, Anda dapat meningkatkan ambang ini (mengurangi itu tidak masuk akal) berdasarkan kebutuhan aplikasi Anda. Lihat
set-max-intset-entries
di redis.conf.7. Zip Maps
Zip Maps adalah kamus yang diratakan dan disimpan dalam daftar. Mereka sangat mirip dengan Daftar Zip.
Zip Maps telah ditinggalkan sejak Redis 2.6, dan hash kecil disimpan di Daftar Zip. Untuk mempelajari lebih lanjut tentang penyandian ini, lihat komentar di zipmap.c .
sumber
Redis menyimpan kunci yang menunjuk ke nilai. Kunci dapat berupa nilai biner apa pun hingga ukuran yang wajar (menggunakan string ASCII pendek disarankan untuk keterbacaan dan tujuan debugging). Nilai adalah satu dari lima tipe data Redis asli.
String
String Redis adalah urutan byte.
String di Redis adalah biner safe (artinya mereka memiliki panjang yang diketahui tidak ditentukan oleh karakter penghentian khusus), sehingga Anda dapat menyimpan apa pun hingga 512 megabyte dalam satu string.
String adalah konsep "key value store" kanonis. Anda memiliki kunci yang menunjuk ke suatu nilai, di mana kunci dan nilainya adalah teks atau string biner.
Untuk semua operasi yang mungkin pada string, lihat http://redis.io/commands/#string
Hash
Hash Redis adalah kumpulan pasangan nilai kunci.
Hash Redis menampung banyak pasangan nilai kunci, di mana setiap kunci dan nilai adalah string. Hash redis tidak mendukung nilai kompleks secara langsung (artinya, Anda tidak dapat memiliki bidang hash memiliki nilai daftar atau set atau hash lain), tetapi Anda dapat menggunakan bidang hash untuk menunjuk ke nilai kompleks tingkat atas lainnya. Satu-satunya operasi khusus yang dapat Anda lakukan pada nilai bidang hash adalah penambahan / pengurangan atom dari konten numerik.
Anda dapat memikirkan hasis Redis dalam dua cara: sebagai representasi objek langsung dan sebagai cara untuk menyimpan banyak nilai kecil secara kompak.
Representasi objek langsung mudah dipahami. Objek memiliki nama (kunci hash) dan kumpulan kunci internal dengan nilai. Lihat contoh di bawah ini untuk, contohnya.
Menyimpan banyak nilai kecil menggunakan hash adalah teknik penyimpanan data masif Redis yang pintar. Ketika hash memiliki sejumlah kecil bidang (~ 100), Redis mengoptimalkan penyimpanan dan efisiensi akses seluruh hash. Optimalisasi penyimpanan hash kecil Redis memunculkan perilaku yang menarik: lebih efisien memiliki masing-masing 100 hash dengan 100 kunci dan nilai internal daripada memiliki 10.000 kunci tingkat atas yang menunjuk ke nilai string. Menggunakan hash Redis untuk mengoptimalkan penyimpanan data Anda dengan cara ini memang memerlukan overhead pemrograman tambahan untuk melacak di mana data berakhir, tetapi jika penyimpanan data Anda berbasis string, Anda dapat menghemat banyak overhead memori menggunakan trik aneh ini.
Untuk semua operasi yang mungkin pada hash, lihat dokumen hash
Daftar
Daftar redis bertindak seperti daftar tertaut.
Anda dapat menyisipkan, menghapus dari, dan melintasi daftar dari kepala atau ekor daftar.
Gunakan daftar saat Anda perlu mempertahankan nilai sesuai urutan yang dimasukkan. (Redis memberi Anda opsi untuk memasukkan ke dalam posisi daftar sembarang jika Anda perlu, tetapi kinerja penyisipan Anda akan menurun jika Anda memasukkan jauh dari posisi awal Anda.)
Daftar redis sering digunakan sebagai antrian produsen / konsumen. Masukkan item ke daftar lalu pop item dari daftar. Apa yang terjadi jika konsumen Anda mencoba keluar dari daftar tanpa elemen? Anda dapat meminta Redis untuk menunggu sebuah elemen muncul dan segera mengembalikannya kepada Anda ketika elemen tersebut ditambahkan. Ini mengubah Redis menjadi antrian pesan waktu nyata / acara / pekerjaan / tugas / sistem pemberitahuan.
Anda dapat menghapus elemen secara atom dari ujung daftar, memungkinkan daftar mana saja diperlakukan sebagai tumpukan atau antrian.
Anda juga dapat mempertahankan daftar panjang tetap (koleksi tertutup) dengan memangkas daftar Anda ke ukuran tertentu setelah setiap penyisipan.
Untuk semua operasi yang mungkin pada daftar, lihat daftar dokumen
Set
Set redis adalah, well, set.
Set Redis berisi string Redis unordered unik di mana setiap string hanya ada sekali per set. Jika Anda menambahkan elemen yang sama sepuluh kali ke set, itu hanya akan muncul sekali. Set sangat bagus untuk memastikan ada sesuatu yang malas setidaknya sekali tanpa khawatir tentang elemen duplikat yang menumpuk dan membuang-buang ruang. Anda dapat menambahkan string yang sama sebanyak yang Anda suka tanpa perlu memeriksa apakah sudah ada.
Set cepat untuk memeriksa keanggotaan, penyisipan, dan penghapusan anggota dalam set.
Set memiliki operasi set yang efisien, seperti yang Anda harapkan. Anda dapat mengambil gabungan, persimpangan, dan perbedaan beberapa set sekaligus. Hasil dapat dikembalikan ke pemanggil atau hasilnya dapat disimpan dalam set baru untuk penggunaan nanti.
Set memiliki akses waktu konstan untuk pemeriksaan keanggotaan (tidak seperti daftar), dan Redis bahkan memiliki penghapusan dan pengembalian anggota acak yang mudah ("pop elemen acak dari set") atau anggota acak yang kembali tanpa penggantian ("beri saya 30 pengguna unik acak-ish) ") atau dengan penggantian (" beri saya 7 kartu, tetapi setelah setiap pemilihan, kembalikan kartu itu sehingga berpotensi dijadikan sampel lagi ").
Untuk semua operasi yang mungkin dilakukan pada set, lihat set docs .
Set Diurutkan
Redis diurutkan set adalah set dengan pemesanan yang ditentukan pengguna.
Untuk kesederhanaan, Anda dapat menganggap set diurutkan sebagai pohon biner dengan elemen unik. (Set redis yang diurutkan sebenarnya melewati daftar .) Urutan sortir elemen ditentukan oleh skor setiap elemen.
Set yang diurutkan masih set. Elemen hanya dapat muncul sekali dalam satu set. Suatu elemen, untuk tujuan keunikan, ditentukan oleh konten stringnya. Memasukkan elemen "apel" dengan skor sortir 3, lalu menyisipkan elemen "apel" dengan skor sortir 500 menghasilkan satu elemen "apel" dengan skor sortir 500 di set yang diurutkan. Set hanya unik berdasarkan Data, bukan berdasarkan pada pasangan (Nilai, Data).
Pastikan model data Anda bergantung pada konten string dan bukan skor elemen untuk keunikan. Skor diizinkan diulangi (atau bahkan nol), tetapi, untuk terakhir kalinya, elemen yang diatur hanya dapat ada satu kali per set yang diurutkan. Misalnya, jika Anda mencoba untuk menyimpan riwayat setiap login pengguna sebagai set yang diurutkan dengan membuat skor sebagai periode login dan nilai id pengguna, Anda akhirnya akan menyimpan hanya periode login terakhir untuk semua pengguna Anda. Set Anda akan tumbuh sesuai ukuran basis pengguna Anda dan bukan ukuran ukuran penggunaan yang Anda inginkan * login.
Elemen ditambahkan ke set Anda dengan skor. Anda dapat memperbarui skor elemen apa saja kapan saja, cukup tambahkan elemen lagi dengan skor baru. Skor diwakili oleh dobel floating point, sehingga Anda dapat menentukan rincian dari cap waktu presisi tinggi jika diperlukan. Beberapa elemen mungkin memiliki skor yang sama.
Anda dapat mengambil elemen dengan beberapa cara berbeda. Karena semuanya diurutkan, Anda dapat meminta elemen mulai dari skor terendah. Anda dapat meminta elemen mulai dari skor tertinggi ("terbalik"). Anda dapat meminta elemen berdasarkan skor sortirnya baik secara alami atau terbalik.
Untuk semua operasi yang mungkin pada set diurutkan, lihat set dokumen yang diurutkan.
sumber