Hlavní navigace

Databáze Redis (nejenom) pro vývojáře používající Python

Pavel Tišnovský

Dnes se seznámíme s nerelační databází Redis, kterou je možné díky její flexibilitě využít k mnoha účelům, například jako vyrovnávací paměť, jako distribuovanou key-value databázi či pro systémy založené na frontách zpráv.

Doba čtení: 29 minut

11. Množiny

12. Množinové operace

13. Mapy (asociativní pole)

14. Množiny s ohodnocenými prvky (uspořádané množiny)

15. Další operace s uspořádanými množinami

16. Transakce

17. Použití Redisu z Pythonu

18. Vybrané operace poskytované knihovnou redis

19. Využití „pipeline“ pro sloučení většího množství příkazů do jediného požadavku

20. Odkazy na Internetu

1. Databáze Redis (nejenom) pro vývojáře používající Python

Databáze Redis (REmote DIctionary Server) patří do rozsáhlé a nehomogenní skupiny nerelačních databází. Konkrétně se jedná o databázi typu key-value, což znamená, že hodnoty ukládané do databáze je možné jednoznačně identifikovat (najít, smazat atd.) na základě klíče, který je reprezentován řetězcem. Podobných databází samozřejmě existuje celá řada; za zmínku stojí především Berkeley DB, dále pak MemcacheDB, Dynamo či InfinityDB. Dnes popisovaná databáze Redis může být pro vývojáře zajímavá a užitečná zejména z toho důvodu, že se jedná o velmi flexibilní systém, který lze škálovat nejenom „nahoru“ (distribuované systémy se shardingem a/nebo replikací), ale i „dolů“ (jednoduše nastavitelné datové odkladiště pro jednouživatelskou aplikaci).

Na jedné straně je možné Redis provozovat na jediném stroji s tím, že data budou uložena pouze v operační paměti, na straně druhé je však možné relativně snadno nakonfigurovat Redis takovým způsobem, že data budou rozložena mezi více strojů (sharding), popř. se použije architektura typu master-slave, kdy bude Redis data replikovat na pozadí mezi uzlem typu master a uzly typu slave (se všemi z toho vyplývajícími důsledky).

Díky této flexibilitě je možné systém Redis v praxi využít mnoha různými způsoby. Používá se například ve formě vyrovnávací paměti (cache), přičemž je dokonce možné specifikovat dobu života jednotlivých údajů, takže mazání starších položek nemusí být řešeno přímo v aplikaci (životnost údajů lze snadno obnovit, což se hodí například při ukládání informací o session/sezení u webových aplikací). Ovšem Redis můžeme použít i jako plnohodnotnou key-value databázi s tím, že data budou na pozadí ukládána na nevolatilní paměť (typicky na pevný disk či dnes spíše na SSD), což znamená, že údaje přežijí restart Redisu, pád počítače či systému atd. K dispozici mají vývojáři dvě základní strategie ukládání dat do nevolatilní paměti, které lze dokonce použít současně, o čemž se ve stručnosti zmíníme v páté a šesté kapitole. V případě potřeby je možné realizovat i systém s transakcemi, popř. využít některé atomické operace, které Redis podporuje už ve své základní sadě příkazů.

Z praktického hlediska je užitečné, že k Redisu, který je již při základní instalaci vybaven klientem ovládaným z příkazové řádky, je možné přistupovat z mnoha programovacích jazyků: na stránce https://redis.io/clients jsou vypsány informace o rozhraních k padesáti (!) jazykům, samozřejmě včetně populární pětice C, C++, Java, Python a Go. Navíc je možné od verze 2.6 dokonce využít i podporu pro přímé spouštění příkazů Redisu ze skriptů napsaných v programovacím jazyce Lua, který se skutečně velmi dobře hodí pro skriptování aplikací. Důležité přitom je, že skripty lze nahrát přímo do serveru Redisu a spustit je až ve chvíli, kdy jsou skutečně zapotřebí. V dnešním článku se však zaměříme především na použití Redisu přímo ze standardního klienta redis-cli a posléze z Pythonu.

2. Instalace Redisu

Před otestováním možností Redisu je samozřejmě nutné tento nástroj nainstalovat. Vzhledem k tomu, že se jedná o (na dnešní poměry) vlastně velmi malý projekt, je instalace prakticky okamžitá. Jen pro ukázku se podívejme na instalaci na Fedoře 27 s využitím nástroje dnf:

$ sudo dnf install redis
 
Last metadata expiration check: 0:15:30 ago on Wed 24 Oct 2018, 22:50:11 CEST.
Dependencies resolved.
================================================================================
 Package           Arch            Version               Repository        Size
================================================================================
Installing:
 redis             x86_64          4.0.9-1.fc27          updates          580 k
Installing dependencies:
 jemalloc          x86_64          4.5.0-5.fc27          updates          210 k
 
Transaction Summary
================================================================================
Install  2 Packages
 
Total download size: 790 k
Installed size: 2.0 M
Is this ok [y/N]:

Samotný průběh instalace:

Downloading Packages:
(1/2): jemalloc-4.5.0-5.fc27.x86_64.rpm         1.0 MB/s | 210 kB     00:00
(2/2): redis-4.0.9-1.fc27.x86_64.rpm            2.3 MB/s | 580 kB     00:00
--------------------------------------------------------------------------------
Total                                           1.0 MB/s | 790 kB     00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : jemalloc-4.5.0-5.fc27.x86_64                           1/2
  Running scriptlet: jemalloc-4.5.0-5.fc27.x86_64                           1/2
  Running scriptlet: redis-4.0.9-1.fc27.x86_64                              2/2
  Installing       : redis-4.0.9-1.fc27.x86_64                              2/2
  Running scriptlet: redis-4.0.9-1.fc27.x86_64                              2/2
Running as unit: run-r389424a3db894d8e83bddf2d54cd6d4e.service
  Verifying        : redis-4.0.9-1.fc27.x86_64                              1/2
  Verifying        : jemalloc-4.5.0-5.fc27.x86_64                           2/2
 
Installed:
  redis.x86_64 4.0.9-1.fc27             jemalloc.x86_64 4.5.0-5.fc27
 
Complete!
Poznámka: povšimněte si, že se nainstalovala verze Redisu 4.0.9. Ve skutečnosti je však k dispozici i novější Redis 5.0. Tato nová verze podporuje některé příkazy, které ve verzi 4.0.x nenalezneme. Týká se to například příkazů ZPOPMIN a ZPOPMAX používaných při práci s množinami, do nichž jsou uloženy ohodnocené prvky (resp. přesněji řečeno prvky s přiřazeným skóre). Nicméně všechny funkce, které si popíšeme v dnešním článku, budou funkční jak na verzích 4.0.x, tak i na verzi 5.0.

Na systémech založených na Debianu (včetně Ubuntu) lze pro instalaci použít příkaz:

$ apt-get install redis-server

Pokud budete potřebovat použít nejnovější verzi Redisu, můžete si ho sami přeložit. Postup je jednoduchý (mj. i díky minimálním závislostem na dalších knihovnách) a je podrobně popsán na stránce https://redis.io/topics/quickstart.

Po instalaci se můžeme přesvědčit, že je skutečně k dispozici spustitelný soubor s implementací serveru i řádkového klienta:

$ whereis -b redis-cli
redis-cli: /usr/bin/redis-cli
 
$ whereis -b redis-server
redis-server: /usr/bin/redis-server

3. Konfigurace vhodná pro první seznámení s Redisem

Databázový server Redis je sice možné spustit jako službu, ale pro otestování jeho základní funkcionality bude jednodušší a především bezpečnější spustit tuto aplikaci pouze lokálně – Redis sice bude stále pracovat ve funkci serveru, ale bude akceptovat pouze požadavky o připojení, které přichází ze stejného počítače a nikoli z okolních strojů. Nejprve si vytvoříme adresář, v němž bude uložena jak konfigurace, tak všechny vytvářené datové soubory. Tento adresář pojmenovaný jednoduše „redis“ vytvoříme přímo v domácím adresáři právě přihlášeného uživatele a následně se do něj přepneme:

$ mkdir redis
$ cd redis

Následně přímo v tomto adresáři vytvoříme konfigurační soubor nazvaný redis.conf. Můžeme se přitom inspirovat souborem /etc/redis/redis.conf (Debian), popř. /etc/redis.conf (Fedora, RHEL, CentOS), který je však poměrně rozsáhlý, protože kromě vlastních konfiguračních voleb obsahuje i podrobné informace o významu jednotlivých konfiguračních voleb. Tento soubor je taktéž dostupný na internetu na adrese https://raw.githubusercon­tent.com/antirez/redis/4.0/re­dis.conf.

Následuje výpis obsahu konfiguračního souboru, který je připraven pro lokální spuštění Redisu, bez nebezpečí, že se k běžícímu serveru připojí případný útočník. Důležité volby jsou zvýrazněny a některé z nich budou popsány na konci kapitoly. Pokud se vám soubor nechce kopírovat, naleznete ho na adrese https://github.com/tisnik/pre­sentations/blob/master/re­dis/redis.conf:

bind 127.0.0.1
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile redis.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir .
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes

Popišme si nyní ve stručnosti zvýrazněné konfigurační volby:

Volba Význam
bind 127.0.0.1 seznam síťových rozhraní, na kterých bude Redis přijímat požadavky (zde explicitně povolujeme jen loopback)
protected-mode yes pokud zapomenete na předchozí volbu a nezadáte heslo, zapne se režim přijímaní lokálních požadavků
logfile redis.log jméno logovacího souboru, zde uvedeno bez adresáře: bude lokální (kde spustíme server)
dir . adresář, do kterého se budou ukládat soubory obsahující databázi
appendfilename „appendonly.aof“ jméno a umístění takzvaného „append only file“ popsaného níže

Takto nastavený Redis bude ukládat prakticky všechny své soubory do aktuálního adresáře. Jediným souborem vytvářeným mimo tento adresář bude soubor s PID běžícího Redisu, který nalezneme v /var/run/redis_6379.pid.

4. Spuštění Redisu a první experimenty se systémem

Nejprve spustíme serverovou část Redisu, a to přímo z adresáře ~/redis, protože právě zde máme uložen výše popsaný konfigurační soubor „redis.conf“

$ pwd
/home/tester/redis
 
$ redis-server redis.conf 

Na druhém terminálu pak již můžeme spustit klienta Redisu, který uživatelům nabízí interaktivní příkazový řádek:

$ redis-cli
127.0.0.1:6379>

Příkazem „ping“ můžeme otestovat, jestli se klient připojí k serveru a zda od něj dokáže získávat odpovědi:

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> ping test
"test"
Poznámka: v dokumentaci jsou všechny příkazy psány velkými písmeny, ovšem v interaktivním shellu můžete používat i písmena malá. Všechny tři následující příkazy jsou tedy z pohledu Redisu totožné:
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> PinG
PONG
127.0.0.1:6379> PING
PONG

Uložení hodnoty do databáze se provádí příkazem set, kterému se předá klíč (řetězec) a hodnota (taktéž řetězec):

127.0.0.1:6379> set answer 42
OK

Opakem operace set je přečtení hodnoty příkazem get. Povšimněte si, že se skutečně vrací řetězec a pokud hodnota neexistuje (resp. přesněji řečeno pokud neexistuje dvojice klíč-hodnota), vrátí se hodnota nil:

127.0.0.1:6379> get answer
"42"
127.0.0.1:6379> get foobar
(nil)

Vzhledem k tomu, že klíčem může být jakýkoli řetězec, můžeme se setkat s tím, že ve jménech klíčů je vyjádřena nějaká hierarchie dat. Používají se například tečky, dvojtečky nebo lomítka:

127.0.0.1:6379> set users:root "Administrator"
OK
127.0.0.1:6379> set users:pavel "Tester"
OK
127.0.0.1:6379> set users:petr "Developer"
OK
127.0.0.1:6379> get users:petr
"Developer"
127.0.0.1:6379> set users:petr "DevOps"
OK
127.0.0.1:6379> get users:petr
"DevOps"

Příkazem setnx taktéž do databáze ukládáme dvojici klíč-hodnota, ale pouze v případě, že daný klíč ještě neexistuje. Pokud klíč existuje, není hodnota přepsána:

127.0.0.1:6379> setnx users:petr "Developer again"
(integer) 0
127.0.0.1:6379> get users:petr
"DevOps"
127.0.0.1:6379> setnx users:lukas "New Developer"
(integer) 1
127.0.0.1:6379> get users:lukas
"New Developer"

Často se setkáme s tím, že se současně načítá větší množství dvojic klíč-hodnota příkazem mget. Eliminuje se tím počet zpráv předávaných serveru, což se pozitivně projeví na plně zatíženém systému:

127.0.0.1:6379> mget users:root users:pavel users:petr users:zdenek
1) "Administrator"
2) "Tester"
3) "DevOps"
4) (nil)

Řádkový klient obsahuje i vestavěnou nápovědu:

127.0.0.1:6379> help
redis-cli 4.0.9
To get help about Redis commands type:
      "help @<group>" to get a list of commands in <group>
      "help <command>" for help on <command>
      "help <tab>" to get a list of possible help topics
      "quit" to exit
 
To set redis-cli preferences:
      ":set hints" enable online hints
      ":set nohints" disable online hints
Set your preferences in ~/.redisclirc

Po ukončení interaktivního shellu můžeme ukončit i běh samotného serveru Redisu, například stiskem Ctrl+C v terminálu, kde server běží, popř. příkazem shutdown zadaným z řádkového klienta:

127.0.0.1:6379> shutdown
not connected>

Nyní by se v aktuálním adresáři ~/redis/ měla nacházet čtveřice souborů:

$ ls -1
appendonly.aof
dump.rdb
redis.conf
redis.log

V dalších kapitolách si vysvětlíme především význam souboru dump.rdb a appendonly.aof.

5. Perzistentní uložení databáze

Databázi Redis je možné nakonfigurovat mnoha různými způsoby. Pro jednoduchost předpokládejme, že celá databáze bude provozována na jediném stroji, tj. nebudeme používat ani horizontální škálování ani replikace. Takto nakonfigurovaná databáze může být uložena buď pouze v operační paměti (typické použití – cache), nebo ji lze ukládat i do nevolatilní paměti (pevný disk, SSD, …). Existují čtyři prakticky používané kombinace:

  1. Databáze je uložena jen v RAM
  2. Použití kombinace RAM + soubory RDB
  3. Použití kombinace RAM + soubory AOF
  4. Použití kombinace RAM + soubory RDB i AOF

Na discích, resp. obecně na paměťových médiích, je databáze ukládána do souborů s koncovkou .rdb. Jedná se o binární soubory, které jsou navrženy takovým způsobem, aby práce s nimi byla velmi rychlá. V případě potřeby se používá komprimace LZW pro zmenšení velikosti těchto souborů. Interně je před každým objektem uloženým v tomto souboru specifikována i velikost objektu, což zjednodušuje načítání .rdb zpět do operační paměti. Na konci souboru je navíc (v závislosti na konfiguraci) uložen 64bitový kontrolní součet, který je možné použít pro jednoduchou kontrolu konzistence dat.

Mimochodem, konzistenci samotného souboru s obrazem databáze je možné zkontrolovat příkazem redis-check-rdb:

$ redis-check-rdb dump.rdb 
 
[offset 0] Checking RDB file dump.rdb
[offset 26] AUX FIELD redis-ver = '4.0.9'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1541800518'
[offset 67] AUX FIELD used-mem = '513184'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 455] Checksum OK
[offset 455] \o/ RDB looks OK! \o/
[info] 18 keys read
[info] 0 expires
[info] 0 already expired

Jak se vlastně soubory RDB vytváří? Frekvence tvorby těchto souborů je plně konfigurovatelná administrátorem, který například může specifikovat, že se tyto soubory budou obnovovat každých pět minut, po zápisu deseti prvků atd. Samotný zápis probíhá do nového souboru a teprve po provedení celého zápisu (a provedení flush) se provede přejmenování souboru, což je – minimálně v Linuxu – atomická operace. Vždy tedy budeme mít k dispozici buď dvojici starý_RDB + potenciálně_neúplný_nový_RDB nebo nový_RDB; nemělo by dojít k situaci, kdy je starý RDB vymazán a nový ještě není konzistentní.

6. AOF – Append Only File

Víme již, že kromě obrazu databáze ukládaného do souborů RDB, je možné použít takzvané Append Only File(s) neboli AOF. Jedná se o textové a tudíž i snadno čitelné textové soubory, do nichž se postupně ukládají všechny příkazy, které modifikují obsah databáze (v praxi to znamená, že zde například nenalezneme příkazy GET). Při opětovném startu Redisu je tedy možné, aby server tento soubor „přehrál“ (vykonal všechny v něm uložené příkazy) a databázi tak obnovil. Použití souborů AOF je možné zakázat či povolit a při jejich povolení je navíc možné specifikovat, jak často se budou provádět zápisy příkazů. Platí jednoduché a pochopitelné pravidlo – čím častěji budeme chtít provádět zápisy (skutečné zápisy následované příkazem flush), tím více klíčů se nám podaří obnovit, ovšem zápisy AOF na druhou stranu zpomalí všechny zápisy do databáze (čtení není nijak ovlivněno). Záleží tedy na administrátorech databáze a samozřejmě též na aplikaci, které databázi používá, kolik potenciálně ztracených dat je možné tolerovat (údaje z poslední minuty? poslední dva zápisy? atd.).

Poznámka: označení Append Only File je pravdivé a přiléhavé, protože se do těchto souborů skutečně pouze přidávají řádky na konec. Nikdy se neprovede seek a nemělo by tedy dojít k poškození již zapsaných informací. Pokud je poškozen konec souboru, což může nastat při nečekaném pádu celého systému (výpadek elektřiny apod.), nepředstavuje to pro Redis katastrofální problém – soubor se jednoduše „přehraje“ až do okamžiku, kdy jsou detekovány poškozené údaje a na tomto místě obnova databáze skončí.

Pokud se podíváme do souboru nazvaného appendonly.aof (viz třetí kapitolu s konfigurací, kde jsme specifikovali umístění tohoto souboru do aktuálního adresáře), měli bychom vidět následující obsah, který odpovídá operacím, které jsme v databázi provedli. Samozřejmě zůstává zachováno pořadí těchto operací. Je tomu tak z toho důvodu, že „přehráním“ AOF souboru bychom měli dostat přesný obraz databáze:

*2
$6
SELECT
$1
0
*3
$3
set
$6
answer
$2
42
Poznámka: ve skutečnosti můžeme v AOF najít odlišné příkazy, než ty, které byly zadány uživatelem. To se může týkat například dále popsaného příkazu INCR atd. Výsledek (z pohledu obsahu databáze) však bude stejný.

7. Nastavení doby životnosti dat

V případě, že se systém Redis používá pro implementaci vyrovnávací paměti, je možné využít jeho další užitečnou funkci – u všech záznamů je totiž možné specifikovat dobu jejich životnosti (TTL – Time To Live). K tomuto účelu se používá několik příkazů, zejména pak:

Příkaz Význam
setex vytvoření záznamu + nastavení jeho životnosti v sekundách
psetex vytvoření záznamu + nastavení jeho životnosti v milisekundách
expire nastavení životnosti existujícího záznamu v sekundách
pexpire nastavení životnosti existujícího záznamu v milisekundách

Podívejme se nyní na způsob použití příkazu expire. Již v předchozích kapitolách byly do databáze uloženy informace o několika uživatelích, ale klidně můžeme tyto příkazy zopakovat:

127.0.0.1:6379> set users:root "Administrator"
OK
127.0.0.1:6379> set users:pavel "Tester"
OK
127.0.0.1:6379> set users:petr "Developer"
OK

Dobu životnosti jednotlivých záznamů lze ovlivnit příkazem expire, přičemž TTL je v nejjednodušším případě nastaveno v sekundách:

127.0.0.1:6379> expire users:pavel 10
(integer) 1
127.0.0.1:6379> expire users:petr 5
(integer) 1

Pokus o načtení čtyř záznamů ihned po provedení předchozích příkazů:

127.0.0.1:6379> mget users:root users:pavel users:petr users:zdenek
1) "Administrator"
2) "Tester"
3) "DevOps"
4) (nil)

Po čtvrtminutě ovšem dostaneme rozdílné výsledky:

127.0.0.1:6379> mget users:root users:pavel users:petr users:zdenek
1) "Administrator"
2) (nil)
3) (nil)
4) (nil)

Aktuální dobu životnosti můžeme zjistit příkazem ttl:

127.0.0.1:6379> expire users:root 20
(integer) 1
127.0.0.1:6379> ttl users:root
(integer) 16
127.0.0.1:6379> ttl users:root
(integer) 10
127.0.0.1:6379> ttl users:root
(integer) 0
127.0.0.1:6379> ttl users:root
(integer) -2

Zajímavá je poslední hodnota. Příkaz ttl totiž vrací buď přirozené číslo vyjadřující zbývající životnost, nebo zápornou hodnotu s tímto významem:

  • –1: klíč existuje, ale nemá přiřazenou životnost (je neomezená)
  • –2: klíč už neexistuje, takže záznam již byl pravděpodobně odstraněn

8. Podporované datové typy, s nimiž Redis pracuje

Při ukládání a zpracování dat ukládaných do Redisu je možné data reprezentovat několika datovými typy. Jména jednotlivých typů jsou vypsána v tabulce pod tímto odstavcem a v navazujících kapitolách si řekneme o vybraných typech některé bližší informace (zaměřené spíše na jejich praktické použití):

Jméno Stručná charakteristika
string řetězce, které lze ovšem využít i pro práci s celými čísly i čísly s FP
list seznamy, ve skutečnosti se s nimi pracuje jako se zásobníkem a frontou
set množiny, je zaručena unikátnost prvků
sorted set množiny, v nichž jsou jednotlivé prvky ohodnoceny skórem
hash mapy (též asociativní pole)
bitmap (bit array) pole bitů, interně mapovány na řetězce
HyperLogLogs (HLL) datová struktura používaná pro zjištění počtu unikátních prvků (s určitou chybou, ovšem s malou spotřebou paměti)

9. Práce s řetězci uloženými do databáze

Základním datovým typem, který se v Redisu používá, jsou řetězce. Ve skutečnosti se jedná o sekvenci bajtů známé délky, které nejsou žádným způsobem interpretovány. Díky tomu, že je délka řetězce uložena ve zvláštním atributu, nemusí Redis používat například znak s kódem 0 pro ukončení řetězce a tudíž se i tento znak může bez problému v řetězci vyskytovat. Maximální délka řetězce je v současné verzi Redisu 512 MB, což v praxi znamená, že se řetězce mohou použít například pro uložení dokumentů, strukturovaných dat reprezentovaných ve formátech JSON, XML, YAML atd. atd.

Mezi základní příkazy pro práci s řetězci patří nám již známé příkazu set a get. Ovšem řetězce lze i modifikovat příkazem append a můžeme získat délku řetězce pomocí strlen:

127.0.0.1:6379> set z ""
OK
127.0.0.1:6379> append z "Hello"
(integer) 5
127.0.0.1:6379> append z " "
(integer) 6
127.0.0.1:6379> append z "world!"
(integer) 12
127.0.0.1:6379> get z
"Hello world!"
127.0.0.1:6379> strlen z
(integer) 12

Zajímavé je, že i když Redis neobsahuje přímou podporu pro datový typ „celé číslo“, nabízí svým uživatelům několik operací určených pro atomickou změnu numerických hodnot reprezentovaných řetězcem v běžném dekadickém formátu. Pro zvýšení hodnoty o jedničku se používá operace INCR, opakem je pochopitelně funkce DECR. V případě, že budeme potřebovat zvýšit nebo snížit uloženou hodnotu o krok odlišný od jedničky, je možné pro tento účel použít operaci pojmenovanou příhodně INCRBY. Podívejme se na příklady (spouštěné přímo z redis-cli:

127.0.0.1:6379> set x 0
OK
127.0.0.1:6379> INCR x
(integer) 1
127.0.0.1:6379> get x
"1"
127.0.0.1:6379> INCRBY x 100
(integer) 101
127.0.0.1:6379> get x
"101"
127.0.0.1:6379> DECR x
(integer) 100
127.0.0.1:6379> get x
"100"
Proč vlastně tyto příkazy existují? Díky jejich existenci nemusíme zvýšení či snížení hodnoty řešit v transakci. Transakce lze samozřejmě použít, ale není nutné s nimi „plýtvat“ na takto jednoduchou věc.

Podobná operace nazvaná INCRBYFLOAT slouží pro změnu hodnoty čísla s desetinnou tečkou (opět ovšem uloženého formou běžného řetězce). Příklad na interpretaci řetězce jako čísla s plovoucí řádovou čárkou:

127.0.0.1:6379> set y 0.5
OK
127.0.0.1:6379> INCRBYFLOAT y 0.3
"0.8"
127.0.0.1:6379> get y
"0.8"

Řetězec „0.8“ ovšem již není možné považovat za reprezentaci celého čísla:

127.0.0.1:6379> incr y
(error) ERR value is not an integer or out of range
Poznámka: hodnoty uložené pod klíči „x“, „y“ a „z“ ve skutečnosti stále zůstávají řetězci:
127.0.0.1:6379> type x
string
127.0.0.1:6379> type y
string
127.0.0.1:6379> type z
string

10. Seznamy

Dalším datovým typem, který se v Redisu velmi často používá, jsou seznamy (list). Tento název je ovšem poněkud nepřesný, protože seznamy je možné využít například i pro implementaci fronty (queue), zásobníku (stack), běžného pole (array) nebo dokonce obousměrné fronty (deque). Počet prvků zapisovaných do seznamu může dosahovat prakticky neomezené hodnoty, konkrétně lze do jediného seznamu uložit 232-1 prvků. Mezi základní operace pro práci se seznamy patří:

Příkaz Význam
lpush přidání prvku na začátek seznamu
rpush přidání prvku na konec seznamu
lpop přečtení prvního prvku ze seznamu s jeho odstraněním
rpop přečtení posledního prvku ze seznamu s jeho odstraněním
   
lset změna hodnoty prvku na určeném indexu v seznamu
lindex přečtení prvku se zadaným indexem
   
linsert přidání prvku na určený index seznamu (s posunem dalších prvků)
llen přečtení délky seznamu

Podívejme se nyní na několik příkladů. Seznam uložený pod klíčem „l“ se automaticky vytvoří hned prvním příkazem:

127.0.0.1:6379> lpush l 3
(integer) 1
127.0.0.1:6379> lpush l 2
(integer) 2
127.0.0.1:6379> lpush l 1
(integer) 3
127.0.0.1:6379> llen l
(integer) 3
127.0.0.1:6379> rpush l 1
(integer) 4
127.0.0.1:6379> rpush l 2
(integer) 5
127.0.0.1:6379> rpush l 3
(integer) 6
127.0.0.1:6379> llen l
(integer) 6

Typ hodnoty uložené pod klíčem „l“:

127.0.0.1:6379> type l
list

Seznam nelze přečíst operací get:

127.0.0.1:6379> get l
(error) WRONGTYPE Operation against a key holding the wrong kind of value

Čtení prvků ze začátku i konce seznamu s jejich postupným odstraňováním:

127.0.0.1:6379> lpop l
"1"
127.0.0.1:6379> lpop l
"2"
127.0.0.1:6379> lpop l
"3"
127.0.0.1:6379> lpop l
"1"
127.0.0.1:6379> lpop l
"2"
127.0.0.1:6379> lpop l
"3"

Pokus o přečtení hodnoty z prázdného seznamu:

127.0.0.1:6379> lpop l
(nil)

11. Množiny

Dalším datovým typem, s nímž je možné v Redisu pracovat, jsou množiny. Každá množina může obsahovat až 232-1 prvků, což je stejná kapacita, jako u seznamů. Prvky se do množiny přidávají příkazem sadd. Pokud množina neexistuje, je prvním příkazem sadd vytvořena:

127.0.0.1:6379> sadd s "foo"
(integer) 1
127.0.0.1:6379> sadd s "bar"
(integer) 1
127.0.0.1:6379> sadd s "baz"
(integer) 1

Počet prvků v množině získáme příkazem scard, seznam všech prvků pak příkazem smembers:

127.0.0.1:6379> scard s
(integer) 3
 
127.0.0.1:6379> smembers s
1) "bar"
2) "baz"
3) "foo"

Test, jestli množina obsahuje nějaký prvek, zajistí příkaz sismemer, který vrací numerickou hodnotu 0 nebo 1:

127.0.0.1:6379> sismember s "foo"
(integer) 1
 
127.0.0.1:6379> sismember s "xyzzy"
(integer) 0

Odstranění prvku z množiny zajistí příkaz srem, který navíc vrátí příznak, zda byl prvek odstraněn (tj. zda vůbec v množině figuroval):

127.0.0.1:6379> srem s "foo"
(integer) 1
 
127.0.0.1:6379> sismember s "foo"
(integer) 0
 
127.0.0.1:6379> smembers s
1) "bar"
2) "baz"

12. Množinové operace

Systém Redis podporuje provádění základních množinových operací – sjednocení, průniku a rozdílu. Tyto operace jsou vyvolány příkazy sunion, sunionstore, sinter, sinterstore, sdiff a sdiffstore.

Před ukázkou těchto operací si vytvoříme dvě množiny s1 a s2.

Naplnění množiny s1:

127.0.0.1:6379> sadd s1 1
(integer) 1
 
127.0.0.1:6379> sadd s1 2
(integer) 1
 
127.0.0.1:6379> sadd s1 3
(integer) 1
 
127.0.0.1:6379> sadd s1 4
(integer) 1

Naplnění množiny s2:

127.0.0.1:6379> sadd s2 3
(integer) 1
 
127.0.0.1:6379> sadd s2 4
(integer) 1
 
127.0.0.1:6379> sadd s2 5
(integer) 1
 
127.0.0.1:6379> sadd s2 6
(integer) 1

Obsah obou množin:

127.0.0.1:6379> smembers s1
1) "1"
2) "2"
3) "3"
4) "4"
 
127.0.0.1:6379> smembers s2
1) "3"
2) "4"
3) "5"
4) "6"

Příkazem sunionstore vytvoříme novou množinu, která bude sjednocením obou množin zdrojových:

127.0.0.1:6379> sunionstore s3 s1 s2
(integer) 6
 
127.0.0.1:6379> smembers s3
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

Podobně je možné příkazem sinterstore vytvořit novou množinu pomocí operace průniku:

127.0.0.1:6379> sinterstore s4 s1 s2
(integer) 2
 
127.0.0.1:6379> smembers s4
1) "3"
2) "4"

Poslední podporovanou operací je rozdíl množin. Tato operace není komutativní, takže je pochopitelně rozdíl mezi rozdílem s1\s2 a s2\s1:

127.0.0.1:6379> sdiffstore s5 s1 s2
(integer) 2
 
127.0.0.1:6379> smembers s5
1) "1"
2) "2"
 
127.0.0.1:6379> sdiffstore s6 s2 s1
(integer) 2
 
127.0.0.1:6379> smembers s6
1) "5"
2) "6"

13. Mapy (asociativní pole)

Jedním z nejpoužívanějších datových typů v Redisu jsou mapy neboli asociativní pole. Každá mapa může obsahovat 232-1 dvojic klíč-hodnota, přičemž klíčem jsou řetězce. Příkazy pro práci s asociativními poli začínají prefixem „H“. Základním příkazem je hset pro uložení dvojice klíč-hodnota do množiny, ovšem častěji se setkáme s příkazem hmset, který umožňuje uložit větší množství dvojic jedinou operací. Opakem jsou operace hget pro přečtení jednoho prvku nebo hgetall pro přečtení všech dvojic (formou tabulky, tj. tabulka má dvakrát více prvků, než asociativní pole):

127.0.0.1:6379> hset apole x 1
(integer) 1
 
127.0.0.1:6379> hset apole y 2
(integer) 1
 
127.0.0.1:6379> hget apole x
"1"
 
127.0.0.1:6379> hget apole z
(nil)

Přepis existující hodnoty:

127.0.0.1:6379> hset apole x "nova hodnota"
(integer) 0
 
127.0.0.1:6379> hget apole x 
"nova hodnota"

Použití příkazů hmset a hgetall:

127.0.0.1:6379> hmset user:1000 username antirez password P1pp0 age 34
OK
 
127.0.0.1:6379> hgetall user:1000
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
 
127.0.0.1:6379> hset user:1000 password 12345
(integer) 0
 
127.0.0.1:6379> hgetall user:1000
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"

14. Množiny s ohodnocenými prvky (uspořádané množiny)

Posledním datovým typem Redisu, o kterém se dnes zmíníme, jsou množiny s ohodnocenými prvky. Každému prvku je přiřazeno číslo, které je následně použito při porovnávání jednotlivých prvků (množina je tedy částečně uspořádaná), při zpětném čtení prvků apod. Příkazy, které s tímto datovým typem pracují, začínají prefixem „z“. Nejprve vytvoříme novou množinu a přidáme do ní několik prvků. Zadané číslo odpovídá ohodnocení prvků:

127.0.0.1:6379> zadd set 100 x
(integer) 1
 
127.0.0.1:6379> zadd set 150 y
(integer) 1
 
127.0.0.1:6379> zadd set 50 z
(integer) 1
 
127.0.0.1:6379> zadd set -5 w
(integer) 1

Hodnota ve skutečnosti může být reálné číslo, nikoli pouze číslo celé:

127.0.0.1:6379> zadd set 0.5 a
(integer) 1

Aktuální pořadí prvku (na základě jeho ohodnocení) přečteme příkazem zrank:

127.0.0.1:6379> zrank set x
(integer) 3
 
127.0.0.1:6379> zrank set w
(integer) 0
 
127.0.0.1:6379> zrank set foo
(nil)

Dále můžeme získat počet prvků množiny příkazem zcard, popř. příkazem zcount zjistit počet takových prvků, jejichž skóre leží v nějakém zadaném intervalu:

127.0.0.1:6379> zcard set
(integer) 4
 
127.0.0.1:6379> zcount set -1000 1000
(integer) 4
 
127.0.0.1:6379> zcount set 0 1000
(integer) 3

Ohodnocení lze změnit příkazem zincrby, kterému se zadá relativní přírůstek (samozřejmě může být i záporný):

127.0.0.1:6379> zrank set x
(integer) 3
 
127.0.0.1:6379> zincrby set 1000 x
"1100"
 
127.0.0.1:6379> zrank set x
(integer) 4
 
127.0.0.1:6379> zincrby set -2000 x
"-900"
 
127.0.0.1:6379> zrank set x
(integer) 0

15. Další operace s uspořádanými množinami

Nad uspořádanými množinami je možné provádět i další operace, například získat ty prvky, jejichž ohodnocení se nachází mezi specifikovanými mezními hodnotami:

127.0.0.1:6379> zrangebyscore set 1 200
1) "z"
2) "y"
 
127.0.0.1:6379> zrangebyscore set 1 300
1) "z"
2) "y"
3) "x"

Příkazem zremrangebyscore lze odstranit prvky, jejichž ohodnocení (skóre) se nachází mezi mezními hodnotami:

127.0.0.1:6379> zremrangebyscore set 1 200
(integer) 2
 
127.0.0.1:6379> zrangebyscore set -1000 1000
1) "w"
2) "x"

Pokus o vymazání prvků se skóre, které v množině neleží:

127.0.0.1:6379> zrangebyscore set 1 200
(empty list or set)

16. Transakce

Redis taktéž podporuje transakce. U příkazů, které jsou součástí transakce, jsou dodrženy následující podmínky:

  1. Všechny příkazy v transakci jsou provedeny v takovém pořadí, v jakém jsou zapsány uživatelem.
  2. Mezi tyto příkazy se nikdy nevmísí příkazy vyžadované jiným klientem.
  3. Transakce je atomická: buď se provede celá (všechny příkazy), nebo se neprovede vůbec.

Pro práci s transakcemi jsou určeny příkazy multi, exec a discard. Podívejme se nyní na velmi jednoduchý „školní“ příklad, v němž se převádí nějaká částka mezi dvěma účty „ucet1“ a „ucet2“:

127.0.0.1:6379> set ucet1 1000.0
OK
 
127.0.0.1:6379> set ucet2 0.0
OK

Tuto peněžní transakci musíme provést v databázové transakci, tj. zadáme ji mezi příkazy multi a exec:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrbyfloat ucet1 -150.50
QUEUED
127.0.0.1:6379> incrbyfloat ucet2 +150.50
QUEUED
127.0.0.1:6379> exec
1) "849.5"
2) "150.5"

Výsledné hodnoty na účtu po provedení transakce:

127.0.0.1:6379> get ucet1
"849.5"
127.0.0.1:6379> get ucet2
"150.5"
Upozornění: v současné verzi Redisu není možné transakce vnořovat:
127.0.0.1:6379> multi
OK
 
127.0.0.1:6379> multi
(error) ERR MULTI calls can not be nested

Redis navíc neumožňuje ani rollback v případě, že při zpracování transakce dojde k chybě nějakého příkazu.

Poznámka: ve skutečnosti je práce s transakcemi v Redisu ještě složitější, neboť je nutné sledovat výsledek (zda transakce proběhla či nikoli) a v případě neúspěchu se transakci pokusit provést znovu. S podrobnostmi se seznámíme příště.

17. Použití Redisu z Pythonu

Ve druhé části dnešního článku si ukážeme, jakým způsobem lze používat databázi Redis z programovacího jazyka Python. Pro Redis samozřejmě existuje knihovna (přesněji řečeno dokonce více knihoven) s rozhraním k Redisu, které je – alespoň při použití běžných datových typů – velmi jednoduše použitelné. Nejprve samozřejmě musíme příslušnou knihovnu nainstalovat, což je otázka několika sekund. Postačuje použít příkaz pip popř. pip3 pro instalaci knihovny redis. Pro jistotu instalaci provedeme pouze pro aktivního uživatele, takže se knihovna i její metadata uloží do adresáře ~/.local/lib/python{VERZE}/site-packages/:

$ pip3 install --user redis
 
Collecting redis
  Downloading https://files.pythonhosted.org/packages/3b/f6/7a76333cf0b9251ecf49efff635015171843d9b977e4ffcf59f9c4428052/redis-2.10.6-py2.py3-n
    100% |████████████████████████████████| 71kB 909kB/s
Installing collected packages: redis
Successfully installed redis-2.10.6

Pokud instalace knihovny redis proběhla v pořádku, můžeme si ji vyzkoušet. Nejprve spustíme interaktivní smyčku Pythonu:

$ python3
Python 3.6.3 (default, Oct  9 2017, 12:11:29)
[GCC 7.2.1 20170915 (Red Hat 7.2.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
Poznámka: jak jste si mohli všimnout, testování provádím na stroji s dnes již zastaralým systémem a taktéž postarší verzí Pythonu. Ovšem knihovna redis je pochopitelně funkční i s nejnovějším (stabilním) Pythonem 3.7.1.

V interpretru Pythonu nyní nejprve naimportujeme modul redis.

>>> import redis

Můžeme si vyzkoušet zobrazit si nápovědu:

>>> help("redis")

S výsledkem:

Help on package redis:
 
NAME
    redis
 
PACKAGE CONTENTS
    _compat
    client
    connection
    exceptions
    lock
    sentinel
    utils
 
CLASSES
    builtins.Exception(builtins.BaseException)
        redis.exceptions.RedisError
            redis.exceptions.AuthenticationError
            redis.exceptions.ConnectionError
                redis.exceptions.BusyLoadingError

Ovšem důležitější je samozřejmě vlastní rozhraní k databázi Redisu. Nejprve vytvoříme objekt typu Redis zavoláním stejnojmenné funkce, které se předá adresa a port Redis serveru, na který se klient pokusí připojit. Náš server naslouchá na loopbacku, konkrétně na portu 6379:

>>> r = redis.Redis(host='127.0.0.1', port=6379)
>>> r
Redis<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>

V případě, že se připojení podařilo, můžeme se pokusit přečíst z databáze hodnotu uloženou pod klíčem „answer“. To je jednoduché, protože postačuje použít metodu get():

>>> r.get("answer")
b'42'
 
>>> print(r.get("answer"))
b'42'
Poznámka: povšimněte si prefixu „b“ před řetězcem. Samotnou interpretaci jednotlivých bajtů můžete provést programově.

V případě, že se pokusíme přečíst hodnotu pod neexistujícím klíčem, vrátí se None:

>>> r.get("foo")
 
>>> print(r.get("foobarbaz"))
None

Samozřejmě je možné do databáze i zapisovat, a to v tom nejjednodušším případě metodou set:

>>> r.set("foo", -1)
True
>>> r.get("foo")
b'-1'

Zjištění délky seznamu:

>>> r.llen("l")
1

Další příkazy si popíšeme v navazujícím textu.

18. Vybrané operace poskytované knihovnou redis

Vyzkoušejme si nyní některé další operace, které jsou poskytovány knihovnou redis a které jsou tedy přístupné všem uživatelům Pythonu.

Nejprve si ukážeme nastavení řetězcové hodnoty a její modifikaci připojením dalšího řetězce:

>>> r.set("greeting", "")
True
 
>>> r.append("greeting", "Hello")
5
 
>>> r.append("greeting", " ")
6
 
>>> r.append("greeting", "world!")
12
 
>>> r.get("greeting")
b'Hello world!'
Poznámka: povšimněte si, že se opět vrátil řetězec obsahující sekvenci bajtů, jehož převod na „skutečný“ řetězec je již ponechán na programátorovi (ten pro tento účel může použít metodu decode).

Nastavení řetězce a použití příkazů pro zvýšení a snížení numerické hodnoty reprezentované řetězcem:

>>> r.set("x", 10)
True
>>> r.incr("x", 20)
30
>>> r.get("x")
b'30'
>>> r.decr("x", 1000)
-970
>>> r.get("x")
b'-970'

Použití prvku nazvaného „zasobnik“ ve funkci skutečného zásobníku s operacemi PUSH a POP:

>>> r.lpush("zasobnik", 1)
1
 
>>> r.lpush("zasobnik", 10)
2
 
>>> r.lpop("zasobnik")
b'10'
 
>>> r.lpop("zasobnik")
b'1'
 
>>> r.lpop("zasobnik")
 

Použití prvku nazvaného „fronta“ ve funkci jednosměrné fronty s operacemi ENQUEUE a DEQUEUE (realizovanými jinak pojmenovanými operacemi Redisu):

>>> r.lpush("fronta", 1)
1
 
>>> r.lpush("fronta", 10)
2
 
>>> r.rpop("fronta")
b'1'
 
>>> r.rpop("fronta")
b'10'
 
>>> r.rpop("fronta")
 

19. Využití „pipeline“ pro sloučení většího množství příkazů do jediného požadavku

Velmi užitečný je v praxi objekt typu „pipeline“. Ten umožňuje specifikovat větší množství příkazů, které se následně přenesou do Redisu (na server) v jediném balíku. V praxi se totiž může ukázat, že přenos jednotlivých příkazů je úzkým hrdlem celého systému. Nejprve si ukažme, jakým způsobem se „pipeline“ použije pouze pro seskupení příkazů, nikoli pro provedení příkazů v transakci:

>>> pipe = r.pipeline(transaction=False)
 
>>> for i in range(1, 11):
...     pipe.lpush("list1", i)
...     pipe.rpush("list2", i)
...
Pipeline<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>
...
...
...
 
>>> pipe.execute()
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]

Povšimněte si, že objekt typu pipeline nabízí stejné metody, jako objekt typu Redis. Teprve po spuštění metody pipe.execute() se všechny operace (v našem případě dvacet operací PUSH přenesou na server a tam provedou. Server odpoví seznamem výsledků těchto příkazů (tento seznam jen vypíšeme, ale jinak ho můžeme ignorovat).

Test, zda se skutečně změnil obsah objektů pod klíči list1 a list2:

>>> while True:
...     item = r.lpop("list1")
...     if item is None:
...         break
...     print(item)
...
 
b'10'
b'9'
b'8'
b'7'
b'6'
b'5'
b'4'
b'3'
b'2'
b'1'
>>> while True:
...     item = r.lpop("list2")
...     if item is None:
...         break
...     print(item)
...
 
b'1'
b'2'
b'3'
b'4'
b'5'
b'6'
b'7'
b'8'
b'9'
b'10'
Poznámka: použití smyčky while je v Pythonu skutečně poněkud nepřirozené; zde jsem ji využil jen kvůli jednoznačnosti zápisu.

Objekt typu pipeline je ovšem možné použít i pro provedení transakce. Podívejme se na prozatím velmi jednoduchou transakci, která odpovídá demonstračnímu příkladu, s nímž jsme se seznámili v šestnácté kapitole (jednalo se o převod peněžní částky mezi dvěma účty):

>>> r.set("ucet1", 1000.0)
True
 
>>> r.set("ucet2", 0.0)
True
 
>>> pipe = r.pipeline(transaction=True)
 
>>> pipe.incrbyfloat("ucet1", -150.50)
Pipeline<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>
 
>>> pipe.incrbyfloat("ucet2", 150.50)
Pipeline<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>
 
>>> pipe.execute()
[849.5, 150.5]
 
>>> r.get("ucet1")
b'849.5'
 
>>> r.get("ucet2")
b'150.5'

20. Odkazy na Internetu

  1. Stránky projektu Redis
    https://redis.io/
  2. Introduction to Redis
    https://redis.io/topics/introduction
  3. Try Redis
    http://try.redis.io/
  4. Redis tutorial, April 2010 (starší, ale pěkně udělaný)
    https://static.simonwilli­son.net/static/2010/redis-tutorial/
  5. Python Redis
    https://redislabs.com/lp/python-redis/
  6. Redis: key-value databáze v paměti i na disku
    https://www.zdrojak.cz/clanky/redis-key-value-databaze-v-pameti-i-na-disku/
  7. Praktický úvod do Redis (1): vaše distribuovaná NoSQL cache
    http://www.cloudsvet.cz/?p=253
  8. Praktický úvod do Redis (2): transakce
    http://www.cloudsvet.cz/?p=256
  9. Praktický úvod do Redis (3): cluster
    http://www.cloudsvet.cz/?p=258
  10. Connection pool
    https://en.wikipedia.org/wi­ki/Connection_pool
  11. Instant Redis Sentinel Setup
    https://github.com/ServiceStack/redis-config
  12. How to install REDIS in LInux
    https://linuxtechlab.com/how-install-redis-server-linux/
  13. Redis RDB Dump File Format
    https://github.com/sripat­hikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format
  14. Lempel–Ziv–Welch
    https://en.wikipedia.org/wi­ki/Lempel%E2%80%93Ziv%E2%80%93­Welch
  15. Redis Persistence
    https://redis.io/topics/persistence
  16. Redis persistence demystified
    http://oldblog.antirez.com/post/redis-persistence-demystified.html
  17. Redis reliable queues with Lua scripting
    http://oldblog.antirez.com/post/250
  18. Ost (knihovna)
    https://github.com/soveran/ost
  19. NoSQL
    https://en.wikipedia.org/wiki/NoSQL
  20. Shard (database architecture)
    https://en.wikipedia.org/wi­ki/Shard_%28database_archi­tecture%29
  21. What is sharding and why is it important?
    https://stackoverflow.com/qu­estions/992988/what-is-sharding-and-why-is-it-important
  22. What Is Sharding?
    https://btcmanager.com/what-sharding/
  23. Redis clients
    https://redis.io/clients
  24. Category:Lua-scriptable software
    https://en.wikipedia.org/wi­ki/Category:Lua-scriptable_software
  25. Seriál Programovací jazyk Lua
    https://www.root.cz/seria­ly/programovaci-jazyk-lua/
  26. Redis memory usage
    http://nosql.mypopescu.com/pos­t/1010844204/redis-memory-usage
  27. Ukázka konfigurace Redisu pro lokální testování
    https://github.com/tisnik/pre­sentations/blob/master/re­dis/redis.conf
  28. Resque
    https://github.com/resque/resque
  29. Nested transaction
    https://en.wikipedia.org/wi­ki/Nested_transaction
Našli jste v článku chybu?