Everything You Need to Know About Redis

Not just a key-value store

Jason Ngan
CodeX
6 min readJan 28, 2023

--

Photo by Silas Kohler from Unsplash

If you have dealt with caching in any backend system before, you have probably heard of Redis.

While most of us know Redis as an in-memory data store, it is, in fact, a much more powerful tool.

Knowing the full capability of Redis allows us to make better design choices when choosing the right data store for our application.

With that said, let’s go through everything that you need to know about Redis!

In-memory cache

Accessing RAM is much faster than SSD and HDD

First thing first, Redis is an in-memory key-value store.

Writing and storing data is equivalent to writing and reading from a variable which hits the RAM (Random Access Memory) instead of the disk.

This allows memory access to be several orders of magnitude faster than disk which enables lower latency and higher throughput.

Support various data structures

Photo by Pixabay from Pexels

As opposed to Memcached which stores values as strings, Redis allows values to be stored in various data structure types.

  • Strings
  • Lists
  • Sets
  • Hashes
  • Bitmaps
  • The list goes on
> HMSET user:1234 name Peter followers 100

> HGETALL user:1234
1) "name"
2) "Peter"
3) "followers"
4) "100"

When caching a user object, we can store the userID as key and the user object as a hash map. Redis allows access to each field in the hash map for any CRUD operation.

> HINCRBY user:1234 followers 1 
> "101"

To increment the user followers by 1, we can amend the field directly without loading it to the memory and unmarshalling it.

This mitigates the need to do it at the application level and reduces the overhead of marshal and unmarshal, thus leading to fewer I/O operations.

Every operation is atomic due to single-threaded nature

Photo by Tara Winstead from Pexels

One unique nature of Redis is that it’s single-threaded.

Due to this very nature, every command or operation in Redis is atomic. While a command is executed, other clients’ requests will NOT be served.

Hence, incrementing a value in Redis using the INCR command is thread-safe and does not require any lock or synchronisation.

This reduces the overhead of lock and makes Redis faster and bug-prone.

Optional Persistency

Photo by Stanislav Kondratiev from Pexels

One caveat about in-memory storage is that data will be lost when the server restarts, as data is not persisted to disk.

Redis offers two persistence options which write the in-memory data to durable storage.

  • RDB snapshot
  • Write ahead log

This helps in disaster recovery where data can be reloaded to memory when the server restarts after a crash.

RDB snapshot

The RDB snapshot saves a snapshot of the in-memory data asynchronously to a durable storage at every fixed interval.

Underneath the hood, the parent process forks a new child process that handles the writing to disk without affecting the performance of the parent process.

One catch about the RDB is that, some data might be loss if a crash happens before the next snapshot is taken.

Append only file

The AOF approach works by appending each Redis command to a file.

If Redis crashes, it simply replays all the commands in the file that occurred prior to the shutdown.

Unlike RDB, AOF ensures safer data retention as each operation is recorded in a file. However, that also implies larger file size and slower reloading of data.

If a user increments the same record 10 million times, Redis will have to iterate through 10 million commands on start up while RDB only needs to load one record from disk.

The AOF by default flushes commands to disk at every 1 second and this may still end up losing data.

To ensure a safer data retention, Redis can be configured to flush commands to disk at every operation but that implies slower performance.

Transaction

Photo by Francesco Ungaro from Pexels

Redis supports transactions which allow a group of commands to be executed in a single step.

Commands in a transaction are executed sequentially and no other requests will be served while the transaction is being executed.

In the event of failure, all operations will be rollbacked and discarded.

This guarantees the atomicity of a set of commands.

> MULTI
OK

> INCR foo
QUEUED

> INCR bar
QUEUED

> EXEC
1) (integer) 1
2) (integer) 1

The MULTI command begins a transaction in Redis. When an EXEC command is encountered, all queued commands are executed as a single unit while the DISCARD command aborts all operations.

Replication

Master-slaves replication

To avoid a single point of failure, Redis offers replication where data from a master instance is replicated to multiple replicas.

Replicas are read-only by default where all write operations are done on the master.

The replication between the master and replicas is done asynchronously. Every command performed on the master is synced to the replicas.

The replicas do not evict key themselves but wait for the master to send a DEL command.

Both master and replica maintain a replication ID and an offset referring to the latest processed command of the replica. When a replica restarts, it obtains the missed commands via the offset.

In the event of a failover, one of the replicas can be promoted to master, resulting in high availability.

Pub/sub system

Redis can also be leveraged as a pub/sub system

Aside from being a cache and database, Redis can also be leveraged as a pub/sub system.

A publisher publishes messages to Redis via the PUBLISH command while a subscriber subscribes and unsubscribes a topic via the SUBSCRIBE and UNSUBSCRIBE command.

While I won’t go through the full details of Redis pub/sub, it’s worth having a quick glimpse at how Redis differs from the commonly known pub/sub system — Kafka.

  • Redis adopts a push-based model. Available messages are popped instantly to consumers.
  • Redis does not retain data. Data is sent out and deleted immediately.
  • Redis cannot deal with large dataset since it’s an in-memory data store.
  • Redis does not support partitioning. A Redis stream is equivalent to one partition in Kafka.
  • Redis does not guarantee ordered delivery. It simply pushes available messages to consumers.
  • Redis supports various data structures, whereas Kafka stores messages as bytes.
  • If a consumer restarts after a shutdown, there’s no way it can know if there are any missed messages.

Conclusion

In short, aside from just an in-memory data store, Redis can be employed as a database and pub-sub system while offering various functional features.

In my next post, I will talk about the reasons why Redis can be performant even if it’s single-threaded. I hope you find this helpful and I will see you at the next one!

If you are interested in articles like this, join me and sign up for Medium today!

References

--

--