Hlavní navigace

Využití Redisu z jazyka Clojure pomocí knihovny Carmine (dokončení)

3. 2. 2022
Doba čtení: 29 minut

Sdílet

 Autor: Clojure
Na úvodní článek o knihovně Carmine, která umožňuje používat Redis v aplikacích naprogramovaných v Clojure, dnes navážeme. Ukážeme si mj. i komunikaci založenou na strategii publish-subscribe a taktéž použití front zpráv (queues).

Obsah

1. Využití Redisu z jazyka Clojure pomocí knihovny Carmine (dokončení)

2. Množiny

3. Základní operace s množinami prováděné z knihovny Carmine

4. Množinové operace: sjednocení, průnik, rozdíl

5. Množinové operace prováděné z jazyka Clojure

6. Mapy (asociativní pole)

7. Práce s mapami v jazyku Clojure

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

9. Uspořádané množiny a jazyk Clojure

10. Komunikační strategie publish-subscribe

11. Program konzumující zprávy (subscriber)

12. Program produkující zprávy (publisher)

13. Použití front pro komunikaci

14. Implementace workera přijímacího úkoly přes frontu

15. Klient vytvářející zprávy pro workery

16. Seznam popsaných maker a funkcí knihovny Carmine

17. Repositář s demonstračními příklady

18. Předchozí články o systému Redis

19. Odkazy na předchozí části seriálu o programovacím jazyku Clojure

20. Odkazy na Internetu

1. Využití Redisu z jazyka Clojure pomocí knihovny Carmine (dokončení)

V úvodním článku jsme se seznámili s tím, jakým způsobem je možné vyvinout aplikace v programovacím jazyku Clojure, které komunikují s databází Redis. Pro tento účel jsme použili knihovnu Carmine. Prozatím víme, jakým způsobem se do Redisu ukládají jednotlivé hodnoty pod určitým klíčem (přičemž hodnotou může být řetězec, ale i celý serializovaný objekt). Taktéž jsme si ukázali základní operace se seznamy, které mohou být ve skutečnosti použity i ve funkci zásobníků popř. front. Dnes si popíšeme další datové typy podporované Redisem, zejména mapy (asociativní pole), množiny a takzvané uspořádané množiny. Ve druhé části článku si na několika demonstračních příkladech ukážeme způsob použití komunikačních strategií publish-subscribe i využití front zpráv (queue).

2. Množiny

Kromě datových typů popsaných minule (tedy řetězců a seznamů, přičemž řetězce mohou ve skutečnosti obsahovat čísla či serializované objekty) lze v Redisu pracovat i s dalšími datovými typy (a každý z nich se pochopitelně hodí pro jiné účely). Třetím datovým typem, s nímž je možné v Redisu pracovat a s nímž se ve stručnosti seznámíme, jsou množiny (sets). Každá množina může obsahovat až 232-1 prvků, což je stejná maximální kapacita prvků, jako u seznamů. Prvky se do množiny přidávají příkazem sadd (neboli set add), přičemž je nutné uvést jak jméno (identifikátor) množiny, tak i hodnotu vkládaného prvku. V případě, že množina daného jména 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
Poznámka: vrácená hodnota 1 oznamuje počet prvků vložených do množiny. V případě potřeby lze jednou operací sadd vložit větší množství prvků, ovšem pokud prvek/prvky již v množině existují, nebudou do výsledku započteny. V limitním případě se tak může vrátit i nula.

Celkový počet prvků uložených 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 sismember, 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"

Vzhledem k tomu, že se jedná o skutečné množiny, je ošetřen i případ, kdy se do množiny vkládá více stejných prvků:

127.0.0.1:6379> sadd mnozina 1
(integer) 1
 
127.0.0.1:6379> sadd mnozina 2
(integer) 1
 
127.0.0.1:6379> sadd mnozina 1
(integer) 0
Poznámka: poslední nula vrácená Redisem značí, že prvek 1 již nebyl do množiny vložen, neboť v ní již existuje.

3. Základní operace s množinami prováděné z knihovny Carmine

Všechny operace s množinami, které jsme si popsali ve druhé kapitole jsou pochopitelně podporovány i knihovnou Carmine. Ukázány jsou v následujícím demonstračním příkladu. Povšimněte si, že se (do značné míry) jedná o idiomatický kód programovacího jazyka Clojure, protože namísto textových literálů používáme „keywords“, tedy symboly, které jsou ve všech jmenných prostorech unikátní a jsou interně reprezentovány referencí a nikoli hodnotou (tedy nezáleží na délce symbolu):

(ns carmine8.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
 
(defn -main
  [& args]
  (println "Working with two sets")
 
  (println "Set s1")
  (println
    (wcar*
      (carmine/sadd :s1 :a)
      (carmine/sadd :s1 :b)
      (carmine/sadd :s1 :c)
      (carmine/sadd :s1 :d)
      (carmine/smembers :s1)
      (carmine/scard :s1)))
 
  (println "Set s2")
  (println
    (wcar*
      (carmine/sadd :s2 :c :d :e :f)
      (carmine/smembers :s2)
      (carmine/scard :s1)))
 
  (println "Done"))

Po spuštění tohoto příkladu se mj. vypíšou i dva vektory:

Working with two sets
Set s1
[1 1 1 1 [c d b a] 4]
Set s2
[4 [f e c d] 4]
Done

První vektor obsahuje postupně výsledek čtyř operací sadd, následně prvky množiny :s1 a konečně počet prvků množiny. Druhý vektor obsahuje výsledek operace sadd, která vložila čtyři prvky, následně prvky množiny :s2 a nakonec taktéž počet prvků této množiny.

4. Množinové operace: sjednocení, průnik, rozdíl

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

Před ukázkou základního způsobu použití těchto operací si vytvoříme dvě množiny s identifikátory s1 a s2.

Naplnění množiny s1 čtyřmi prvky:

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 taktéž čtyřmi prvky (ovšem částečně odlišnými od množiny s1):

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

Pro jistotu si vypíšeme aktuální 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 (union). Následně zkontrolujeme výsledek:

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 s využitím operace průniku (intersection):

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 (difference). Tato operace není komutativní, takže je pochopitelně výsledek jiný při provedení rozdílu 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"
Poznámka: použít lze i příkazy sunion, sinter a sdiff, které taktéž provedou sjednocení, průnik či rozdíl množin, ale výsledek je v tomto případě pouze poslán uživateli a není uložen zpět do Redisu.

5. Množinové operace prováděné z jazyka Clojure

Opět platí, že všechny výše popsané a otestované množinové operace můžeme provádět z programovacího jazyka Clojure s využitím knihovny Carmine. Ukažme si nejdříve operace, u nichž se výsledek ukládá zpět do Redisu do nové množiny, tedy operace, jejichž jméno končí na „store“:

(ns carmine9.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
 
(defn -main
  [& args]
  (println "Working with two sets")
  (println "Fill in sets s1 and s2")
 
  (println
    (wcar*
      (carmine/srem :s1 :a :b :c :d :e :f)
      (carmine/srem :s2 :a :b :c :d :e :f)
      (carmine/sadd :s1 :a :b :c :d)
      (carmine/sadd :s2 :c :d :e :f)
      (carmine/smembers :s1)
      (carmine/smembers :s2)))
 
  (println "Set operations")
 
  (println "union")
  (println
    (wcar*
      (carmine/sunionstore :s3 :s1 :s2)
      (carmine/smembers :s3)))
 
  (println "intersection")
  (println
    (wcar*
      (carmine/sinterstore :s4 :s1 :s2)
      (carmine/smembers :s4)))
 
  (println "diff")
  (println
    (wcar*
      (carmine/sdiffstore :s5 :s1 :s2)
      (carmine/smembers :s5)
      (carmine/sdiffstore :s6 :s2 :s1)
      (carmine/smembers :s6)))
 
  (println "Done"))

Po spuštění tohoto demonstračního příkladu získáme sérii vektorů, přičemž u zvýrazněných vektorů je zobrazen počet prvků ve výsledné množině, za nímž následuje seznam těchto prvků:

Working with two sets
Fill in sets s1 and s2
[0 0 4 4 [d b a c] [f d e c]]
Set operations
 
union
[6 [c d b f a e]]
 
intersection
[2 [d c]]
 
diff
[2 [b a] 2 [f e]]
 
Done

Podobným způsobem je možné použít i množinové operace, jejichž výsledkem je množina vrácená uživateli (ale neukládaná zpět do Redisu):

(ns carmineA.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
 
(defn -main
  [& args]
  (println "Working with two sets")
  (println "Fill in sets s1 and s2")
 
  (println
    (wcar*
      (carmine/srem :s1 :a :b :c :d :e :f)
      (carmine/srem :s2 :a :b :c :d :e :f)
      (carmine/sadd :s1 :a :b :c :d)
      (carmine/sadd :s2 :c :d :e :f)
      (carmine/smembers :s1)
      (carmine/smembers :s2)))
 
  (println "Set operations")
 
  (println "union")
  (println
    (wcar*
      (carmine/sunion :s1 :s2)))
 
  (println "intersection")
  (println
    (wcar*
      (carmine/sinter :s1 :s2)))
 
  (println "diff")
  (println
    (wcar*
      (carmine/sdiff :s1 :s2)
      (carmine/sdiff :s2 :s1)))
 
  (println "Done"))

Výsledek získaný po spuštění tohoto demonstračního příkladu. Výsledky množinových operací jsou opět zvýrazněny:

Working with two sets
Fill in sets s1 and s2
[0 0 4 4 [c a d b] [f c e d]]
Set operations
 
union
[c a e d b f]
 
intersection
[c d]
 
diff
[[a b] [f e]]
 
Done
Poznámka: poslední vektor obsahuje dva výsledky; konkrétně výsledky rozdílu s1\s2 a s2\s1:

6. Mapy (asociativní pole)

Jedním z nejpoužívanějších datových typů v systému Redis 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 určený 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 dvojice hset/hmset 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). Tyto operace si snadno odzkoušíme přímo z konzole Redisu:

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 operací hset:

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"

7. Práce s mapami v jazyku Clojure

Příkazy, které byly otestovány v konzoli Redisu, si můžeme vyzkoušet i přímo v programovacím jazyce Clojure. Vzhledem k tomu, že hodnoty prvků jsou serializovány knihovnou Nippy (viz úvodní článek) je v dalším demonstračním příkladu ukázáno použití prvků různých typů, konkrétně seznamů, vektorů, ale i množin či map (přesněji řečeno množin a map v kontextu jazyka Clojure, který tyto datové typy plně podporuje):

(ns carmineB.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]
            [clojure.pprint :as pprint]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
 
(defn -main
  [& args]
  (println "Working with maps")
 
  (println "hset operation")
  (println
    (wcar*
      (carmine/hset :m1 :foo :bar)
      (carmine/hset :m1 :bar :baz)
      (carmine/hset :m1 "result" 1/3)
      (carmine/hset :m1 "more-complicated" [1 2 3])
      (carmine/hset :m1 :boolean   true)
      (carmine/hset :m1 :nil-value nil)
      (carmine/hset :m1 :text      "Hello world!")
      (carmine/hset :m1 :list      '(1 2 3))
      (carmine/hset :m1 :vector    [1 2 3])
      (carmine/hset :m1 :a-set     #{1 2 3 4})
      (carmine/hset :m1 :map {:name    "foo"
                              :surname "bar"
                         })))
 
  (println "hget operation")
  (println
    (wcar*
      (carmine/hget :m1 :foo)
      (carmine/hget :m1 :bar)
      (carmine/hget :m1 :baz)
      (carmine/hget :m1 "result")
      (carmine/hget :m1 "more-complicated")
      (carmine/hget :m1 :unknown)))
 
 
  (println "hgetall operation")
  (pprint/pprint
    (wcar*
      (carmine/hgetall :m1)))
 
  (println "Done"))

Po spuštění tohoto příkladu se nejprve prvky do mapy uloží a následně zase přečtou a vypíšou na terminál:

Working with maps
 
hset operation
[1 1 1 1 1 1 1 1 1 1 1]
 
hget operation
[bar baz nil 1/3 [1 2 3] nil]
 
hgetall operation
["foo"
 "bar"
 "bar"
 "baz"
 "result"
 1/3
 "more-complicated"
 [1 2 3]
 "boolean"
 true
 "nil-value"
 nil
 "text"
 "Hello world!"
 "list"
 (1 2 3)
 "vector"
 [1 2 3]
 "a-set"
 #{1 4 3 2}
 "map"
 {:name "foo", :surname "bar"}]
 
Done
Poznámka: povšimněte si, že příkaz hset vrací počet prvků vložených do mapy. Pokud se provedlo více těchto operací současně v rámci makra wcar*, vrátí se vektor těchto hodnot:
hset operation
[1 1 1 1 1 1 1 1 1 1 1]

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

Posledním datovým typem Redisu, o kterém se v dnešním článku zmíníme, jsou množiny s ohodnocenými prvky. V tomto datovém typu (kontejneru) je každému prvku 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. To se hodí například při implementaci prioritních front 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 (ohodnocení) 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í je možné změnit příkazem zincrby, kterému se zadá relativní přírůstek (samozřejmě může být i záporný a opět se nemusí jednat o celé číslo):

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

Nad uspořádanými množinami je možné provádět i některé 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 (opět užitečné při implementaci některých variant prioritních front):

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> zremrangebyscore set 1 200
(empty list or set)

9. Uspořádané množiny a jazyk Clojure

I manipulace s uspořádanými množinami je podle očekávání podporovaná knihovnou Carmine a tím pádem dostupná pro aplikace naprogramované v Clojure. Základní operace jsou ukázány v dalším demonstračním příkladu. Funkce a makra definovaná v knihovně Carmine odpovídají přímo protokolu Redisu (ostatně jedná se o generovaná jména, takže je plná kompatibilita Carmine-Redis zaručena automaticky):

(ns carmineC.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]
            [clojure.pprint :as pprint]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
 
(defn -main
  [& args]
  (println "Working with sorted sets")
 
  (println "Fill in sorted set s1")
  (println
    (wcar*
      (carmine/zadd :s1 0.9 :a)
      (carmine/zadd :s1 0.8 :b)
      (carmine/zadd :s1 0.7 :c)
      (carmine/zadd :s1 0.6 :d)))
 
  (println "Retrieving items from sorted set s1")
  (println
    (wcar*
      (carmine/zcard :s1)
      (carmine/zrangebyscore :s1 0 100)
      (carmine/zrangebyscore :s1 0.65 0.85)))
 
  (println "Done"))

Po spuštění tohoto demonstračního příkladu získáme následující informace:

Working with sorted sets
Fill in sorted set s1
[1 1 1 1]
Retrieving items from sorted set s1
[4 [d c b a] [c b]]
Done

Důležiý je především výpis prvků s ohonocením 0..100 a poté 0.65 až 0.85:

[d c b a]
[c b]

10. Komunikační strategie publish-subscribe

Jedna z velmi užitečných technologií, kterou najdeme v Redisu, je technologie implementující paradigma publish-subscribe (nebo též publisher-subscriber). Jedná se o jednu z forem posílání zpráv mezi několika subsystémy, které tak mohou pracovat relativně samostatně, mohou být nakonfigurovány a administrovány nezávisle na sobě a případná změna architektury může být snadnější, než kdyby byly tyto subsystémy propojeny přímo (například přes nějaké binární API). V praxi se setkáme jak s paradigmatem pojmenovaným publish-subscribe, tak i s frontami zpráv (message queues), ovšem mezi oběma technologiemi existuje několik rozdílů a každá se proto používá k odlišným účelům.

Nejprve se budeme zabývat komunikační strategií publish-subscribe. Mezi vlastnosti této komunikační strategie patří:

  1. Existuje jeden či několik zdrojů zpráv.
  2. Příjemců může být taktéž více, zpráva je doručena všem příjemcům, kteří se k odběru přihlásili.
  3. Pořadí zpráv je zaručeno.
  4. Většinou není zaručeno zpracování a ani přijetí zprávy (pokud se například příjemce odpojí, zbytku „pipeline“ to nevadí).

Toto paradigma se může použít například při implementaci různých komunikačních systémů atd. Příkladem může být chat, kde záleží na pořadí doručení zpráv a příjemců je většinou větší množství. Popř. se tato strategie používá v IoT, kde je důležité poslat (a přijmout) aktuální data a nikoli sledovat minulé hodnoty.

V Redisu nalezneme následujících šest příkazů, kterými je implementována komunikační strategie publish-subscribe:

Příkaz Stručný popis příkazu
SUBSCRIBE přihlášení se k odebírání jednoho kanálu nebo většího množství kanálů
UNSUBSCRIBE opak předchozího, odhlášení se z odebírání specifikovaných kanálů (popř. ze všech kanálů)
   
PSUBSCRIBE odpovídá SUBSCRIBE, ovšem pro jméno kanálu lze použít žolíkové znaky
PUNSUBSCRIBE odpovídá UNSUBSCRIBE, ovšem pro jméno kanálu lze použít žolíkové znaky
   
PUBLISH publikování zprávy do zvoleného kanálu
   
PUBSUB získání podrobnějších informací o stavu kanálů, přihlášených odebíratelů zpráv atd.

U příkazů psubscribe a punsubscribe je možné ve jménu kanálu používat takzvané žolíkové znaky, které s velkou pravděpodobností znáte například z BASHe při specifikaci souborů. Mezi tyto znaky patří především hvězdička (nahrazuje libovolně dlouhou sekvenci znaků), otazník (nahrazuje jeden libovolný znak) a zápis množiny znaků: [znaky]. Žolíkové znaky se odlišují od zápisu regulárních výrazů především v tom, že „*“ a „?“ před sebou neobsahují specifikaci, jakých znaků se náhrada týká (tj. nepíše se například „.*“ ale jen „*“). Více informací je uvedeno například na stránce https://en.wikipedia.org/wi­ki/Glob_(programming).

Poznámka: protokol používaný Redisem je většinou založen na té nejjednodušší možné komunikaci typu dotaz-odpověď. To znamená, že každý příkaz poslaný klientem na server je následován odpovědí serveru zpět klientovi. Typicky jsou buď klientovi poslána data nebo alespoň celočíselná hodnota 0 nebo 1 reprezentující úspěch popř. neúspěch příkazu. Existují však tři výjimky, kdy se dotaz-odpověď nepoužívá. První výjimkou jsou takzvané pipeline, kdy klient zasílá více příkazů v jednom balíčku. Druhou výjimkou je právě použití Pub/Sub kanálů, protože v této chvíli se začne používat push protokol – server sám začíná posílat zprávy ve chvíli, kdy jsou publikovány nějakým jiným klientem. Třetí výjimka se objevila v páté verzi Redisu a souvisí se streamy a příkazem XREAD. Popisem streamů se však dnes zabývat nebudeme.

11. Program konzumující zprávy (subscriber)

Vytvoření samotného konzumenta zpráv v jazyce Clojure je ve skutečnosti poměrně triviální. Postačuje totiž použít makro with-new-pubsub-listener, v němž se uvede seznam kanálů (resp. jejich jmen) a funkce, která se má zavolat ve chvíli, kdy je do daného kanálu poslána zpráva. Například pro kanál pojmenovaný „events“ můžeme takovou (anonymní) funkci definovat následovně:

{"events" (fn f [event] (println "Received event" event))}

Konzument ovšem může přijímat zprávy z většího množství kanálů:

{"kanál1" (fn f [event] (println "Received event" event))}
{"kanál2" (fn f [event] (println "Received event" event))}
{"kanál3" (fn f [event] (println "Received event" event))}

Popř.:

{"kanál*" (fn f [event] (println "Received event" event))}

Podívejme se nyní na úplný zdrojový kód konzumenta zpráv:

(ns carmineD.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]
            [clojure.pprint :as pprint]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
(defn -main
  [& args]
  (println "Listener to given channel")
 
  (carmine/with-new-pubsub-listener
    (:spec redis-connection)
    {"events" (fn f [event] (println "Received event" event))}
    (carmine/subscribe "events")))

12. Program produkující zprávy (publisher)

Následující program po svém spuštění vytvoří sto zpráv, které budou poslány do kanálu „events“. V případě, že bude současně spuštěný i předchozí příklad, budou zprávy přijaty, v opačném případě zahozeny:

(ns carmineE.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
(defn -main
  [& args]
  (println "Publisher")
 
  (doseq [i (range 100)]
    (println i)
    (println (wcar* (carmine/publish "events" (* i 100))))))
Poznámka: sami si vyzkoušejte, jak bude situace vypadat ve chvíli, kdy se spustí větší množství producentů zpráv popř. větší množství konzumentů – vše za předpokladu, že se použije shodné jméno komunikačního kanálu.

13. Použití front pro komunikaci

Knihovna Carmine obsahuje podporu pro tvorbu aplikací, které spolu komunikují přes fronty zpráv. V dalších dvou kapitolách si ukážeme jak producenta, tak i konzumenta takto posílaných zpráv, ovšem nejprve si připomeňme typické vlastnosti front zpráv (které se v některých ohledech liší od komuniační strategie publish-subscribe):

  1. Existuje jeden či několik zdrojů zpráv.
  2. Příjemců může být taktéž více, ovšem zpráva je typicky získána jen jedním z nich (příjemci se tedy o zprávy dělí).
  3. Obecně není zaručeno pořadí doručení zpráv.
  4. Zpráva je zpracována jen jedenkrát, ovšem pokud ji příjemce nezpracuje, může být doručena dalšímu příjemci.
  5. Volitelná vlastnost související s předchozím bodem: po nezpracování se zpráva vrací zpět do fronty.

Fronty zpráv se používají velmi často například ve chvíli, kdy se zpracovávají různé transakce, u nichž není nutné, aby jejich výsledek uživatel viděl v reálném čase. Do fronty se pouze uloží všechny informace o tom, jaká transakce se má provést a později si tuto operaci z fronty vyzvedne nějaký „worker“.

Alternativně lze fronty zpráv obecně využít pro dělbu práce mezi větším množstvím „workerů“, kteří mohou být vhodným způsobem naškálovány, mohou se zapnout v době, kdy je volný strojový čas atd.

14. Implementace workera přijímacího úkoly přes frontu

Ukažme si nyní, jak snadné je vytvoření workera, který přijímá úkoly přes frontu, konkrétně přes frontu nazvanou „task-queue“. Povšimněte si, že při přijetí zprávy se zavolá takzvaný handler, což je v našem případě anonymní funkce. Důležité je, aby tato funkce potvrdila přijetí zprávy tím, že vrátí hodnotu {:status :success}:

(fn [{:keys [message attempt]}]
    (println "Received" message)
    {:status :success})

Samotná obsluha fronty je v balíčku taoensso.carmine.message-queue, což znamená odlišnou hlavičku programu:

(ns carmineF.core
  (:require [taoensso.carmine.message-queue :as car-mq]))

Podívejme se nyní na úplný zdrojový kód workera:

(ns carmineF.core
  (:require [taoensso.carmine.message-queue :as car-mq]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
(defn -main
  [& args]
  (println "Worker")
 
  (car-mq/worker {:spec redis-connection} "task-queue"
   {:handler (fn [{:keys [message attempt]}]
               (println "Received" message)
               {:status :success})})
 
  ;(car-mq/stop my-worker)
)
Poznámka: forma car-mq/stop by se měla zavolat ve chvíli, kdy již klient nepotřebuje s frontou pracovat. V našem konkrétním případě však k zavolání této formy stejně nedojde, takže je zakomentována.

15. Klient vytvářející zprávy pro workery

Zprávy posílané do fronty „task-queue“ můžeme pochopitelně vytvářet přímo v řádkovém klientu Redisu (redis-cli), ovšem pochopitelně je možné pro tento účel opět použít aplikaci naprogramovanou v jazyku Clojure. Po spuštění následujícího skriptu se do fronty „task-queue“ vloží sto zpráv, které mohou být kdykoli později přečteny:

DT24

(ns carmineG.core
  (:require [taoensso.carmine :as carmine :refer (wcar)]
            [taoensso.carmine.message-queue :as car-mq]))
 
 
(def redis-connection {
  :pool {}
  :spec {
    :uri "redis://localhost@127.0.0.1:6379"}})
 
 
(defmacro wcar*
  [& body]
  `(carmine/wcar redis-connection ~@body))
 
(defn -main
  [& args]
  (println "")
 
  (doseq [i (range 100)]
    (println i)
    (println (wcar* (car-mq/enqueue "task-queue" (* i 100))))))
Poznámka: opět si vyzkoušejte paralelní spuštění většího množství workerů popř. i producentů zpráv, aby bylo zřejmé, jakým způsobem komunikace přes fronty reálně probíhá.

16. Seznam popsaných maker a funkcí knihovny Carmine

Makro/funkce Oblast/typ Stručný popis
ping komunikační protokol dotaz, zda je Redis připraven
pong komunikační protokol odpověď Redisu na příkaz ping
info komunikační protokol dotaz na vlastnosti Redisu
type komunikační protokol získání typu prvky
     
set řetězce uložení řetězce nebo serializovaného objektu
get řetězce načtení řetězce nebo serializovaného objektu
     
incr numerické hodnoty změna uložené hodnoty o jedničku
incrby numerické hodnoty změna uložené hodnoty
decr numerické hodnoty změna uložené hodnoty o jedničku
decrby numerické hodnoty změna uložené hodnoty
incrbyfloat numerické hodnoty změna uložené hodnoty
     
lpush seznamy přidání prvku na začátek seznamu
rpush seznamy přidání prvku na konec seznamu
lpop seznamy přečtení prvního prvku ze seznamu s jeho odstraněním
rpop seznamy přečtení posledního prvku ze seznamu s jeho odstraněním
lset seznamy změna hodnoty prvku na určeném indexu v seznamu
lindex seznamy přečtení prvku se zadaným indexem
linsert seznamy přidání prvku na určený index seznamu (s posunem dalších prvků)
llen seznamy přečtení délky seznamu
     
sadd množiny přidání prvku či prvků do množiny
scard množiny získání počtu prvků množiny
smembers množiny přečtení prvků z množiny
sismember množiny test existence prvku
srem množiny odstranění prvku z množiny
sunion množiny množinové sjednocení bez uložení výsledků
sinter množiny množinový průnik bez uložení výsledků
sdiff množiny množinový rozdíl bez uložení výsledků
sunionstore množiny množinové sjednocení s uložením výsledků
sinterstore množiny množinový průnik s uložením výsledků
sdiffstore množiny množinový rozdíl s uložením výsledků
     
hset mapy vložení prvku do mapy
hget mapy přečtení prvku z mapy
hmset mapy vložení více prvků do mapy
hgetall mapy přečtení všech prvků z mapy
     
zadd množiny s ohodnocenými prvky přidání prvku
zrank množiny s ohodnocenými prvky pořadí prvku
zcard množiny s ohodnocenými prvky počet prvků v množině
zcount množiny s ohodnocenými prvky počet prvků s ohodnocením x až y
zincrby množiny s ohodnocenými prvky změna ohodnocení prvku
zrangebyscore množiny s ohodnocenými prvky prvky s ohodnocením x až y
zremrangebyscore množiny s ohodnocenými prvky odstranění prvků s ohodnocením x až y

17. Repositář s demonstračními příklady

Všechny minule i dnes popsané demonstrační příklady byly uloženy do repositáře dostupného na adrese https://github.com/tisnik/clojure-examples/. V tabulce umístěné pod tímto odstavcem jsou uvedeny odkazy na tyto příklady (vždy se přitom jedná o plnohodnotný projekt vyžadující jak samotný jazyk Clojure, tak i Leiningen a pochopitelně i virtuální stroj Javy):

# Projekt Popis projektu Cesta
1 carmine1 připojení k Redisu, poslání zprávy PING a obdržení zprávy PONG https://github.com/tisnik/clojure-examples/tree/master/carmine1
2 carmine2 pomocné makro wcar* vytvořené pro každé připojení k Redisu https://github.com/tisnik/clojure-examples/tree/master/carmine2
3 carmine3 alternativní způsob definice připojení k Redisu https://github.com/tisnik/clojure-examples/tree/master/carmine3
4 carmine4 uložení řetězce a zpětné přečtení řetězce realizované v Clojure https://github.com/tisnik/clojure-examples/tree/master/carmine4
5 carmine5 využití příkazu incr https://github.com/tisnik/clojure-examples/tree/master/carmine5
6 carmine6 uložení strukturovaných dat do Redisu https://github.com/tisnik/clojure-examples/tree/master/carmine6
7 carmine7 manipulace se seznamy uloženými v Redisu https://github.com/tisnik/clojure-examples/tree/master/carmine7
       
8 carmine8 základní operace s množinami https://github.com/tisnik/clojure-examples/tree/master/carmine8
9 carmine9 množinové operace s uložením výsledku do nové množiny https://github.com/tisnik/clojure-examples/tree/master/carmine9
10 carmineA množinové operace s posláním výsledku bez ukládání https://github.com/tisnik/clojure-examples/tree/master/carmineA
11 carmineB práce s mapami https://github.com/tisnik/clojure-examples/tree/master/carmineB
12 carmineC práce s uspořádanými množinami https://github.com/tisnik/clojure-examples/tree/master/carmineC
13 carmineD komunikace typu pub-sub: příjemce zpráv https://github.com/tisnik/clojure-examples/tree/master/carmineD
14 carmineE komunikace typu pub-sub: odesílatel zpráv https://github.com/tisnik/clojure-examples/tree/master/carmineE
15 carmineF komunikace přes frontu (queue): implementace workera https://github.com/tisnik/clojure-examples/tree/master/carmineF
16 carmineG komunikace přes frontu (queue): tvorba úloh pro workery https://github.com/tisnik/clojure-examples/tree/master/carmineG

18. Předchozí články o systému Redis

Se systémem Redis jsme se již na stránkách Rootu setkali, a to dokonce několikrát. Buď jsme si popisovali přímo přístup k Redisu z různých programovacích jazyků (což je konkrétně případ všech dále zmíněných článků zaměřených na jazyky Python a Go) nebo byl Redis použit ve funkci databáze resp. perzistentního úložiště různými message brokery (Celery, RQ, apod.). Poslední dva články pak popisují problematiku proudů v systému Redis:

  1. Databáze Redis (nejenom) pro vývojáře používající Python
    https://www.root.cz/clanky/databaze-redis-nejenom-pro-vyvojare-pouzivajici-python/
  2. Databáze Redis (nejenom) pro vývojáře používající Python (dokončení)
    https://www.root.cz/clanky/databaze-redis-nejenom-pro-vyvojare-pouzivajici-python-dokonceni/
  3. Použití databáze Redis v aplikacích naprogramovaných v Go
    https://www.root.cz/clanky/pouziti-databaze-redis-v-aplikacich-naprogramovanych-v-go/
  4. Použití databáze Redis v aplikacích naprogramovaných v Go (2)
    https://www.root.cz/clanky/pouziti-databaze-redis-v-aplikacich-naprogramovanych-v-go-2/
  5. Použití nástroje RQ (Redis Queue) pro správu úloh zpracovávaných na pozadí
    https://www.root.cz/clanky/pouziti-nastroje-rq-redis-queue-pro-spravu-uloh-zpracovavanych-na-pozadi/
  6. Proudy (streams) podporované systémem Redis
    https://www.root.cz/clanky/proudy-streams-podporovane-systemem-redis/
  7. Proudy (streams) podporované systémem Redis (dokončení)
    https://www.root.cz/clanky/proudy-streams-podporovane-systemem-redis-dokonceni/

19. Odkazy na předchozí části seriálu o programovacím jazyku Clojure

  1. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  2. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  3. Clojure 3: Funkcionální programování
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/
  4. Clojure 4: Kolekce, sekvence a lazy sekvence
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/
  5. Clojure 5: Sekvence, lazy sekvence a paralelní programy
    http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/
  6. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  7. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  8. Clojure 8: Identity, stavy, neměnné hodnoty a reference
    http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/
  9. Clojure 9: Validátory, pozorovatelé a kooperace s Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/
  10. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  11. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  12. Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
    http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/
  13. Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
    http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/
  14. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  15. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  16. Programovací jazyk Clojure – triky při práci s řetězci
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/
  17. Programovací jazyk Clojure – triky při práci s kolekcemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/
  18. Programovací jazyk Clojure – práce s mapami a množinami
    http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/
  19. Programovací jazyk Clojure – základy zpracování XML
    http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/
  20. Programovací jazyk Clojure – testování s využitím knihovny Expectations
    http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/
  21. Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
    http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/
  22. Enlive – výkonný šablonovací systém pro jazyk Clojure
    http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/
  23. Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
    http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/
  24. Novinky v Clojure verze 1.8.0
    http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/
  25. Asynchronní programování v Clojure s využitím knihovny core.async
    http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/
  26. Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
    http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/
  27. Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
    http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/
  28. Vytváříme IRC bota v programovacím jazyce Clojure
    http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/
  29. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  30. Multimetody v Clojure aneb polymorfismus bez použití OOP
    https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/
  31. Práce s externími Java archivy v programovacím jazyku Clojure
    https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/
  32. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  33. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  34. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  35. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  36. Clojure 20: Vývojová prostředí pro Clojure (Vim s REPL)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/
  37. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
  38. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  39. Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/
  40. Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/
  41. Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/
  42. Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/
  43. Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/
  44. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  45. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/
  46. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  47. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/
  48. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/
  49. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/
  50. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  51. Seesaw: knihovna pro snadnou tvorbu GUI v azyce Clojure (2)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/
  52. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/
  53. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  54. Programovací jazyk Clojure a práce s Gitem (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
  55. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/
  56. Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
    https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/
  57. Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
    https://www.root.cz/clanky/pro­gramovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/
  58. Novinky v Clojure verze 1.9.0
    https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/
  59. Validace dat s využitím knihovny spec v Clojure 1.9.0
    https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/
  60. Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
    https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/
  61. Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
    https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/
  62. Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
    https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/
  63. Incanter: operace s maticemi
    https://www.root.cz/clanky/incanter-operace-s-maticemi/
  64. Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
    https://www.root.cz/clanky/interpret-programovaciho-jazyka-clojure-integrovany-do-jupyter-notebooku/
  65. Babashka: interpret Clojure určený pro rychlé spouštění utilit z příkazového řádku
    https://www.root.cz/clanky/babashka-interpret-clojure-urceny-pro-rychle-spousteni-utilit-z-prikazoveho-radku/
  66. Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw
    https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw/
  67. Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw (2. část)
    https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw-2-cast/
  68. Pokročilý streaming založený na projektu Apache Kafka, jazyku Clojure a knihovně Jackdaw (streamy a kolony)
    https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-projektu-apache-kafka-jazyku-clojure-a-knihovne-jackdaw-streamy-a-kolony/
  69. Řídicí struktury využitelné v programovacím jazyku Clojure
    https://www.root.cz/clanky/ridici-struktury-vyuzitelne-v-programovacim-jazyku-clojure/
  70. Řídicí struktury využitelné v programovacím jazyku Clojure (dokončení)
    https://www.root.cz/clanky/ridici-struktury-vyuzitelne-v-programovacim-jazyku-clojure-dokonceni/
  71. Formát EDN: extensible data notation
    https://www.root.cz/clanky/format-edn-extensible-data-notation/
  72. Formát EDN: extensible data notation (dokončení)
    https://www.root.cz/clanky/format-edn-extensible-data-notation-dokonceni/
  73. Čtyři různé podoby datové struktury map v programovacím jazyku Clojure
    https://www.root.cz/clanky/ctyri-ruzne-podoby-datove-struktury-map-v-programovacim-jazyku-clojure/
  74. Programová tvorba diagramů v jazyku Clojure s využitím knihovny Rhizome
    https://www.root.cz/clanky/programova-tvorba-diagramu-v-jazyku-clojure-s-vyuzitim-knihovny-rhizome/
  75. Využití Redisu z jazyka Clojure pomocí knihovny Carmine
    https://www.root.cz/clanky/vyuziti-redisu-z-jazyka-clojure-pomoci-knihovny-carmine/

20. Odkazy na Internetu

  1. Carmine: a pure-Clojure Redis client & message queue
    https://github.com/ptaoussa­nis/carmine
  2. Redis streams and Clojure
    https://tirkarthi.github.i­o/programming/2018/08/17/re­dis-streams-clojure.html
  3. Clojure Redis using Carmine
    https://clojure.tgenedavis.com/clojure-redis-using-carmine/
  4. Clojure with a Touch of Redis
    https://clojure.tgenedavis.com/2020–07–04/clojure-with-a-touch-of-redis/
  5. Clojure Redis: Get and Set
    https://clojure.tgenedavis.com/2020–07–07/clojure-redis-get-and-set/
  6. Clojure Redis Pub/Sub with Carmine
    https://clojure.tgenedavis.com/2020–10–17/clojure-redis-pub-sub-with-carmine/
  7. Redis and Clojure (založeno na odlišné knihovně)
    https://devender.me/2010/06/13/redis-and-clojure/
  8. Disque, an in-memory, distributed job queue
    https://github.com/antirez/disque
  9. Scripting Redis with Lua
    https://redislabs.com/ebook/part-3-next-steps/chapter-11-scripting-redis-with-lua/
  10. Redis Lua script for atomic operations and cache stampede
    https://engineering.linecor­p.com/en/blog/redis-lua-scripting-atomic-processing-cache/
  11. Příkaz pro spuštění skriptu v jazyce Lua: EVAL script numkeys key [key …] arg [arg …]
    https://redis.io/commands/eval
  12. Redis Lua scripts debugger
    https://redis.io/topics/ldb
  13. Repositář projektu s Redis klientem pro jazyk Go
    https://github.com/go-redis/redis
  14. Stránky programovacího jazyka Lua
    https://www.lua.org/
  15. Programovací jazyk Lua
    https://www.palmknihy.cz/ucebnice-odborna-literatura/programovaci-jazyk-lua-12651
  16. Programming in Lua
    https://www.lua.org/pil/
  17. Redis Lua Scripts – Itamar Haber
    https://www.youtube.com/wat­ch?v=eReTl8NhHCs
  18. Building Databases with Redis Tutorial: Lua Script | packtpub.com
    https://www.youtube.com/wat­ch?v=mMfGNsAr7Bg
  19. Repositář projektu redis-luajit (fork)
    https://github.com/coleifer/redis-luajit
  20. Type-safe Redis client for Go
    https://redis.uptrace.dev/
  21. Dokumentace k balíčku redis
    https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc
  22. godis – redis client implement by golang, inspired by jedis.
    https://github.com/piaohao/godis
  23. How to Use Redis Go Client go-redis/redis with GoLang
    https://kb.objectrocket.com/redis/how-to-use-redis-go-client-go-redis-redis-with-golang-592
  24. Adventures in message queues
    http://antirez.com/news/88
  25. redeo
    https://github.com/bsm/redeo
  26. First-in, first-out queues
    https://redislabs.com/ebook/part-2-core-concepts/chapter-6-application-components-in-redis/6–4-task-queues/6–4–1-first-in-first-out-queues/
  27. Stránky projektu Redis
    https://redis.io/
  28. Introduction to Redis
    https://redis.io/topics/introduction
  29. Try Redis
    http://try.redis.io/
  30. Redis tutorial, April 2010 (starší, ale pěkně udělaný)
    https://static.simonwilli­son.net/static/2010/redis-tutorial/
  31. 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/
  32. Praktický úvod do Redis (1): vaše distribuovaná NoSQL cache
    http://www.cloudsvet.cz/?p=253
  33. Praktický úvod do Redis (2): transakce
    http://www.cloudsvet.cz/?p=256
  34. Praktický úvod do Redis (3): cluster
    http://www.cloudsvet.cz/?p=258

Byl pro vás článek přínosný?