Niektóre dodatki do danego zestawu odpowiedzi:
Przede wszystkim, jeśli zamierzasz efektywnie korzystać z skrótu Redis, musisz wiedzieć, że klucze liczą maksymalną liczbę i wartości maksymalny rozmiar - w przeciwnym razie, jeśli wyłamią wartości skrótu-wartości-ziplista lub wartości skrótu-z-listy-kluczy, Redis przekonwertuje je na praktycznie zwykłe pary klucz / wartość pod maską. .
Oznacza to, że jeśli zaczniesz z opcją drugą i przypadkowo wyrwiesz się z wartości maksymalnej-z-listy skrótów, otrzymasz +90 bajtów na KAŻDY ATRYBUT, który masz wewnątrz modelu użytkownika! (właściwie nie +90, ale +70 patrz wyjście konsoli poniżej)
# you need me-redis and awesome-print gems to run exact code
redis = Redis.include(MeRedis).configure( hash_max_ziplist_value: 64, hash_max_ziplist_entries: 512 ).new
=> #<Redis client v4.0.1 for redis://127.0.0.1:6379/0>
> redis.flushdb
=> "OK"
> ap redis.info(:memory)
{
"used_memory" => "529512",
**"used_memory_human" => "517.10K"**,
....
}
=> nil
# me_set( 't:i' ... ) same as hset( 't:i/512', i % 512 ... )
# txt is some english fictionary book around 56K length,
# so we just take some random 63-symbols string from it
> redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), 63] ) } }; :done
=> :done
> ap redis.info(:memory)
{
"used_memory" => "1251944",
**"used_memory_human" => "1.19M"**, # ~ 72b per key/value
.....
}
> redis.flushdb
=> "OK"
# setting **only one value** +1 byte per hash of 512 values equal to set them all +1 byte
> redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), i % 512 == 0 ? 65 : 63] ) } }; :done
> ap redis.info(:memory)
{
"used_memory" => "1876064",
"used_memory_human" => "1.79M", # ~ 134 bytes per pair
....
}
redis.pipelined{ 10000.times{ |i| redis.set( "t:#{i}", txt[rand(50000), 65] ) } };
ap redis.info(:memory)
{
"used_memory" => "2262312",
"used_memory_human" => "2.16M", #~155 byte per pair i.e. +90 bytes
....
}
W przypadku odpowiedzi TheHippo komentarze do Opcji pierwszej wprowadzają w błąd:
hgetall / hmset / hmget na ratunek, jeśli potrzebujesz wszystkich pól lub wielu operacji get / set.
Na odpowiedź BMiner.
Trzecia opcja jest naprawdę fajna, ponieważ zestaw danych z wartością max (id) <has-max-ziplist-value to rozwiązanie ma złożoność O (N), ponieważ, niespodzianka, Reddis przechowuje małe skróty jako podobny do tablicy kontener długości / klucza / wartości przedmioty!
Ale wiele razy skróty zawierają tylko kilka pól. Gdy skróty są małe, możemy zamiast tego po prostu zakodować je w strukturze danych O (N), jak tablica liniowa z parami klucz-wartość z prefiksem długości. Ponieważ robimy to tylko wtedy, gdy N jest małe, zamortyzowany czas dla poleceń HGET i HSET wynosi wciąż O (1): skrót zostanie przekonwertowany na prawdziwą tablicę skrótów, gdy tylko liczba zawartych w nim elementów wzrośnie zbyt mocno
Ale nie powinieneś się martwić, bardzo szybko przerwiesz wpisy hash-max-ziplist-i gotowe, jesteś teraz przy rozwiązaniu numer 1.
Druga opcja najprawdopodobniej przejdzie do czwartego rozwiązania pod maską, ponieważ jak stanowi pytanie:
Pamiętaj, że jeśli użyję skrótu, długość wartości nie jest przewidywalna. Nie wszystkie są krótkie, tak jak powyższy przykład biografii.
I jak już powiedziałeś: czwarte rozwiązanie to na pewno najdroższy bajt +70 na każdy atrybut.
Moja sugestia jak zoptymalizować taki zestaw danych:
Masz dwie opcje:
Jeśli nie możesz zagwarantować maksymalnego rozmiaru niektórych atrybutów użytkownika, przejdź do pierwszego rozwiązania i jeśli ważna jest pamięć, to skompresuj użytkownika json przed przechowywaniem w redis.
Jeśli możesz wymusić maksymalny rozmiar wszystkich atrybutów. Następnie możesz ustawić hash-max-ziplist-wpisy / wartość i używać skrótów jako jeden skrót dla reprezentacji użytkownika LUB jako optymalizację pamięci hash z tego tematu przewodnika Redis: https://redis.io/topics/memory-optimization i przechowuj użytkownika jako ciąg json. Tak czy inaczej możesz kompresować długie atrybuty użytkownika.