Usage and application scenarios of the redis-string type

Recently, I have been learning Redis intensively and writing while learning

Like it before you read it, make it a habit

The usage of String memory

  • Redis strings are dynamic strings
  • usingpre-allocatedRedundant space way toTo reduceThe memory ofFrequent distribution
  • The content space is generally larger than the actual string length len
    • If the string length is less than 1 MB, the capacity expansion doubles the existing space.
    • If more than 1 MB space is added, only 1 MB space is added at a time.
  • The thing to watch out for is stringsThe maximum lengthIs 512 m.

String: String;

set

SET expire60 "will expire in a minute" EX 60 #Copy the code

To save more

local_redis:0> mset name1 boy name2 girl name3 unknown
"OK"

local_redis:0> mget name1 name2 name3
 1)  "boy"
 2)  "girl"
 3)  "unknown"
Copy the code

overdue

Setex name 5 codehole # 5s expires, equivalent to set+expireCopy the code

A distributed lock

Setnx name codehole # Set creation if name does not existCopy the code

count

The increment has a range. The range is the maximum or minimum value of a signed long. Redis will report an error if it exceeds this value.

> set codehole 9223372036854775807  # Long.Max
OK

> incr codehole
(error) ERR increment or decrement would overflow
Copy the code

3. Common scenarios of String type

1, verification code: often in some websites for login, registration, obtain verification code and other operations, will receive some verification code, and said that after 10min invalid.

set phone_num code ex 600

Use the mobile phone number as the key and the verification code as the value, and the timeout is 6 minutes. Get phone_num and compare your input with the value stored in the database to verify your identity.

2, cache function: String String is the most commonly used data types, not just the redis, every language is the most basic type, therefore, to use redis as cache, in combination with other database as the storage layer, using redis support the characteristics of high concurrency, can greatly speed up the system of reading and writing, and reduce the pressure of the back-end database.

3. Counter: Many systems will use Redis as the real-time counter of the system, which can quickly realize the function of counting and querying. And the final data results can be dropped to the database or other storage media for permanent storage at a specific time.

4, bitmap: can be widely used, check-in, active, punch in and other scene statistics. Very nice

5. Distributed lock To ensure that distributed locks are available, we must ensure that the implementation of the lock meets at least the following four conditions:

  • Resource occupation: Mutually exclusive. Only one client can hold the lock at any time.
  • Life cycle: Deadlock does not occur. Even if one client crashes while holding the lock and does not unlock actively, it is guaranteed that subsequent clients can lock it.
  • Multi-redis: fault tolerant. Clients can lock and unlock as long as most Redis nodes are running properly.
  • The same person to unlock the lock: the bell must be tied to the bell. Lock and unlock must be the same client, the client can not unlock the lock added by others

PHP implementation:

class RedLock
{
    private $retryDelay;    // Retry interval
    private $retryCount;    // Number of retries
    private $clockDriftFactor = 0.01;
    private $quorum;
    private $servers = array(a);private $instances = array(a);function __construct(array $servers, $retryDelay = 200, $retryCount = 3)
    {
        $this->servers = $servers;
        $this->retryDelay = $retryDelay;
        $this->retryCount = $retryCount;
        $this->quorum  = min(count($servers), (count($servers) / 2 + 1));
    }

    public function lock($resource, $ttl)
    {
        $this->initInstances();
        $token = uniqid();
        $retry = $this->retryCount;

        do {
            $n = 0;
            $startTime = microtime( true ) * 1000;
            foreach ($this->instances as $instance) {
                if ($this->lockInstance($instance, $resource, $token, $ttl)) { $n++; }}// Add 2 ms to drift to take into account Redis expiration precision, i.e. 1 ms, plus 1 ms minimum drift for small TTL.
            $drift = ( $ttl * $this->clockDriftFactor ) + 2;
            $validityTime = $ttl - ( microtime( true ) * 1000 - $startTime ) - $drift;
            if ($n >= $this->quorum && $validityTime > 0) {
                return [
                    'validity' => $validityTime,
                    'resource' => $resource,
                    'token'    => $token,
                ];
            } else {
                foreach ( $this->instances as $instance ) {
                    $this->unlockInstance( $instance, $resource, $token ); }}// Wait a random delay before to retry
            $delay = mt_rand( floor( $this->retryDelay / 2 ), $this->retryDelay );
            usleep( $delay * 1000 );
            $retry--;
        } while ($retry > 0);
        return false;
    }

    public function unlock(array $lock)
    {
        $this->initInstances();
        $resource = $lock['resource'];
        $token    = $lock['token'];
        foreach ($this->instances as $instance) {
            $this->unlockInstance($instance, $resource, $token); }}private function initInstances(a)
    {
        if (empty($this->instances)) {
            foreach ($this->servers as $server) {
                list($host, $port, $timeout) = $server;
                $redis = new \Redis();
                $redis->connect($host, $port, $timeout);
                $this->instances[] = $redis; }}}private function lockInstance($instance, $resource, $token, $ttl)
    {
        return $instance->set($resource, $token, ['NX'.'PX' => $ttl]);
    }

    private function unlockInstance($instance, $resource, $token)
    {
        // Not only realize the same person lock unlock; In addition, if the unlock fails, the rollback can ensure that resources are occupied
        $script = ' if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end ';
        return $instance->eval($script, [$resource, $token], 1);
    }
}

$servers = [
    ['127.0.0.1'.6379.0.01]]; $redLock =new RedLock($servers);
$i2Count = 0;echo '<pre>';

while ( $i2Count < 10 ) {
    $lock = $redLock->lock('test'.10000);
    if ($lock) {
        print_r($lock);
        $ret2Unlock = $redLock->unlock( $lock );

        / /! $ret2Unlock rolls back all operations
    } else {
        print "Lock not acquired\n";
    }

    $i2Count++;
}
Copy the code

Four, the last

The article leaves problems because of its length

  • Distributed lock implementation ideas, scheme discussion
  • Use bitmap

This year and next

Reference reading:

  • Redis Deep Adventure — Lao Qian
  • Redis 5 design and source code Analysis — Chen Lei et al
  • “Redis In Action” — Josiah L. Carlson