When an application queries the database on every single request, the system starts to slow down noticeably as the number of users grows. Disk-based databases are reliable, but every read operation requires hitting the disk, searching through indexes and returning the result. This is exactly where caching comes to the rescue, and Redis is today one of the most popular solutions for the job. In this article we will explore what Redis is, which caching strategies exist and how to apply them in practice with real code examples.
What Redis is and why it is fast
Redis (Remote Dictionary Server) is an in-memory key-value data store that keeps all of its information in RAM. Because traditional databases store data on a hard disk, accessing them takes milliseconds, whereas Redis reads from memory and returns a response in microseconds. This difference may seem small, but in high-load systems it allows the application to operate hundreds of times faster. Redis is more than just a cache, however: it is a full-fledged data structure server that can work with strings, lists, sets, hashes and even queues.
The core idea behind caching is simple: return frequently requested but rarely changing data from fast memory instead of the database. For example, the product list on a homepage might be requested thousands of times per second, yet it is only updated once or twice a day. Instead of pulling that list from the database every time, you store it in Redis, which dramatically reduces the load on the database and speeds up page loading. As a result, server resources are saved and the user experience improves significantly.
The main caching strategies
There are several approaches to how a cache is populated and updated, and each one suits its own kind of situation. The most widely used is the cache-aside strategy. With this approach the application first checks the cache, and if the data is found it returns it immediately; if not, it fetches the data from the database and writes it into the cache for next time. This strategy is the most common thanks to its simplicity and flexibility, since the application has full control over the cache and decides exactly what to store and when.
In the write-through strategy, every write operation is saved to both the cache and the database at the same time. This guarantees that the cache and the database are always in the same state, meaning the data never goes stale. The downside is that each write happens twice, which makes write operations slightly slower. The write-behind strategy works the opposite way: data is first written only to the cache and is transferred to the database later, asynchronously through a queue. This boosts write speed, but it introduces the risk of losing data that has not yet reached the database if the server crashes.
TTL and eviction: managing memory
Since Redis keeps all of its data in memory, memory is a limited resource that must be managed wisely. This is where the concept of TTL (Time To Live) plays an important role. You can assign an expiry time to each key, for instance the key will be automatically deleted after 300 seconds. This prevents stale data from living forever and ensures that the cache is constantly refreshed. A well-chosen TTL is the heart of any caching strategy, because it strikes the balance between data freshness and efficiency.
If memory fills up, Redis decides which keys to remove according to its eviction policy. The most popular policy is LRU (Least Recently Used), where the keys that have not been used for the longest time are removed first. Other options include LFU (Least Frequently Used) and random eviction. Choosing the right policy based on your application's needs helps you use memory as efficiently as possible and avoid the sudden disappearance of important data.
A practical code example
Let's look at a simple example of the cache-aside strategy in Python. This code first searches for data in Redis and only queries the database if nothing is found in the cache:
import redis
import json
r = redis.Redis(host="localhost", port=6379, db=0)
def get_user(user_id):
cache_key = f"user:{user_id}"
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# Not in cache - fetch from the database
user = db_query("SELECT * FROM users WHERE id = %s", user_id)
# Store in cache for 300 seconds (TTL)
r.setex(cache_key, 300, json.dumps(user))
return user
Redis is also an excellent tool for rate limiting. Using the INCR command you can count how many requests each user has sent and block them if they exceed a defined limit:
def is_rate_limited(user_id, limit=100):
key = f"rate:{user_id}"
count = r.incr(key)
if count == 1:
r.expire(key, 60) # 60-second window
return count > limit
Where Redis is used
Beyond caching, Redis is useful in a wide range of tasks. It is an ideal solution for storing sessions, because session data needs to be read and written quickly and naturally has an expiry time. Page caches, a list of the latest news or a ranking of popular products are all read-heavy pieces of data that fit well in Redis. In addition, using the List and Stream structures you can build queues for background jobs, which lets you run heavy operations asynchronously without making the user wait.
Strengths and precautions
The biggest advantage of Redis is its speed and simplicity, but there are several risks to keep in mind when using it. The most common problem is stale data: if a record in the database has changed but the cache has not yet been updated, the user will see incorrect information. This can be solved by tuning the TTL correctly or by actively deleting the cache when a record changes, a process known as invalidation. The second important aspect is memory: because Redis stores everything in RAM, you need to control how much data you cache and choose the eviction policy carefully to avoid running out of memory.
On sayt.uz hosting, installing and configuring Redis noticeably improves the performance of your backend application. With a well-chosen strategy, sensible TTL values and timely cache updates, you can reduce database load several times over and deliver lightning-fast responses to your users. Start working with Redis using a simple approach like cache-aside, and as your application grows, move on to more advanced strategies - this will ensure the speed and reliability of your project for the long term.