Using Redis as Your Main Superfast Persistent Database in Node & Express

Redis is a great database. I love it, I really do. It’s easy to use. It’s super powerful with its useful and easy to use structures. I can do anything with it. And above all it is FAST, extremely fast. Nothing else comes even close to it.

Most of this speed comes from the fact that Redis is an in-memory database. Every data, every structure, everything is always in the memory.

As a result, we often think that it is only good for storing temporary data. Everybody uses it for caching the information from their “real” database.

We just expect that it cannot have the persistence of MySQL, Mongo or any other database out there. But it is not true.

Let’s have a look at two very important facts that we are going to use today.

  1. Redis is a great database for storing your data persistently and just as safely and securely as any other.

  2. Many applications don’t need that kind of persistence.

For more infomration on why the first point is true, you should read the following post by Redis creator Redis persistence demystified

Installing & Configuring Redis

To install Redis go to http://redis.io/download and follow the instructions.

Then in the folder where you compiled Redis there is the default configuration file. To use it just do the following

$ ./src/redis-server redis.conf

However, before issuing the command above, let’s make one little change. Look for the following line appendonly no and change it to appendonly yes. You have just enabled Redis’ AOF (Append Only File) persistence. You are ready to go.

The sky and the memory is your limit

The only real limit when using Redis is not the persistence. It is your memory. You can store only so much data even when your drive is much bigger.

Redis is not a silver bullet even with persistence

Yes, Redis is persistent but due to its memory limits it is not for all cases. First, not all applications need fast access. Second, memory is expensive.

It’s much less expensive to store you data on a hard drive when you need to access it rarely or when accessing speed is not critical.

So when you have a lot of data, like hundreds of terabytes, using Redis might be way too expensive without any real advantages.

OK, Redis is persistent, let’s work with it.

Enough talk let’s look at some very simple code. First, you need to install as usual an NPM package to be able to talk to Redis.

$ npm install ioredis 

Reading and writing to the database is very simple, you have to just do the following

var Redis = require("ioredis")
  , client = new Redis() 

client.set("some_key", "some_value")
client.get("some_key", function(err, result) {
  console.log(result) // prints 'some_value'

})

This very simple example connects to Redis, then saves a value some_value and then reads it back again.

It is simple, fast and persistent. Restart your server and your data will still be there.

Application

Let’s look at a more complex application instead of a simple example.

app/
  controllers/
    comments.js
    users.js
  models/
    comment.js
    user.js
  views/
  app.js

As you can see it is a typical MVC structure. There are two models User and Comment, and there are two controllers users and comments.

Our app will require a few more packages in addition to the Redis package.

$ npm install express jade

Express will run our web app and Jade will be our template language.

Connecting to Redis

In the file structure above, there are two controllers comments and users. The comments controller displays and edits comments, where as the other one does the same for users.

Both of them need to connect to the database. When you copy the code from the previous example, inside each of these files, it will work but it will not be very convenient.

When you later want to make a change to how you connect to Redis, you will have to modify each file. The more files you have the more difficult and error prone it will be.

Instead, let’s create in our app folder a file named db.js with the following content. It will help us manage our database connections as well as help us when testing.

var Redis = require("ioredis")

var state = {
  db: null,
}

var MODE_TEST = "mode_test"
  , MODE_PRODUCTION = "mode_production"

exports.MODE_TEST = MODE_TEST
exports.MODE_PRODUCTION = MODE_PRODUCTION

exports.connect = function(mode) {
  state.db = new Redis()

  // Use different DB when testing

  if (mode === MODE_TEST) {
    state.db.select(15)
  }
}

exports.get = function() {
  return state.db
}

Any controller and model can use this simple file to connect to the database. When ever we want to make a change on how we connect, all we have to do is just change this file.

This is especially useful when you want to change the path to the server where Redis is running.

Moreover, instead of every model or controller connecting we will connect to our database at start of our application.

This will happen in our app.js file. It is the entry point of our application. Let’s have a look at it.

var express = require('express')
  , app = express()

var db = require('./db')

app.engine('jade', require('jade').__express)
app.set('view engine', 'jade')

app.use('/comments', require('./controllers/comments'))
app.use('/users', require('./controllers/users'))

db.connect()
app.listen(3000, function() {
  console.log('Listening on port 3000...')
})

Once the app is running our app establishes a connection to Redis and all the models can use it. They don’t need to connect themselves.

Model & Business Logic

Redis is great for caching but it is just as great when you need to build your models around it. In our app we have comments and users. Let’s look at how our Comment model could look like.

var db = require('../db')

exports.add = function(user, message, done) {
  var data = {
    user: user,
    message: message,
    date: new Date().getTime(),
  }

  db.get().rpush("comments", JSON.stringify(data), done)
}

exports.all = function() {
  db.get().lrange("comments", 0, -1, function(err, items) {
    done(err, items.map(function(item) {
      var data = JSON.parse(item)
      data.date = new Date(data.date)
      return data
    }))
  })
}

exports.recent = function() {
  db.get().lrange("comments", -10, -1, function(err, items) {
    done(err, items.map(function(item) {
      var data = JSON.parse(item)
      data.date = new Date(data.date)
      return data
    }))
  })
}

As you can see our Comment model uses the established connection. All comments are appended to a single list in chronological order. We can add a comment, then take all comments or just take the 10 most recent comments.

It looks so simple thanks to how well Redis works.

Let’s have a look at how our comments controller in the controllers/comments.js file may look like

var express = require('express')
  , router = express.Router()

  var Comments = require('../models/comments')

router.get('/all', function(req, res) {
  Comments.all(function(err, docs) {
    res.render('comments', {comments: docs})
  })
})

router.get('/recent', function(req, res) {
  Comments.recent(function(err, docs) {
    res.render('comments', {comments: docs})
  })
})

module.exports = router

The router has two methods. One which shows all comments and one the most recent comments. The best of all is that it doesn’t even know whether it is using Mongo, Redis or any other database. The only thing which can give you away is that your app will be blazingly fast.

How is a persistent Redis performing in the Real World?

It is all good when looking at examples and running all the code and database on your development machine, but this is not the real world.

In the real world there are sever crashes, power outages and other scary things. How is Redis doing out there in the wild?

We have been using the setup that I showed you above for years. Redis is the only database behind our Tasks application synchronization feature.

It is super fast. We have hundreds of tests which pass in milliseconds. Our production servers have been running for years wihtout any crashes or other problems. And all data is safely stored with redis AOF mechanism.

Next

Today Redis is ready to be used as a production, persistent and a super fast database.

Check whether your app data can fit into memory, and if this is the case, just give a try to Redis as your persistent datastore.

If you are using Git, this will be super easy. Just create a new branch and you are ready to go.

Did you like this article?

Please share it

We are Stefan Fidanov & Vasil Lyutskanov. We share actionable advice about development with Node, Express, React and other web & mobile technologies.

It is everything that we have learned from years of experience working with customers from all over the world on projects of all sizes.

Let's work together
© 2024 Terlici Ltd · Terms · Privacy