Redis (REmote DIctionary Server)

Redis Docs | Modules | Wiki | Example: Twitter Clone

Redis clients communicate with the Redis server using RESP (REdis Serialization Protocol) @ TCP:6379. It's a Request/Response model. The protocol is very human readable and easy to implement, yet can be implemented with a performance similar to that of a binary protocol.

Unusual data model; commands do not describe a query, but rather specific operations to perform on data types, hence data must be identifiable by primary index alone (no secondary index). Yet can implement RDB on top of key-value store. E.g., store users per user, and have users track the user-id key:

INCR next_user_id => 1000
HMSET user:1000 username foo password 1234
HSET users foo 1000

Install @ Ubuntu (per download)

# Redis server + client
$ sudo apt-get install redis-server # installed v.4

Redis @ Docker

dokcer run --rm --name 'rds' -d -p 6379:6379 redis
docker exec -it 'rds' redis-cli

@ Swarm service (app_rds), task 1, node h3 (f0pd8lcif0m433yp6h0iqpgzp)

_CTNR='app_rds.1.f0pd8lcif0m433yp6h0iqpgzp'
docker-machine ssh h3 "docker exec -it $_CTNR redis-cli"
redis.conf | Optimizing
tcp-backlog 511
#... @ boot2docker :: cat /proc/sys/net/core/somaxconn => 128
#...                  cat /proc/sys/net/ipv4/tcp_max_syn_backlog => 128

Start/Connect

# Start Redis server; pass args
$ redis-server --port 6380 --slaveof 127.0.0.1 6379
# Start Redis server as bkgnd proc
$ redis-server &  # ... prints startup msgs 
# Connect per Redis CLI
$ redis-cli
127.0.0.1:6379> QUIT # to exit

Commands per Data Type

@ Strings (commands)

@ Lists (commands)

@ Sets (commands)

@ Sorted Sets (commands)

@ Hashes (commands)

@ Streams (commands)

Add (XADD) and Query (XRANGE)

# Add entries
XADD key ID field string [field string ...] 
XADD strm * sensor-id 1234 temp 19.8 # `*` to auto-generate ID (time-series)
XADD strm * sensor-id 7777 temp 16.3

XLEN strm  # stream length; number of entries

# Query entries; access items over a range
XRANGE key start end [COUNT n]  # COUNT for 1st n items only
XRANGE strm - +  # `-/+` is min/max ID (time) of stream @ key "strm"
1) 1) "1555877533372-0"
   2) 1) "sensor-id"
      2) "1234"
      3) "temp"
      4) "19.8"
2) 1) "1555879971871-0"
   2) 1) "sensor-id"
      2) "7777"
      3) "temp"
      4) "16.3"

XRANGE strm 1555879971800 +
1) 1) "1555879971871-0"
   2) 1) "sensor-id"
      2) "7777"
      3) "temp"
      4) "16.3"

Listening (XREAD) for new items

# Subscribe to new items arriving to the stream
XREAD [COUNT n] [BLOCK msec] STREAMS key [key ...] ID [ID ...] 
XREAD STREAMS strm 1555879971870 # all GREATER than ID 
1) 1) "strm"
   2) 1) 1) "1555879971871-0"
         2) 1) "sensor-id"
            2) "7777"
            3) "temp"
            4) "16.3"
XREAD STREAMS strm $  # NEW only; since listening started
(nil)

Consumer Groups

 XREADGROUP GROUP group consumer [COUNT n] [BLOCK msec] [NOACK] STREAMS key [key ...] ID [ID ...] 

# Create consumer group
XGROUP CREATE strm grp1 $

# Add entries
XADD strm * msg apple
XADD strm * msg orange
XADD strm * msg strawberry
XADD strm * msg apricot
XADD strm * msg banana

# Read from stream using group grp1; consumer Alice. 
# ">"; returns only new msgs never delivered to other consumers so far
XREADGROUP GROUP grp1 Alice COUNT 1 STREAMS strm > 
1) 1) "strm"
   2) 1) 1) "1555885532198-0"
         2) 1) "msg"
            2) "apple"

# Acknowledge msg(s); REMOVEs msg(s)
XACK key group ID [ID ...] 

XACK strm grp1 1555885532198-0
(integer) 1
XREADGROUP GROUP grp1 Alice COUNT 1 STREAMS strm 0
1) 1) "strm"
   2) (empty list or set)

XREADGROUP GROUP grp1 Alice COUNT 1 STREAMS strm1 > 
(nil)

Pipelining

Pipelining a file containing many Redis statements:

Use to insert a large amount of data; starting with a DATA_SERIES file of many key/val pairs, prepend "SET " to each line:

$ awk '{print "SET " $0}' DATA_SERIES > 'data.txt'

Then, enter the data into Redis:

# Pipelining a file containing many Redis statements
cat 'data.txt' | redis-cli --pipe