Beginner’s Guide to Redis with Python

Python Redis Featured

In this article, we will extensively cover what Redis is and how it can be used alongside Python. Since both of these technologies are trending, it is a great tool to have in your bag. Let’s get started with understanding some basics

What is Redis?

Often referred to as a data structure server, Redis is an acronym for “Remote Dictionary Server”. Strings, lists, sets, hashes, ordered sets, bitmaps, and other data structures are among those it supports.

These data structures allow developers to use Redis’s special abilities and qualities to create complex applications. A free-to-use and store data structure in memory which can be a database, cache and message is Redis. Redis is the best option for situations requiring low-latency data access since it stores data in memory, enabling incredibly quick read and write operations.

Key Features and Advantages of Redis in  Python Applications

A wide range of essential capabilities and benefits are provided by Redis when it is integrated with Python programs Redis is perfect for real-time data processing and guarantees lightning-fast access speeds with its in-memory data storage.

Data availability is guaranteed even after the server restarts because of Redis’ capability for data persistence. Data redundancy and fault tolerance are allowed by integrated replication. The efficient communication between application components is made possible by pub/sub messaging.

Complex processes can be performed with little network overhead thanks to Lua scripting. Lowering backend load and enhancing performance are two areas where Redis excels as a powerful caching tool. Additionally, it guarantees data consistency by atomic operations, and automatic cache eviction is ensured through key expiration

Why Using Redis in Python is Beneficial?

The bar for Python applications is raised with numerous advantages due to Redis integration with Python. To achieve low latency and quick response times, the combination of Redis’s efficient structure and in-memory data storage is used. Redis’s scalability allows for seamless extension with master-slave replication and data distribution across numerous nodes as the user base expands.

Python applications greatly benefit from Redis’s speed and low latencies for real-time data processing. By reducing the burden on the backend databases, the excellent caching capabilities of Redis improve the performance of the application. Event-driven architectures and real-time messaging systems are made possible by the Publish/Subscribe capability. Cache eviction is automated for more efficient operations, as Redis also helps with atomic tasks that guarantee data consistency and reduce race situations.

Installing and Setting up Redis for Python 

Installation Process of Redis

Following the instructions in the official documentation will allow you to install Redis relatively easily.  You can follow along with the Installation Guide by clicking the link I’ll provide in the references section at the bottom of this article, then return here as we go with learning how to utilize Redis with Python.

As I’ll be using a Mac to write this article, you can install Redis on your Mac if you have Homebrew installed by typing the command below in your terminal.

brew install redis
Redis Installation Mac
Redis Installation Mac

How to Install Redis-py, The Python Redis Client Library

Using pip, the Python package manager, you may install the Redis-py client library after installing Redis:

pip install redis

The default package manager for Python is called Pip; I’ll include a link to the site if you’d like to learn more.

Setting up Redis server and connecting from Python

On Windows, you can simply run the ‘red-server.exe’ which will be located in the installation folder, using the command prompt or PowerShell.

If you are using Mac or Linux, then you can use the below given command on your terminal.

redis-server
Redis Running Server
Redis Running Server

If you have correctly installed Redis and it has launched a server without any errors, you might see a result similar to this.

Once our server is started, we can use the following code to link it to our Python file:

import redis

redis_client = redis.Redis(host='localhost', port=6379, db=0)

redis_client.set('key', 'value')
data = redis_client.get('key')
print(data) 
Redis Python Connection
Redis Python Connection

The above is very basic code that will help you connect your Python file to a Redis server. It is completely fine if you don’t understand the code as of now because we will be studying all the methods used in the above example in depth in the upcoming sections.

As of now, all you need to see is if your server and code are working properly without any errors and if the hostname and port number match the result generated in your terminal. If all these are set, then we are good to move ahead with the more complex stuff.

Basics of Redis

Let us first understand some of the basics of using Redis.

In this section, we will be understanding some of the important data structures that are used in Redis, First, we will understand them conceptually, and then we will see how we can implement them using Python code.

The Fundamental Data Structures

Strings

A straightforward key-value data structure. Provides support for several operations, including set, get, increment, decrement, and append.Useful for session management, counters, and caching.

Lists

A set of components in an ordered collection where duplicates are permitted.Supports various operations such as push, pop, obtaining range, etc. Ideal for constructing activity feeds, message brokers, and queues.

Sets

A group of distinct, unorganized components.Supports set operations such as intersection, difference, and union.Excellent for using tags, relationships in the social graph, and event membership.

Sorted Sets

Similar to sets, but with scores assigned to each element. Enabling range-based inquiries, the ordering of the elements is done by using scores. Useful for time-series data, leaderboards, and rankings.

Hashes

A key-value store in which the keys correspond to various fields and their corresponding values. Ideal for complicated object storage and retrieval.Managed user profiles, setups, and other things.

Python Code Examples to Demonstrate Each Data Structure

Strings

import redis

redis_client = redis.Redis()

redis_client.set("name", "John")
redis_client.set("Age", '15')

name = redis_client.get("name")
age = redis_client.get("Age")
print(name.decode()) 
print(age.decode()) 

In the code shown above, we can see how to use strings.

Firstly, I imported Redis, then I created a connection to the Redis Client, and then on lines 5 and 6, I used the set() method to create two strings.

Then, to retrieve the data, I used the get() function on lines 8 and 9, storing the values in the variables “name” and “age,” and last, using the decode() method on lines 10 and 11, I simply printed the numbers stored in the variable.

The output is seen in the figure below.

Redis String
Redis String

Lists

import redis

redis_client = redis.Redis()

redis_client.lpush("nums", 1)
redis_client.lpush("nums", 2)
redis_client.lpush("nums", 3)

numbers = redis_client.lrange("nums", 0, -1)
print(numbers) 

The code above demonstrates how to use lists.

To add elements to the list, I first imported Redis, then connected to the Redis Client, and then, on lines 5, 6, and 7, I used the lpush() method, which accepts the arguments “list name” and “element”.

Lastly, I use the lrange() method to display the list by retrieving the data from a variable.

Redis Lists
Redis Lists

Sets

import redis

redis_client = redis.Redis()

redis_client.sadd("fruits", "apple")
redis_client.sadd("fruits", "banana")
redis_client.sadd("fruits", "orange")

fruits = redis_client.smembers("fruits")
print(fruits)

We can see how to use sets in the code above.

After importing Redis and establishing a connection to the Redis Client, lines 5 to 7 implement the sadd() method, which adds the elements to a set.

Lastly, to print the list, I use the smembers() method to retrieve the values in a variable and print it

Redis Sets
Redis Sets

Hashes

import redis

redis_client = redis.Redis()

redis_client.hset("user:1", "name", "Alice")
redis_client.hset("user:1", "age", 30)

user_data = redis_client.hgetall("user:1")
print(user_data)

We can see how to use hashes in the code above.

I first imported Redis, after which I established a connection to the Redis client. I used the hset() method on lines 5 and 6, which adds elements to the hash.

I then used the hgetall() method to store the hash table in a variable before printing the values.

Redis Hashes
Redis Hashes

Redis Keys and Commands

Redis’ principal method of data storage and retrieval is through the use of keys. To interact with these keys, which are all connected to different values, a wide range of commands are provided by Redis

To use Python to conduct CRUD operations on Redis keys, we’ll look at a few important Redis commands and their Python equivalents in this section.

Importance of Keys in Redis

For data storage, keys serve as the distinctive identities in Redis. These keys might be able to store any binary data and be binary safe. Each key has a unique value, which might be a straightforward string or one of the many data structures Redis provides, such as lists, sets, hashes, or sorted sets.

Meaningful keys, which are used to manage data and allow developers to quickly organize data, are all given by Redis. Python applications may easily achieve high-performance data storage and retrieval by utilizing Redis’ robust key-value paradigm and variety of data formats.

Example of CRUD Operations with Redis Keys in Python

Let us see the importance of using keys with the help of an example, as when we see things happening, we tend to understand better. I would like to request that you code along with me through this example.

I will be performing CRUD (Create, Read, Update, Delete) operations with Redis keys in this example:

import redis

redis_client = redis.Redis()

redis_client.set("username", "john_doe")

username = redis_client.get("username")
print(username.decode())

redis_client.set("email", "[email protected]", nx=True)

redis_client.setex("password_reset_token", 600, "a1b2c3d4e5")

redis_client.delete("username")

key_exists = redis_client.exists("email")
print(key_exists)

In the above code, the Redis library is first imported into the code, allowing us to use the Python Redis-py client. The Redis client is then created using redis.Redis().

This establishes a connection to the local Redis server, which is listening on port 6379 on the default host, localhost. You can supply those values as arguments to redis.Redis() if your Redis server is running on a different host or port. We assign the value “john_doe” to a new key called “username” using redis_client.set().

Redis is where this key-value pair is kept. The username of a user is now represented by the key “username”. To retrieve the value of the key “username”, we use redis_client.get(). This returns the value “john_doe”, which we decode using decode() since Redis-py returns values as bytes.

Redis_client.set() is used to add the value “[email protected]” to the new key “email”. The key is only set if it does not already exist thanks to the nx=True option. The key will not be updated if it already exists. We generate a new key called “password_reset_token” with the value “a1b2c3d4e5” using redis_client.setex(). In addition, we gave this key a 600-second (10-minute) expiration duration. The key will be automatically deleted from Redis after ten minutes.

We use redis_client.delete() to remove a key. This deletes from Redis the key-value combination related to the key “username”. Using redis_client.exists(), we may determine whether a key is present. It returns 1, which is true if the key “email” is present, and 0, which is False otherwise.

Redis Key Demo
CRUD Operations Using Redis Keys

Redis Transactions and Pipelines in Python

Need for Transaction in Certain Redis Operations

Redis transactions are required to guarantee atomicity for a collection of operations. Atomicity ensures that either every operation in a transaction is successful simultaneously, or that none of them are successful at all. This is essential for preserving data integrity and consistency, particularly when managing vital processes that involve numerous Redis commands. For instance, transferring money between accounts in a banking application requires a combination of deducting from one account and crediting another, which should either happen totally or not at all.

How to Use Transactions and Pipelines in Redis-py to Ensure Atomicity 

Transactions utilizing the MULTI, EXEC, and WATCH commands are supported by Redis-py. Using the pipeline method, which generates a pipeline object for batch execution, you can run several Redis commands as a single transaction.

Redis ensures the atomic execution of the commands by enclosing them in a pipeline block.

Let’s use an illustration to demonstrate how this functions.

import redis

redis_client = redis.Redis()

with redis_client.pipeline() as pipe:
    while True:
        try:
            pipe.watch('key1', 'key2', 'key3')
            pipe.multi()

            # Perform multiple Redis operations within the transaction
            pipe.set('key1', 'value1')
            pipe.set('key2', 'value2')
            pipe.set('key3', 'value3')

            pipe.execute()
            break

        except redis.WatchError:
            continue

In this code, we begin by using Redis to create a Redis client.Redis(). Then, a with statement is used to build an object for a pipeline called a pipe. We can organize several commands for atomic execution using a pipeline. We attempt to carry out a transaction using the Redis instructions inside the while True loop. To handle instances involving concurrency, the loop is required.

We begin the transaction by “watching” the keys “key1,” “key2,” and “key3” in the pipe.watch(). The watch technique makes sure that no other clients during the transaction can change these keys. The transaction is aborted if one client modifies any of these keys.

The transaction begins with the use of the pipe.multi() method.  In this example, we are setting the keys “key1,” “key2,” and “key3” to the corresponding values “value1, “value2,” and “value3.”

Any Redis command that your application requires can be executed throughout the transaction. The execute method now uses pipe.execute() to atomically execute every command in the pipeline. Redis raises a WatchError whenever any command fails, indicating that one of the observed keys was altered during the transaction.

When this occurs, until it is successful, the loop will start over and the transaction will be attempted once more.

Redis Transaction Pipeline Demp
Redis Transaction Pipeline Example in Python

Benefits of Batching Command Using Pipelines in Python

In Python, using pipelines to batch commands has several benefits. Improving the performance, the number of network round-trips is lowered by transmitting several commands at once. The pipeline’s commands run atomically, guaranteeing the consistency and integrity of the data.

Especially for big command sets, processing is speeded up by the concurrent execution of commands, which is allowed by pipelines. Overheads are minimized as pipelines improve communication efficiency by sending numerous commands in a single request. Redis’ throughput is increased overall by batching instructions using pipelines, which makes data processing more productive and scalable in Python applications.

Caching with Redis in Python 

Advantages of Using Redis as a Cache in Python Applications

A superb caching option for Python applications with in-memory functionality and fast performance is Redis To avoid having to get frequently used data from primary data sources like databases or APIs, caching entails storing it in Redis.

Improved application performance is one benefit of using Redis as a cache, as data is fetched from the cache more quickly than from the disc or other external sources. Thanks to its low latency response times, a seamless user experience is ensured by Redis for quick access to cached data. When the workload of the application increases, effective data retrieval is still assured by Redis’s scalability

Caching and Its Benefits

Several advantages, like Redis, are offered by caching, as it is a useful approach that saves frequently accessed data in quick and easy locations. By cutting down on the time spent requesting it from slower sources, caching applications can make data access more rapid.

Overall, a better user experience is a result of faster reaction times. In addition to resulting in more effective resource use and financial savings, applications can reduce their dependence on primary data sources like databases or external APIs by taking advantage of cached data. The outsourcing of repetitive data retrieval activities to a specialized cache, which enables more effective horizontal scaling as the application’s demands increase, is another way that caching helps to enhance scalability.

Implementing Caching using Redis-py

Redis-py caching implementation in Python is a simple procedure. Create a Redis client using Redis to connect to the Redis server first.Redis(). Use redis_client to see if the data is already present in the Redis cache before requesting it from the main source.get(key).

If the information is missing, get it from the main source and use redis_client to save it in Redis. To control cache validity, use the set(key, value, expiry_time) function with an optional expiration time. Fetch data for upcoming requests from the Redis cache rather than the main source to drastically cut response times and lighten the stress on the main data source, improving data retrieval and the performance of the application.

Real World Use-Cases

Variety of practical Python application contexts. Minimized database queries and fast application response times by storing frequently visited data are areas where it excels as an in-memory cache. Redis’ fast handling of user sessions, login tokens, and user-specific data for session management ensures scalable session handling.

To stop abuse and preserve system stability, another crucial application is rate limitation, as Redis sets API rate limits. For real-time communication between distributed system components, Redis also offers Pub/Sub messaging. Leaderboards, job queues, geospatial data storage, caching database queries, and caching machine learning models are the various areas that show Redis’s adaptability and importance across several industries.

Summary

So here we are, finally, at the end of this intense journey of learning how to use Redis with Python. We have covered all the theoretical points and understood the various concepts.

With the help of simple code examples, we gained practical knowledge and, along with that, understood the concepts in theory. Lastly, we covered some key and vital elements that are used when using Redis with Python.

References

Python Tutorial

Official Redis Documentation

Installation Guide for Redis