Client-side caching enables storing frequently accessed data at the browser’s end or in the application server’s memory. It consumes client-side storage to some extent, but the performance gain is high. Usually, when the data is required, the client sends a request to the back end to query data. Most of the time, web clients retrieve the same set of data over and over from the database. With the client-side caching enabled, data retrieved via popular queries are stored on the client side.
Client-side caching has two main benefits:
- Improves performance by a considerable amount.
- Reduces the database and network loads.
At the same time, client-side caching faces the challenge of keeping up-to-date data. If the data is changed in the database end, that piece of data in the client cache becomes outdated and the client should be notified immediately to fetch the updated piece. Redis has implemented its caching model by addressing these problems.
Set Up Client-Side Caching with Redis
In Redis, the client-side caching is named tracking. There are two modes of tracking supported by Redis. The default mode is called server-assisted tracking, where the server sends invalidation notifications that are related only to the keys that are in the client cache. On the other hand, the broadcasting mode gives freedom for clients to subscribe to preferred key prefixes and receive notifications whenever a key with the subscribed prefix is modified.
Server-Assisted Tracking for Redis Clients
As the name suggests, in server-assisted mode, the server keeps track of the keys that a specific client is accessing. Whenever a tracked key is altered in the database, the client will be notified immediately. Most importantly, the invalidation notifications are generated only for the keys that are in a given client cache. The only downside to this mode is that it exploits the server memory to remember the accessed keys by each client.
Dedicated Client for Invalidation Notifications
Usually, the server-assisted client-side caching is implemented using a dedicated client that receives invalidation notifications. This client is the central point that receives all the invalidation messages for all the clients connected to a given database.
Let’s set up a dedicated client to receive invalidation messages. First, we need to connect to our Redis server as an authorized client and get the client’s ID as follows.
The above command returns the ID of the current client connection, which is 3. This ID is needed in the next steps to identify it as the central client to receive the invalidation messages. Next, we subscribe to the invalidation notification channel as follows. The SUBSCRIBE command can be used.
In this example, the channel is __redis__:invalidate.
Now we have set up the client connection to receive the invalidation notifications. Let’s initiate another client connection and turn on the client tracking. Furthermore, we redirect all the invalidation messages associated with the new client to the central client created in the earlier step. We can use the CLIENT TRACKING command to achieve this. The following is the syntax of the CLIENT TRACKING command.
ON | OFF : Determine whether client tracking should be enabled or not.
REDIRECT : Specify the ID of the client who receives invalidation messages.
Let’s enable client tracking for a new authorized client and use the REDIRECT option to specify the connection that receives the invalidation, messages which is 3.
Now we are ready to test our Redis client tracking. First, we set a key-value pair as follows.
Next, we access the username from the same client, which will cache that piece of information on the client side since we have enabled client tracking.
Let’s open a new client and change the value stored in the key username as follows.
Immediately, the client who has subscribed to the invalidate channel gets notified that the value stored at the key username has been modified and it’s invalid already.
This model is based on the RESP2 protocol, which is the default protocol Redis clients use.
RESP3 Protocol to Receive Notifications to the Tracking Client
From version 6.0, Redis introduces the RESP3 protocol, which enables an active client to receive invalidation messages. This is a huge advantage where a Redis client can listen to a given channel while issuing commands.
Let’s check the Redis version first. It must be version 6.0 or the latest one to use the RESP3 protocol. The following command can be issued to check the Redis version.
Since it is version 7.0, we are all good to use the RESP3 protocol. Redis clients use RESP2 by default. So, we need to switch to the RESP3 protocol.
This would change the protocol to RESP3 with the following output.
Let’s enable client tracking as in the earlier example by using the CLIENT TRACKING command. In this case, we do not need to specify the REDIRECT option.
Now the keys this client fetches will be tracked by the server. In addition, when the value of a tracked key changes, an invalidation message will be sent to the clients who cached that particular key.
Let’s fetch the key username.
The client caches the username key and its associated value. Now, we initiate another client connection and change the value stored in the key username.
If you check the previous client connection, there is no invalidation message received yet. If you issue another command, the invalidation notification will be displayed immediately as follows.
2. Broadcast Mode for Client Tracking
In the default mode, clients get invalidation notifications only for the keys that they have fetched in earlier command calls. With the broadcast mode enabled, clients subscribe to a specific key prefix and the client gets invalidation notifications for every key that gets changed whose key starts with the subscribed prefix.
Let’s use a new client connection to receive the invalidation messages by subscribing to the invalidate channel as follows.
In this example, the client connection ID is 10, which will be used with the REDIRECT option for a new client. Let’s specify the BCAST option in the CLIENT TRACKING command as follows.
Assume that we have a key called user:id:1 in the Redis instance. Let’s get it from this client.
Now the user:id:1 key is cached on the client side.
Let’s create a new client connection and set a new key as follows: user:id:3.
At this moment, the client who enabled tracking gets an invalidation message, and it will be redirected to the client who is identified by the ID 10. This happens because the new key contains the prefix user: which is the subscribed prefix by the tracking enabled client. As you can see, the server doesn’t keep track of any of the keys that each client fetches, but it broadcasts invalidation messages if the changed key prefix matches the subscribed prefix by each client.
OPTIN and OPTOUT Options
The OPTIN and OPTOUT options can be used to filter out what keys the server should exactly track or not track. With these options enabled in the CLIENT TRACKING command, Redis only keeps track of the keys that are queries just after the CLIENT CACHING yes command. This minimizes server-side memory usage and loads drastically.
In summary, client-side caching is one of the widely used techniques to improve the performance of web applications that frequently request data from back-end databases. As discussed, the browser or client-side application server can hold the data related to popular queries issued by the client. As mentioned in the introduction, in Redis, the client-side caching is called tracking. Furthermore, the two tracking modes are available in Redis. Both the dedicated client and broadcast modes have their own use cases.