Применение и практика Redis в веб-проектах

Redis

В качестве высокопроизводительной системы хранения на основе памяти с открытым исходным кодом (BSD) Redis широко используется крупными интернет-компаниями и имеет множество сценариев применения. Эта статья подробно объяснит основное применение и практику Redis в веб-проектах на основе PHP.

тайник

Представленный здесь кеш относится к данным, которые могут быть потеряны или просрочены. Общие командыset, hset, get, hget, вам необходимо обратить внимание на следующие проблемы при использовании Redis в качестве кеша:

  • Из-за ограниченной памяти redis невозможно добиться бесконечного роста памяти Redis.maxmemoryмаксимальная память.
  • Когда maxmemory включен, можно включить механизм lru для установки срока действия ключа.Когда будет достигнут максимальный объем памяти Redis, Redis автоматически удалит ключ в соответствии с наименее использовавшимся алгоритмом.
  • Стратегия персистентности Redis и время восстановления после сбоя Redis — это игровой процесс.Если вы хотите восстановиться как можно быстрее в случае сбоя, вам следует включить механизм резервного копирования дампа, но для этого требуется больше доступного места в памяти для персистентности. . Если вы можете мириться с длительным временем восстановления после сбоя Redis, вы можете использовать механизм сохраняемости AOF и отключить механизм дампа, который не требует дополнительного места в памяти.

место хранения

В веб-проектах Redis может хранить данные, которые считываются и записываются очень часто, чтобы уменьшить нагрузку на такие базы данных, как MySQL. Если в качестве системы хранения используется Redis, во избежание потери данных необходимо включить сохраняемость.

Типичная сцена

  • прилавок

Потребность в счетчиках очень распространена, например, количество лайков Weibo, количество избранных постов, количество перепостов статей и количество подписчиков пользователей.

  • социальный список

Например, используйте структуру Sets для хранения списков наблюдения, списков избранного, списков лайков и т. д.

  • Session

Благодаря высокопроизводительному хранилищу ключей и значений redis статус входа пользователя можно сохранить в redis.

  • ...

очередь

простая очередь

Обычно списковая структура Redis используется как очередь.rpushНовости производства,lpopпотреблять сообщения, когдаlpopПри отсутствии сообщения следует выполнить соответствующую операцию ожидания.

$queueKey = "queue";

// 生产者
$redis->rpush($queueKey, $data)

// 消费者
while (true) {
    $data = $redis->lpop($queueKey);
    if (null === $data) {
        usleep(100000);
        continue;
    }
    // 业务逻辑
    ...
}

Поскольку событие сна, используемое при отсутствии сообщения, нелегко контролировать, старайтесь не использовать сон для сна в производственной среде, вы можете использоватьblpopдля потребления сообщений, а когда новых сообщений нет, он будет блокироваться до тех пор, пока сообщение не поступит.

очередь задержки

Очередь задержки может использовать Redissorted setструктура данных, используя метку времени какscore, содержание сообщенияmember,использоватьzaddкоманда для создания сообщений, потребители используютzrangebyscoreКоманда получает опрос данных сообщения до указанного времени обработки.

$queueKey = "queue";

// 生产消息

// 消费时间, 这里设置为1小时候
$consumeTimestamp = time() + 3600;
// $data需要添加随机串前缀(or后缀),防止出现重复member被丢弃
$data = $data . md5(uniqid(rand(), true));
$redis->zadd($queueKey, $consumeTimestamp, $data);

// 消费消息
while (tue) {
    $arrData = $redis->zrangebyscore($queueKey, 0, time());
    if (!$arrData) {
        usleep(100000);
        continue;
    }
    // 业务逻辑
    foreach ($arrData as $data) {
        $data = substr($data, 0, strlen($data) - 32);
        
        // 消费$data

    }
}

многопользовательский

Используя шаблон подписчика темы публикации/подписки, можно реализовать очередь сообщений 1:N. В этом режиме, когда потребитель выходит из сети, созданное сообщение будет потеряно, что здесь не рекомендуется.

Следует подчеркнуть, что не рекомендуется использовать Redis в качестве службы очереди сообщений, что не является целью разработки Redis. Если вы должны использовать его, подумайтеdisque, разработан автором redis.

Распределенная блокировка

Распределенные блокировки в основном решают несколько задач:

  • Взаимное исключение: только один сервис (или приложение) может получить доступ к ресурсу одновременно
  • Безопасность: блокировки могут быть сняты только службой (или приложением), удерживающей блокировку.
  • Отказоустойчивость: блокировки по-прежнему могут быть сняты при сбое службы, удерживающей блокировку.
  • избежать тупика

план 1

мы можем рассмотреть возможность использованияsetnxа такжеexpireКоманда для достижения блокировки, то есть при отсутствии ключа значение будет успешно записано:

$lockStatus = $redis->setnx($lockKey, 1);
if (1 === $lockStatus) {
    // 加锁成功,为锁设置超时时间
    $redis->expire($lockKey, 300);

    // 进行后续操作

} elseif (0 === $lockStatus) {
    // 加锁失败
} else {
    // 其他异常
}

Однако эта операция не является атомарной, если во время setnx произойдет сбой сервиса, а времени на установку таймаута на Ключе нет, блокировка никогда не будет снята.

Сценарий 2

мы рекомендуемset key value [EX seconds] [PX milliseconds] [NX|XX]команда на блокировку

  • EX: через сколько секунд истекает срок действия ключа
  • PX: через сколько миллисекунд истекает срок действия ключа
  • NX: когда ключ не существует, ключ создается, эффект эквивалентен setnx
  • XX: если ключ существует, перезаписать ключ
$lockStatus = $this->redis->set($lockKey, 1, "EX", 30, "NX");
if ("OK" === $lockStatus) {
    // 加锁成功,可进行后续操作
    
    //业务逻辑执行完毕,释放锁
    $this->redis->del($lockKey);

} elseif (null === $lockStatus) {
    // 加锁失败
}

Как показано в приведенном выше коде, еслиsetКоманда возвращает OK, после чего клиент может получить блокировку (если она возвращает значение null, служба приложения может повторить попытку получения блокировки через некоторое время) и можетdelКоманда для отпускания блокировки.

Этот метод требует внимания к проблеме:

  • Блокировка (ключ), полученная службой a, была удалена сервером redis, поскольку срок действия истек, но в это время служба все еще выполняет команду DEL. И служба b повторно получает блокировку с тем же ключом после истечения срока действия, установленного параметром a, затем выполняется a.delБлокировка, добавленная службой b, будет снята.
  • Когда срок действия большого количества ключей истекает одновременно, удаление ключей приведет к увеличению давления повторного доступа и повлияет на стабильность службы.

Приведенную выше систему блокировки можно сделать более надежной за счет следующих оптимизаций:

  • Вместо того, чтобы задавать фиксированную строку, задайте для нее случайную большую строку, которую можно назвать токеном.
  • Удалить ключ указанного замка скриптом, вместоdelЗаказ.
  • Добавить случайное значение при установке срока действия ключа.

Оптимизированный код может относиться к следующему:

$lockToken = md5(uniqid(rand(), true));
// 此处超时时间根据具体业务逻辑配置
$expire = rand(280, 320);
$lockStatus = $this->redis->set($lockKey, $lockToken, "EX", $expire, "NX");
if ("OK" === $lockStatus) {
    // 加锁成功,可进行后续操作
    
    // 业务逻辑执行完毕,释放锁
    // 删除锁之前需要判断是否是自己上的锁
    $currentToken = $this->redis->get($lockKey);
    if ($currentToken === $lockToken) {
        $this->redis->del($lockKey);
    }

} elseif (null === $lockStatus) {
    // 加锁失败
}

рассчитать

Метод атомарного самоувеличения и упорядоченная структура набора, предоставляемые Redis, могут выполнять некоторые вычислительные задачи, такие как статистика просмотров страниц.

Количество просмотров

Просмотры статьи +1

$redis->incr($postsKey);

Получите просмотры статей в пакетном режиме

$arrPostsKey = [
    //...
];
$arrPostsViewNum = $redis->mget($arrPostsKey);

Таблица лидеров

Вы можете использовать упорядоченный набор redis для реализации функции таблицы лидеров, а баллы используются в качестве веса для сортировки и взятия первых n записей.

// 存储数据
$sortKey = "sort_key";
$redis->zadd($sortKey, 100, "tom");
$redis->zadd($sortKey, 80, "Jon");
$redis->zadd($sortKey, 59, "Lilei");
$redis->zadd($sortKey, 87, "Hanmeimei");

// 获取排行

// 由大到小排序
$arrRet = $redis->zrevrange($sortKey, 0, -1, true);

// 由小到大排序
$arrRet = $redis->zrange($sortKey, 0, -1, true);

конец

В Redis задействовано множество практик применения. Из-за ограниченного объема в этой статье представлены только наиболее часто используемые сценарии в веб-приложениях. Студенты, которые хотят еще больше расширить свои знания о Redis, могут обратиться к следующим ссылкам для дальнейшего изучения.

Оригинальная ссылка:Применение и практика Redis в веб-проектах

Отсканируйте код и подпишитесь на общедоступную учетную запись WeChat: Learn2Code