Рубрики
Uncategorized

Используйте растровое изображение redis для реализации функции регистрации (версия PHP)

Автор оригинала: David Wong.

Что необходимо оптимизировать, пожалуйста, укажите в своих комментариях

I. спрос

Record user sign in, query user sign in

2, Техническое предложение

1. Используйте MySQL (поле времени max’u-это последовательные дни регистрации)

Ход мыслей: (1) Когда пользователь регистрируется, вставьте запись и запросите, следует ли регистрироваться вчера в соответствии со временем создания. Если есть регистрация заезда, максимальное время на первоначальной основе + 1. В противном случае будет обнаружена максимальная (2) регистрация. Запросите, существует ли запись в соответствии со временем “Идентификатор пользователя и создание”. Если он не существует, это означает, что он не зарегистрирован

2. Используйте функцию растрового изображения redis

Train of thought:
(1) Each user has a separate redis record every month, such as 00101010101010. From left to right, it represents 01-31 days (there are several days in each month, just a few days)
(2) In the early morning of the 8th day of each month, the redis records are uniformly moved to MySQL, as shown in the figure below
(3) Query the current month from redis, and get from MySQL last month

3. Сравнение схем

Example: 10000 users sign in 365 days
Scheme 1: insert 3.65 million records into MySQL
·Frequent requests for database logging waste server overhead.
·As time goes on, the data increases dramatically
·The efficiency of massive data retrieval is not high. At the same time, only create time can be used as the interval query condition, and the large amount of data must be slow

Scheme 2: insert 12W records into MySQL
·Save space. Each user only occupies 1 bit of space and 1 W users generate 10000 bit = 1050 bytes of data every day, which is about 1 KB
·Fast memory operation

3. Реализация (сценарий 2)

1. Ключевая структура

Prefix: year, month: user ID -- sign: 2019: 10:01
Enquiries:
Single: keys sign? 2019? 10? 01
All: keys sign_*
Months: keys sign*

2. Структура таблицы MySQL

3. Код (список 1 вызывающий метод и 3 класса)

(1) Способ регистрации

public static function userSignIn($userId)
    {
        $time = Time();
        $today = date('d', $time);
        $year = date('Y', $time);
        $month = date('m', $time);
        $signModel = new Sign($userId,$year,$month);
        //1. Check in information of users today
        $todaySign = $signModel->getSignLog($today);
        if ($todaySign) {
            Return self:: jsonarr (- 1, 'you have checked in', []);
        }
        try {
            Db::startTrans();
            $signModel->setSignLog($today);
            //4. Bonus points
            if (self::SING_IN_SCORE > 0) {
                $dataScore['order_id'] = $userId.'_'.$today;
                $datascore ['type '] = 2; // 2. Check in
                $datascore ['remark '] =' check in to get points';
                Finance::updateUserScore(Finance::OPT_ADD, $userId, self::SING_IN_SCORE, $dataScore);
            }
            $code = '0';
            $MSG = 'sign in succeeded';
            $score = self::SING_IN_SCORE;
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $code = '-2';
            $MSG = 'sign in failed';
            $score = 0;
        }
        return self::jsonArr($code, $msg, ['score' => $score]);
    }

(2) Базовый класс Redis

php

namespace app\common\redis\db1;

/**
 *Redis operation class
 */
class RedisAbstract
{

    /**
     *Connected Libraries
     * @var int
     */
    Protected $_db = 1; // database name
    Protected $_tablename = '; // table name

    static $redis = null;

    public function __construct()
    {
        return $this->getRedis();
    }

    public function _calcKey($id)
    {
        return $this->_tableName . $id;
    }

    /**
     * find key
     * @param $key
     * @return array
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function keys($key)
    {
        return $this->getRedis()->keys($this->_calcKey($key));
    }

    /**
     *Get the setting parameters of whether to turn on caching
     *
     * @return boolean
     */
    public function _getEnable()
    {
        $conf = Config('redis');
        return $conf['enable'];
    }

    /**
     *Get redis connection
     *
     * @staticvar null $redis
     * @return \Redis
     * @throws \Exception
     */
    public function getRedis()
    {
        if (!self::$redis) {
            $conf = Config('redis');
            if (!$conf) {
                Throw new \ exception ('redis connection must be set ');
            }

            self::$redis = new \Redis();
            self::$redis->connect($conf['host'], $conf['port']);
            self::$redis->select($this->_db);
        }
        return self::$redis;
    }

    /**
     *Set bitmap
     * @param $key
     * @param $offset
     * @param $value
     * @param int $time
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function setBit($key, $offset, $value, $time = 0)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        $result = $this->getRedis()->setBit($key, $offset, $value);
        if ($time) {
            $this->getRedis()->expire($key, $time);
        }
        return $result;
    }

    /**
     *Get bitmap
     * @param $key
     * @param $offset
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function getBit($key, $offset)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        return $this->getRedis()->getBit($key, $offset);
    }

    /**
     *Statistical bitmap
     * @param $key
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function bitCount($key)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        return $this->getRedis()->bitCount($key);
    }

    /**
     *Bitmap operation
     * @param $operation
     * @param $retKey
     * @param mixed ...$key
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function bitOp($operation, $retKey, ...$key)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        return $this->getRedis()->bitOp($operation, $retKey, $key);
    }

    /**
     *Calculates the first occurrence of 1 or 0 in a bitmap segment
     * @param $key
     * @param $bit 1/0
     * @param $start
     * @param null $end
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function bitPos($key, $bit, $start, $end = null)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        return $this->getRedis()->bitpos($key, $bit, $start, $end);
    }

    /**
     *Delete data
     * @param $key
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function del($key)
    {
        if (!$this->_getEnable()) {
            return null;
        }
        return $this->getRedis()->del($key);
    }

}

(3) Войдите в класс операций redis

keySign = $this->keySign . '_' . $year . '_' . $month . ':' . $userId;
    }

    /**
     *User sign in
     * @param $day
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function setSignLog($day)
    {
        return $this->setBit($this->keySign, $day, 1);
    }

    /**
     *Check in record
     * @param $day
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function getSignLog($userId,$day)
    {
        return $this->getBit($this->keySign, $day);
    }

    /**
     *Delete sign in record
     * @return int|null
     * @throws \Exception
     * @author wenzhen-chen
     */
    public function delSignLig()
    {
        return $this->del($this->keySign);
    }
}

(4) Регулярно обновляйте класс MySQL

keys('sign_' . $year . '_' . $month . ':*');
        foreach ($keys as $key) {
            $bitlog = ''; // user's attendance record in the current month
            $userData = explode(':', $key);
            $userId = $userData[1];
            //3. Cycle to query whether the user has signed in (it is not stored by the number of days per month, but directly stored for 31 days)
            for ($i = 1; $i <= 31; $i++) {
                $isSign = $signModel->getBit($key, $i);
                $bitLog .= $isSign;
            }
            $data[] = [
                'user_id' => $userId,
                'year' => $year,
                'month' => $month,
                'bit_log' => $bitLog,
                'create_time' => $time,
                'update_time' => $time
            ];
        }
        //4. Insert log
        if ($data) {
            $logModel = new SignLog();
            $logModel->insertAll($data, '', 100);
        }

    }
}

Оригинал: “https://developpaper.com/use-redis-bitmap-bitmap-to-implement-check-in-function-php-version/”