Introduction:

A timed event is currently under development, and the event is multi-session. After this, it is necessary to push information to the client at the beginning of the activity and at the end of the activity. A simple design is to cache the configuration in Redis, poll reIDS every second to get the configuration information, determine if it is at the start or end of the activity, and push it to the client. One problem, however, is that if you don’t get to the start or end point of the activity, it can cause a lot of useless polling operations. This operation not only increases access to the key, but also consumes CPU and reduces machine performance.

Redis provides a keyspace notification mechanism in version 2.8.0, which can be described in the official documentation. In a nutshell, clients can subscribe to a key, and redis notifies clients that they have subscribed to it when it changes.

implementation

This implementation is also very simple, and we can use a demo to see how to use this mechanism.

package main

import (
   "context"
   "fmt"
   "github.com/go-redis/redis/v8"
   "time"
)

var redisCli *redis.Client

func init(a) {
   / / connect to redis
   redisCli = redis.NewClient(&redis.Options{
      Addr:     "127.0.0.1:6379",
      Password: "redis123"})},/* * Automatic notification of redis key expiration */
func SetExpireEvent(a) {
   // Set a key and expire after 3 seconds
   redisCli.Set(context.Background(), "test_expire_event_notify"."Test key Expiration Notification".3*time.Second)
}

func SubExpireEvent(a) {
   // Subscribes to the key expiration event
   sub := redisCli2.Subscribe(context.Background(), "__keyevent@0__:expired")
   
   // Listen for messages from redis-server through a for loop.
   // When the client receives an event notification from the redis-server,
   // The client will tell us through a channel. Let's go back to the
   // the MSG channel field determines whether the message is the one we expect to receive,
   // Then proceed to business processing.
   for {
      msg := <-sub.Channel()
      fmt.Println("Channel ", msg.Channel)
      fmt.Println("pattern ", msg.Pattern)
      fmt.Println("pattern ", msg.Payload)
      fmt.Println("PayloadSlice ", msg.PayloadSlice)
   }
}

func main(a) {
   SetExpireEvent()
   go SubExpireEvent()
   
   // sleep is used to prevent main from being pushed out directly
   time.Sleep(10 * time.Second)
}
Copy the code

The code output is as follows:

The implementation logic is simple. The core logic is to subscribe to __keyevent@0__:expired and wait for notifications of the event in a loop. It is important to note that enabling this feature requires modifying the configuration file to enable notify-keyspace-events. You can refer to the comments in the configuration file to enable different events.

Used in business

Going back to the business scenario I mentioned at the beginning, how do you use the redis mechanism in this scenario? It is quite simple. After the activity is configured to the database, there is a step to update the cache. When setting data in the active cache, as long as we calculate the time difference between the current time and the start/end of the activity, use this difference as the expiration time of the key. For example, activity ID1 starts at t0, ends at T2, and the current time is T. At this point, you can set it like this:

// Set the key for the start of the activity
redisCli.Set(context.Background(), "id1:start"."Here we go.", t0 - t)
// Set the key at the end of the activity
redisCli.Set(context.Background(), "id1:start"."Here we go.", t1 - t)
Copy the code

This allows you to receive notifications when an activity starts/ends.

conclusion

In fact, this scheme can fully meet the requirements of the paper, but there are some problems in this scheme. These issues are also addressed in the Redis documentation.

  • First, when Redis-server pushes this event notification, all clients subscribed to this event will receive this message. Typically, our business runs in multiple nodes, so it is up to the scenario to decide whether to perform atomic operations of the business.
  • Second, Redis-Server will only push this notification once. If the node hangs or does not receive the message due to some other exception when redis-server pushes this notification, it will not push it again.
  • Third, notification may be delayed. Due to the Redis implementation mechanism, there are two mechanisms for dealing with expired keys. One is that when a command accesses a key, it is found that the key has expired. The other is to use a background system to progressively find expired keys in the background so that you can collect those keys that have never been accessed. So there is a potential for delays.

This article describes a business scenario that uses Redis’s keyspace notification mechanism, but it’s not the best way to do it. There are other ways to do it. There will be a lot of factors to consider in the actual development, and the implementation of a variety of ways, this requires us to analyze the pros and cons of each scheme, and then make a choice.

Finally, if you find any mistakes in the article, please correct them, thank you very much!