合理的使用缓存策略对开发同学来讲,就好像孙悟空习得自在极意功一般~

抛出问题

Redis如何批量设置过期时间呢?

不要说在foreach中通过set()函数批量设置过期时间

给出方案

我们引入redis的PIPLINE,来解决批量设置过期时间的问题。

PIPLINE的原理是什么?

  1. 未使用pipline执行N条命令

  1. 使用pipline执行N条命令

通过图例可以很明显的看出来PIPLINE的原理:

客户端通过PIPLINE拼接子命令,只需要发送一次请求,在redis收到PIPLINE命令后,处理PIPLINE组成的命令块,减少了网络请求响应次数。

网络延迟越大PIPLINE的优势越能体现出来

拼接的子命令条数越多使用PIPLINE的优势越能体现出来

注意:并不是拼接的子命令越多越好,N值也有是上限的,当拼接命令过长时会导致客户端等待很长时间,造成网络堵塞;我们可以根据实际情况,把大批量命令拆分成几个PIPLINE执行。

代码封装

//批量设置过期时间
public static function myPut(array $data, $ttl = 0)
{
if (empty($data)) {
return false;
} $pipeline = Redis::connection('cache')
->multi(\Redis::PIPELINE);
foreach ($data as $key => $value) {
if (empty($value)) {
continue;
}
if ($ttl == 0) {
$pipeline->set(trim($key), $value);
} else {
$pipeline->set(trim($key), $value, $ttl);
}
}
$pipeline->exec();
}

项目实战

需求描述

  1. 打开APP,给喜欢我的人发送我的上线通知(为了避免打扰,8小时内重复登录不触发通知)

  2. 每个人每半小时只会收到一次这类上线通知(即半小时内就算我喜欢的1万人都上线了,我也只收到一次喜欢的人上线通知)

要点分析

  1. 合理使用缓存,减少DB读写次数

  2. 不仅要减少DB读写次数,也要减少Redis的读写次数,使用PIPLINE

代码实现解析

  1. canRecall() 写的比较优雅,先判断是否已发送的标记,再判断HouseOpen::getCurrentOpen(),因为HouseOpen::getCurrentOpen()是要查询DB计算的,这种代码要尽可能少的被执行到,减少DB查询。

  2. array_diff() 取差集的思路,获得需要推送的人

封装工具类

<?php

namespace App\Model\House;

.
.
. class HouseLikeRecallUser
{
protected $_userid = '';
protected $_availableUser = [];
protected $_recallFlagKey = ''; const TYPE_TTL_HOUSE_LIKE_RECALL = 60 * 30; //半小时后可以再次接收到喜欢的xxx进入通知
const TYPE_TTL_HOUSE_LIKE_RECALL_FLAG = 60 * 60 * 8; //8小时重复登录不触发 //初始化 传入setRecalled 的过期时间
public function __construct($userid)
{
$this->_userid = $userid;
//登录后给喜欢我的人推送校验:同一场次重复登录不重复发送
$this->_recallFlagKey = CacheKey::getCacheKey(CacheKey::TYPE_HOUSE_LIKE_RECALL_FLAG, $this->_userid);
} //设置当前用户推送标示
public function setRecalled()
{
Cache::put($this->_recallFlagKey, 1, self::TYPE_TTL_HOUSE_LIKE_RECALL_FLAG);
} //获取当前用户是否触发推送
public function canRecall()
{
$res = false;
if (empty(Cache::get($this->_recallFlagKey))) {
$houseOpen = HouseOpen::getCurrentOpen();
if ($houseOpen['status'] == HouseOpen::HOUSE_STATUS_OPEN) {
$res = true;
}
}
return $res;
} //获取需要推送用户
public function getAvailableUser()
{
//获得最近喜欢我的用户
$recentLikeMeUser = UserRelationSingle::getLikeMeUserIds($this->_userid, 100, Utility::getBeforeNDayTimestamp(7)); //获得最近喜欢我的用户的 RECALL缓存标记
foreach ($recentLikeMeUser as $userid) {
$batchKey[] = CacheKey::getCacheKey(CacheKey::TYPE_HOUSE_LIKE_RECALL, $userid);
} //获得最近喜欢我的且已经推送过的用户
$cacheData = [];
if (!empty($batchKey)) {
$cacheData = Redis::connection('cache')->mget($batchKey);
} //计算最近喜欢我的用户 和 已经推送过的用户 的差集:就是需要推送的用户
$this->_availableUser = array_diff($recentLikeMeUser, $cacheData);
return $this->_availableUser;
} //更新已经推送的用户
public function updateRecalledUser()
{
//批量更新差集用户
$recalledUser = [];
foreach ($this->_availableUser as $userid) {
$cacheKey = CacheKey::getCacheKey(CacheKey::TYPE_HOUSE_LIKE_RECALL, $userid);
$recalledUser[$cacheKey] = $userid;
}
//批量更新 设置过期时间
self::myPut($recalledUser, self::TYPE_TTL_HOUSE_LIKE_RECALL);
} //批量设置过期时间
public static function myPut(array $data, $ttl = 0)
{
if (empty($data)) {
return false;
} $pipeline = Redis::connection('cache')
->multi(\Redis::PIPELINE);
foreach ($data as $key => $value) {
if (empty($value)) {
continue;
}
if ($ttl == 0) {
$pipeline->set(trim($key), $value);
} else {
$pipeline->set(trim($key), $value, $ttl);
}
}
$pipeline->exec();
}
}

调用工具类

public function handle()
{
$userid = $this->_userid;
$houseLikeRecallUser = new HouseLikeRecallUser($userid);
if ($houseLikeRecallUser->canRecall()) {
$recallUserIds = $houseLikeRecallUser->getAvailableUser();
$houseLikeRecallUser->setRecalled();
$houseLikeRecallUser->updateRecalledUser();
//群发推送消息
.
.
.
}
}

总结

不同量级的数据需要不同的处理办法,减少网络请求次数,合理使用缓存,是性能优化的必经之路。

进一步思考

如果我喜欢的1万人同时上线(秒级并发),我只收到一个消息推送,要避免被通知轰炸,怎么解决这类并发问题呢?

小伙伴们有没有解决思路,可以在评论区讨论哦~

相关阅读推荐

性能优化反思:不要在for循环中操作DB

性能优化反思:不要在for循环中操作DB 进阶版

最后

:觉得有收获请点个赞鼓励一下!

:收藏文章,方便回看哦!

:评论交流,互相进步!

本文由博客一文多发平台 OpenWrite 发布!

Redis 如何批量设置过期时间?PIPLINE的使用的更多相关文章

  1. redis批量设置过期时间

    Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作.代码如下: redis-cli keys &qu ...

  2. 针对永久不过期的key 批量设置过期时间

    问题需求: redis内存暴增,后来发现有很多设置永久不过期. 解决:查找出来之后针对前缀批量设置过期时间 (过期时间与开发沟通 保证服务不受影响) 来源于网上杨一的代码 正好解决了我遇到的问题 在这 ...

  3. redis 一二事 - 设置过期时间,以文件夹形式展示key显示缓存数据

    在使用redis时,有时回存在大量数据的时候,而且分类相同,ID相同 可以使用hset来设置,这样有一个大类和一个小分类和一个value组成 但是hset不能设置过期时间 过期时间只能在set上设置 ...

  4. redis文档翻译_key设置过期时间

    Available since 1.0.0.    使用開始版本号1.01 Time complexity: O(1)  时间复杂度O(1) 出处:http://blog.csdn.net/colum ...

  5. redis string类型设置过期时间后 再进行set操作,会清除过期时间

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_41756437/article/d ...

  6. 查询redis中没有设置过期时间的key

    #!/bin/sh ## 该脚本用来查询redis集群中,哪些key是没有设置过期时间,对应只需要修改redis的其中一个实例的 host和port ## 脚本会自动识别出该集群的所有实例,并查出对应 ...

  7. 如何使用Senparc.Weixin SDK 底层的Redis缓存并设置过期时间

    最近在微信第三方平台项目开发中,有一个需求,所有绑定的公众号的回复规则按照主公众号的关键词配置来处理,我的处理思路是获取主公众号配置的关键词回复规则,缓存10分钟,由于需要使用Redis缓存来存储一些 ...

  8. python redis 批量设置过期key

    在使用 Redis.Codis 时,我们经常需要做一些批量操作,通过连接数据库批量对 key 进行操作: 关于未过期: 1.常有大批量的key未设置过期,导致内存一直暴增 2.rd需求 扫描出这些ke ...

  9. redis中的key设置过期时间

    EXPIRE key seconds 为给定  key  设置生存时间,当  key  过期时(生存时间为  0  ),它会被自动删除. 在 Redis 中,带有生存时间的  key  被称为『易失的 ...

随机推荐

  1. C++面向对象编程之堆、栈和内存形式

    1.stack 是存在与某个作用域的一块内存空间,当调用函数时,函数就会形成一个stack 存这它的一些参数.返回地址等,生闷气在函数执行完会自动消灭: 2.heap 是操作系统提供的全局的内存空间, ...

  2. oneplus8手机蓝牙连接tws耳机无法双击退出语音助手

    通过蓝牙协议栈我们知道,蓝牙耳机可以通过发送AT指令唤醒或者退出语音助手 唤醒语音助手: AT+BVRA=1 退出语音助手: AT+BVRA=0 但是实际操作中发现双击可以唤醒但再次双击却无法退出语音 ...

  3. AspNetCore中 使用 Grpc 简单Demo

    为什么要用Grpc 跨语言进行,调用服务,获取跨服务器调用等 目前我的需要使用 我的抓取端是go 写的 查询端用 Net6 写的 导致很多时候 我需要把一些临时数据写入到 Redis 在两个服务器进行 ...

  4. flutter系列之:builder为构造器而生

    目录 简介 Builder StatefulBuilder LayoutBuilder 总结 简介 flutter中有很多种Builder,虽然所有的builder都是构造器,但是不同的builder ...

  5. grpc中的拦截器

    0.1.索引 https://waterflow.link/articles/1665853719750 当我们编写 HTTP 应用程序时,您可以使用 HTTP 中间件包装特定于路由的应用程序处理程序 ...

  6. 《HelloGitHub》第 79 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...

  7. SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

    大家好,这篇文章跟大家聊下 SpringCloudAlibaba 中的微服务组件 Nacos.Nacos 既能做注册中心,又能做配置中心,这篇文章主要来聊下做配置中心时 client 端的一些设计,主 ...

  8. 第2-3-2章 环境搭建-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5. 文件服务开发 5.1 环境搭建 5.1.1 数据库环境搭建 5.1.2 Nacos环境搭建 5.1.3 Nginx环境搭建 5.1.4 maven工程环境搭建 5. 文件服务开发 全套代码 ...

  9. 1 c++编程基础

    重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦! 生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦! 1 c++揭开面纱 1.1 编程 ...

  10. easyUI ajax拼接样式失效

    重新渲染:  $.parser.parse()