Redis application and practice in Web project

Redis, as an open source (BSD) memory-based high-performance storage system, has been widely used by Internet companies and has many application scenarios. This article will elaborate on the main application and practice of Redis in Web projects based on PHP.

The cache

The cache described here refers to data that can be lost or expired. The common commands are set, hset, get, hget. When using redis as a cache, note the following:

  • Since the available memory of Redis is limited, unlimited growth of redis memory cannot be toleratedmaxmemoryMaximum memory.
  • With maxMemory enabled, you can enable the LRU mechanism and set the expire of the key. When the maximum Redis memory is reached, Redis will automatically eliminate the key based on the least recently used algorithm.
  • The Redis persistence strategy and Redis failure recovery time are a game process. If you want to recover quickly after a failure, you should enable the dump backup mechanism, but this requires more free memory space for persistence. If you can tolerate long Redis failure recovery times, you can use AOF persistence while turning off the dump mechanism so that no additional memory space is required.

storage

In Web projects, Redis stores data that is read and written very frequently to relieve pressure on databases such as MySQL. If Redis is used as a storage system, persistence must be enabled to prevent data loss.

A typical scenario

  • counter

Counter requirements are very common, such as the number of likes on weibo, the number of favorites on posts, the number of articles shared, the number of users concerned, and so on.

  • Social list

For example, use Sets to store lists of concerns, favorites, likes, and so on.

  • Session

With redis’s high-performance key-value storage, you can save user login status to Redis.

  • .

The queue

Simple queue

Generally, the redis list structure is used as a queue, rpush produces messages, LPOP consumes messages, and when lPOP has no messages, the appropriate sleep operation is performed.

$queueKey = "queue"; / / producer$redis->rpush($queueKey.$data) // Consumerswhile (true) {
    $data = $redis->lpop($queueKey);
    if (null === $data) {
        usleep(100000);
        continue; } // Business logic... }Copy the code

Because the sleep event used when there is no message is difficult to control, the production environment should try not to use sleep to sleep. Instead, it can use blPOP to consume messages, which blocks until the message arrives when there is no new message.

Delay queue

The sorted set data structure of Redis can be used for delayed queue, with time stamp as score and message content as member. Zadd command is used to produce messages, and consumers use Zrangebyscore command to obtain the polling of message data before the specified time for processing.

$queueKey = "queue"; // Production message // consumption time, set to 1 hour here$consumeTimestamp = time() + 3600;
// $dataAdd random string prefix (or suffix) to prevent duplicate member from being discarded$data = $data . md5(uniqid(rand(), true));
$redis->zadd($queueKey.$consumeTimestamp.$data); // Consume messageswhile (tue) {
    $arrData = $redis->zrangebyscore($queueKey, 0, time());
    if (!$arrData) {
        usleep(100000);
        continue; } // foreach ($arrData as $data) {
        $data = substr($data, 0, strlen($data) - 32); / / consumption$data}}Copy the code

Many consumers

Using the PUB/SUB topic subscriber pattern, a 1:N message queue can be implemented. This mode is not recommended because production messages are lost when the consumer is offline.

It is important to note that using Redis as a message queue service is not recommended; this is not the design goal of Redis. If you must, consider disque, developed by the authors of Redis.

A distributed lock

Distributed lock mainly solves several problems:

  • Mutual exclusion: Only one service (or application) can access a resource at a time
  • Security: A lock can only be released by the service (or application) holding the lock
  • Fault tolerance: The lock can still be released if the holding service crashes
  • Avoid deadlock

Plan 1

We might consider using setnx and expire commands to implement locking, where value is written successfully only when no key exists:

$lockStatus = $redis->setnx($lockKey, 1);
if(1 = = =$lockStatus) {// Lock succeeded, set timeout for lock$redis->expire($lockKey, 300); } elseIf (0 === =$lockStatus) {// failed to lock}else{// Other exceptions}Copy the code

However, this operation is not atomic. If the service crashes during setNX and the Key is not timed out, the lock will remain unreleased.

Scheme 2

We recommend the set key value [EX seconds] [PX milliseconds] [NX | XX] command to lock

  • EX: The number of seconds after the key expires
  • PX: How many milliseconds after the key expires
  • NX: Creates a key when it does not exist. The effect is the same as setnx
  • XX: Overwrites the key if it exists
$lockStatus = $this->redis->set($lockKey, 1, "EX", 30, "NX");
if ("OK"= = =$lockStatus) {// If the lock is successfully added, perform subsequent operations. // If the service logic is completed, release the lock$this->redis->del($lockKey);

} elseif (null === $lockStatus) {// failed to lock}Copy the code

As shown in the code above, if the set command returns OK, the client can acquire the lock (if null is returned, the application service can try again to acquire the lock after some time), and the lock can be released by the del command.

Note the following points in this approach:

  • The lock (key) obtained by service A has been deleted by the Redis server due to its expiration time, but service A also runs the DEL command at this time. And service B reobtains the lock with the same key after the expiration time set by a, then A executesdelThe lock placed by service B is released.
  • When a large number of keys expire at the same time, deleting keys will increase redis pressure and affect service stability.

The above locking system can be made more robust by optimizing it as follows:

  • Instead of fixed strings, set them to random large strings, which can be called tokens.
  • Delete the key that specifies the lock by script instead ofdelCommand.
  • Add a random value to the key expiration time.

The optimized code can be referred to as follows:

$lockToken = md5(uniqid(rand(), true)); // Set the timeout period based on the service logic$expire = rand(280, 320);
$lockStatus = $this->redis->set($lockKey.$lockToken."EX".$expire."NX");
if ("OK"= = =$lockStatus) {// If the lock is successfully added, perform subsequent operations. // If the service logic is completed, release the lock. // Before deleting the lock, check whether it is your own lock$currentToken = $this->redis->get($lockKey);
    if ($currentToken= = =$lockToken) {
        $this->redis->del($lockKey);
    }

} elseif (null === $lockStatus) {// failed to lock}Copy the code

To calculate

The atomic increment and subtraction method and ordered collection structure provided by Redis can undertake some computing tasks, such as page view statistics.

Browse the count

Article views +1

$redis->incr($postsKey);
Copy the code

Get article views in bulk

$arrPostsKey= / /... ;$arrPostsViewNum = $redis->mget($arrPostsKey);
Copy the code

list

The ordered set of Redis can be used to achieve the function of ranking, score as the weight ranking and take the first N records.

// Store data$sortKey = "sort_key";
$redis->zadd($sortKey, 100, "tom");
$redis->zadd($sortKey, 80, "Jon");
$redis->zadd($sortKey, 59, "Lilei");
$redis->zadd($sortKey, 87, "Hanmeimei"); // Get the ranking // Sort in descending order$arrRet = $redis->zrevrange($sortKey, 0, 1,true); // Sort from smallest to largest$arrRet = $redis->zrange($sortKey, 0, 1,true);
Copy the code

At the end

There are many application practices involved in REDis. Due to space limitation, this paper only introduces several scenarios most commonly used in Web applications. Students who are eager to further expand their knowledge of Redis can refer to the following links for further study.

  • Redis website
  • Antirez

Redis application and practice in Web project

Scan your wechat account: Learn2Code