Below are the commands to clone the source code (frontend and backend) for the application used in this tutorial
git clone https://github.com/redis-developer/ebook-speed-mern-frontend.git
git clone https://github.com/redis-developer/ebook-speed-mern-backend.git
Imagine you've built a movie streaming app. You used MongoDB as your data store, and as you needed to scale you implemented caching using Redis. This allows you to drastically speed up reads. However, now you are experiencing slowness when writing to MongoDB.
For example, maybe you want to allow users to continue watching movies where they last left off. This requires you to store the timestamp of where a user is when they decide to pause the movie. With millions of users, this is starting to cause MongoDB to slow down when you have peaks in demand.
You need a way of flattening the peaks in demand, allowing you to write data quickly and then persist it to MongoDB when the demand dies down. What you need is called the "write-behind pattern."
The pattern is simple, your application writes data to Redis and then asynchronously data gets written to MongoDB. Write operations are queued up so that the application can move on quickly and the cache can catch up over time. However, this does mean there is a short time when the data between the cache and the system of record is inconsistent.
Below is a diagram of the write-behind pattern for the application:
The pattern works as follows:
There are two related write patterns, and the main differences between them are as follows
Write Behind | Write through |
---|---|
Syncs data asynchronously | Syncs data synchronously/ immediately |
Data between the cache and the system of record (database) is inconsistent for a short time | Data between the cache and the system of record (database) is always consistent |
Learn more about Write through pattern
Consider Redis with this pattern when you need to
You can skip reading this section if you are already familiar with RedisGears)
RedisGears is a programmable serverless engine for transaction, batch, and event-driven data processing allowing users to write and run their own functions on data stored in Redis.
Functions can be implemented in different languages, including Python and C, and can be executed by the RedisGears engine in one of two ways:
Some batch type operations RedisGears can do:
person:
person:
to a setperson:
(assume all of them are of type hash)Some event type operations RedisGears can do:
I-AM-IMPORTANT:
and asynchronously dump them in a "deleted keys" log fileplayer:
and synchronously update a user's level when the score reaches 1000Run the Docker container:
docker run -p 6379:6379 redislabs/redisgears:latest
For a very simple example that lists all keys in your Redis database with a prefix of person:
create the following python script and name it hello_gears.py
:
gb = GearsBuilder() gb.run('person:*')
Execute your function:
docker exec -i redisgears redis-cli RG.PYEXECUTE "`cat hello_gears.py`"
The gears-cli tool provides an easier way to execute RedisGears functions, specially if you need to pass some parameters too.
It's written in Python and can be installed with pip
:
pip install gears-cli
gears-cli hello_gears.py REQUIREMENTS rgsync
Usage:
gears-cli --help
usage: gears-cli [-h] [--host HOST] [--port PORT]
[--requirements REQUIREMENTS] [--password PASSWORD] path [extra_args [extra_args ...]]
The demo application used in the rest of this tutorial showcases a movie application with basic create, read, update, and delete (CRUD) operations.
The movie application dashboard contains a search section at the top and a list of movie cards in the middle. The floating plus icon displays a pop-up when the user selects it, permitting the user to enter new movie details. The search section has a text search bar and a toggle link between text search and basic (that is, form-based) search. Each movie card has edit and delete icons, which are displayed when a mouse hovers over the card.
Below are the commands to clone the source code (frontend and backend) for the application used in this tutorial
git clone https://github.com/redis-developer/ebook-speed-mern-frontend.git
git clone https://github.com/redis-developer/ebook-speed-mern-backend.git
To demonstrate this pattern using the movie application, imagine that the user opens the pop-up to add a new movie.
Instead of the application immediately storing the data in MongoDB, the application writes the changes to Redis. In the background, RedisGears automatically synchronizes the data with the MongoDB database.
Developers need to load some code (say python in our example) to the Redis server before using the write-behind pattern (which syncs data from Redis to MongoDB). The Redis server has a RedisGears module that interprets the python code and syncs the data from Redis to MongoDB.
Loading the Python code is easier than it sounds. Simply replace database details in the Python file and then load the file to the Redis server.
Create the Python file (shown below, and available online). Then update the MongoDB connection details, database, collection, and primary key name to sync.
# Gears Recipe for a single write behind
# import redis gears & mongo db libs
from rgsync import RGJSONWriteBehind, RGJSONWriteThrough
from rgsync.Connectors import MongoConnector, MongoConnection
# change mongodb connection (admin)
# mongodb://usrAdmin:passwordAdmin@10.10.20.2:27017/dbSpeedMernDemo?authSource=admin
mongoUrl = 'mongodb://usrAdmin:passwordAdmin@10.10.20.2:27017/admin'
# MongoConnection(user, password, host, authSource?, fullConnectionUrl?)
connection = MongoConnection('', '', '', '', mongoUrl)
# change MongoDB database
db = 'dbSpeedMernDemo'
# change MongoDB collection & it's primary key
movieConnector = MongoConnector(connection, db, 'movies', 'movieId')
# change redis keys with prefix that must be synced with mongodb collection
RGJSONWriteBehind(GB, keysPrefix='MovieEntity',
connector=movieConnector, name='MoviesWriteBehind',
version='99.99.99')
A collection of RedisGears functions and any dependencies they may have that implement a high-level functional purpose is called a recipe
. Example : "RGJSONWriteBehind" function in above python code
# install
pip install gears-cli
# If python file is located at “/users/tom/movies-write-behind.py”
gears-cli --host <redisHost> --port <redisPort> --password <redisPassword> run /users/tom/movies-write-behind.py REQUIREMENTS rgsync pymongo==3.12.0
2. Using the RG.PYEXECUTE from the Redis command line.
Find more information at RG.PYEXECUTE.
# Via redis cli
RG.PYEXECUTE 'pythonCode' REQUIREMENTS rgsync pymongo==3.12.0
The RG.PYEXECUTE command can also be executed from the Node.js code (Consult the sample Node file for more details)
Find more examples at Redis Gears sync with MongoDB.
RedisInsight is the free redis GUI for viewing data in redis. Click here to download.
The next step is to verify that RedisGears is syncing data between Redis and MongoDB.
Insert a key starting with the prefix (that's specified in the Python file) using the Redis CLI
Next, confirm that the JSON is inserted in MongoDB too.
You can also check RedisInsight to verify that the data is piped in via Streams for its consumers (like RedisGears).
How does all that work with the demo application? Below is a code snipped to insert a movie. Once data is written to Redis, RedisGears automatically synchronizes it to MongoDB.
...
//(Node mongo query)
if (movie) {
//insert movie to MongoDB
await db.collection("movies")
.insertOne(movie);
}
...
...
//(Redis OM Node query)
if (movie) {
const entity = repository.createEntity(movie);
//insert movie to Redis
await moviesRepository.save(entity);
}
...
You now know how to use Redis for write-behind caching. It's possible to incrementally adopt Redis wherever needed with different strategies/patterns. For more resources on the topic of caching, check out the links below: