Redis限流实践:实现用户消息推送每天最多通知2次的功能

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。
🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。
🏆本文已收录于PHP专栏:PHP进阶实战教程。
🏆另有专栏PHP入门基础教程,希望各位大佬多多支持❤️。
🎉欢迎 👍点赞✍评论⭐收藏
文章目录
- 🚀一、背景
- 🚀二、准备工作
- 🚀三、实现逻辑
- 🔎3.1 查询用户的已发送通知数量
- 🔎3.2 发送通知
- 🔎3.3 获取用户通知列表
- 🔎3.4 清理过期通知记录
- 🔎3.5 定时任务
- 🚀四、结语
🚀一、背景
在开发应用程序中,经常需要向用户推送消息通知,但是为了避免过多的打扰用户,我们希望限制每天最多通知2次。本篇博文将介绍如何使用 PHP 和 Redis 实现这一功能。

🚀二、准备工作
首先,我们需要准备好数据库和 Redis 服务。在 MySQL 数据库中创建一个 user_notifications 表, 包含以下字段:
id:主键自增长IDuser_id:用户IDcontent:通知内容created_at:记录创建时间
此外,还需要安装 Redis 扩展,在 PHP 中可以通过以下命令安装:
$ pecl install redis
常见的推送消息场景如下图。

🚀三、实现逻辑
🔎3.1 查询用户的已发送通知数量
在用户登录或接收新通知时,我们需要查询用户今天已发送的通知数量。我们可以利用 Redis 的 Sorted Set 数据结构来存储每个用户的通知记录。将用户ID作为 Sorted Set 的 key,通知的发送时间戳作为 score 值,这样就可以按照时间顺序存储用户的通知记录。
使用以下代码实现查询用户已发送通知数量的函数:
function getNotificationCount($userId) {$redis = new Redis();$redis->connect('127.0.0.1', 6379);$todayStart = strtotime('today'); // 当天开始的时间戳$todayEnd = strtotime('tomorrow') - 1; // 当天结束的时间戳$count = $redis->zcount('user_notifications:' . $userId, $todayStart, $todayEnd);return $count;
}
🔎3.2 发送通知
在发送通知之前,先检查用户已发送通知数量是否达到限制。如果已发送通知数量大于等于2,则不再发送新通知;否则,保存通知记录到数据库,并将通知记录的发送时间戳添加到 Redis Sorted Set 中。
使用以下代码实现发送通知的函数:
function sendNotification($userId, $content) {// 检查用户已发送通知数量$count = getNotificationCount($userId);if ($count >= 2) {return false;}// 保存通知记录到数据库$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');$stmt = $pdo->prepare("INSERT INTO user_notifications (user_id, content, created_at) VALUES (?, ?, NOW())");$stmt->execute([$userId, $content]);// 将通知记录的发送时间戳添加到 Redis Sorted Set$redis = new Redis();$redis->connect('127.0.0.1', 6379);$redis->zadd('user_notifications:' . $userId, time(), $content);return true;
}
🔎3.3 获取用户通知列表
用户可以通过接口或页面查看自己的通知列表。我们可以从数据库中查询用户的通知记录,并按照发送时间倒序排列。
使用以下代码实现获取用户通知列表的函数:
function getNotificationList($userId) {$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');$stmt = $pdo->prepare("SELECT * FROM user_notifications WHERE user_id = ? ORDER BY created_at DESC");$stmt->execute([$userId]);$notifications = $stmt->fetchAll(PDO::FETCH_ASSOC);return $notifications;
}
🔎3.4 清理过期通知记录
为了避免 Redis Sorted Set 中存储的用户通知记录过多,我们可以定时清理过期的通知记录。通过设置 Redis 的过期时间来实现自动清理。例如,我们可以设置 Sorted Set 的过期时间为2天,在用户查询通知列表时,先删除过期的通知记录,再返回有效的通知列表。
function cleanExpiredNotifications($userId) {$redis = new Redis();$redis->connect('127.0.0.1', 6379);// 设置 Sorted Set 的过期时间为2天$expireTime = strtotime('2 days ago');$redis->expireAt('user_notifications:' . $userId, $expireTime);
}
🔎3.5 定时任务
为了每天凌晨清理用户的通知记录,我们可以使用 Linux 的 crontab 来定时执行清理任务。编辑 crontab 文件,添加如下代码:
0 0 * * * php /path/to/clean_expired_notifications.php
并创建 clean_expired_notifications.php 文件,内容如下:
<?phprequire_once 'redis.php';$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $pdo->prepare("SELECT DISTINCT user_id FROM user_notifications");
$stmt->execute();$userIds = $stmt->fetchAll(PDO::FETCH_COLUMN);foreach ($userIds as $userId) {cleanExpiredNotifications($userId);
}
🚀四、结语
通过 PHP 和 Redis 实现用户消息推送每天最多通知2次的功能,并结合定时任务清理过期通知记录,可以有效地避免过多地打扰用户。以上是基本实现逻辑和代码示例,你可以根据自己的实际需求进行修改和扩展,例如根据不同用户设置不同的通知限制次数等。

推荐您阅读本专栏其他内容,PHP进阶实战教程,相信不会让您失望。如果你对上面的功能有疑问,随时欢迎与我交流。
相关文章:
Redis限流实践:实现用户消息推送每天最多通知2次的功能
🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师…...
uniapp 存储base64资源为http链接图片
1. 新建一个base64.js 文件 const fsm wx.getFileSystemManager(); // base64data base64资源 // name 文件名 function base64src(base64data, name, cb) {const time new Date().getTime();const filePath ${wx.env.USER_DATA_PATH}/${name}.${time}.png;const buffer …...
列表类控件虚拟化
WPF列表控件提供的最重要的功能是UI虚拟化(WPF编程宝典说的)。所有的WPF列表控件(所有继承自ItemsControl的控件,包括ListBox、CombBox、ListView、TreeView、DataGrid)都支持UI虚拟化。 UI虚拟化的支持实际上没有被构…...
c# 多线程Task.Run 取消正在执行的多线程
c# 异步处理,上次处理没有完成,下次有紧接着处理多线程出错 在 C# 中进行异步处理时,确保处理上一个任务完成后再处理下一个任务是很重要的,特别是在涉及多线程的情况下。如果上一个任务尚未完成,而下一个任务又开始执…...
sql server 如何设置主键
开始之前 限制和局限 一个表只能包含一个 PRIMARY KEY 约束。 在 PRIMARY KEY 约束中定义的所有列都必须定义为 NOT NULL。 如果没有指定为 Null 性,则加入 PRIMARY KEY 约束的所有列的为 Null 性都将设置为 NOT NULL。 创建主键会自动创建相应的唯一群集索引、…...
【LeetCode-中等题】19. 删除链表的倒数第 N 个结点
文章目录 题目方法一:节点加入集合找索引方法二:直接计算长度,然后找出要删除的节点的前一个节点方法三:栈方法四:前后双指针 题目 这题的关键在与两个点 一定要设置一个哑结点,防止删除第一个元素时,导致空…...
Matlab图像处理-减法运算
减法运算 图像减法也称为差分方法,是一种常用于检测图像变化及运动物体的图像处理方法。常用来检测一系列相同场景图像的差异,其主要的应用在于检测同一场景下两幅图像之间的变化或是混合图像的分离。 差影法 将同一景物在不同时问拍摄的图像或同一景…...
stm32之11.USART串口通信
可以添加上拉电阻,但会增加功耗,传输距离变长 要添加库函数USART 官方参考文档说明书位置 ALT+左键可实现整体删除(如下图) 输出模式第三种模式AF ---------------------- 源码 远程控制pc端 #include <stm32f4x…...
Python实现T检验
今天来分享一下T检验的python实现方法。 01 先来上一波概念。 1.单样本t检验,又称单样本均数t检验,适用于来自正态分布的某个样本均数与已知总体均数的比较,其比较目的是检验样本均数所代表的总体均数是否与已知总体均数有差别。已知总体均数…...
校招算法题实在不会做,有没有关系?
文章目录 前言一、校招二、时间复杂度1、单层循环2、双层循环 三、空间复杂度四、数据结构五、校招算法题实在不会做,有没有关系?六、英雄算法集训 前言 英雄算法联盟八月集训 已经接近尾声,九月算法集训将于 09月01日 正式开始,目…...
Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol
Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol 0. 版本0.1 SignatureChecker.sol 1. 目标合约2. 代码精读2.1 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) 0. 版本 [openzeppelin]:v4.8.3,[for…...
如何修改字符串内容?
⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:浅谈Java 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 String 1. 修改字符串2. StringBuilder和…...
pgadmin4中的备份与恢复
一,postgresql 数据的备份与恢复 (一)数据库备份与恢复 1,备份 windows环境 1> dump 逻辑备份 1,用管理员身份打开power shell 2,切换到本机 postgresql 安装目录下的 bin 目录: PS C…...
内网穿透——搭建私人影音媒体平台
文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...
使用psql操作PostgreSQL数据库
postgresql的操作和mysql差别较大。。 可以使用 psql 命令行工具或者其他的 PostgreSQL 客户端工具来查看表。如下是使用 psql 命令行工具查看表的方法: 连接到 PostgreSQL 数据库: 如果一个PostgreSQL的连接为 postgresql://用户名:密码127.0.0.1:5432/…...
什么是网络取证(Network Forensics)
企业采用新技术来检查其网络安全是否存在零日漏洞,与立即指示问题的物理层不同,黑客攻击尝试可能会被忽视并变得严重,直到对网络流量有一个整体的可见性。通过实时监控来跟踪其源和目标的流量,以查明问题或潜在问题的根源。 什么…...
农村农产品信息展示网站的设计与实现(论文+源码)_kaic
摘 要 随着软件技术的迅速发展,农产品信息展示的平台越来越多,传统的农产品显示方法将被计算机图形技术取代。这种网站技术主要把农产品的描述、农产品价格、农产品图片等内容,通过计算机网络的开发技术,在互联网上进行展示,然后通过计算机网…...
keepalived+lvs(DR)(四十六)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、作用 二、调度器配置 三、web节点配置 一、作用 使用keepalived解决lvs的单点故障 高可用集群 二、调度器配置 安装keepalived yum install -y k…...
从数据孤岛到企业xPA的演化
“数据孤岛”一直以来是企业在信息化进程中面临的比较头疼的问题,由于数据独立存在于不同部门之中,无法进行相互联动,致使数据库无法兼容,这无形中加大了跨部门合作的沟通成本。在此背景下,一种新兴的规划方法——扩展…...
视觉注意力收集
参考博文:神经网络学习小记录64——Pytorch 图像处理中注意力机制的解析与代码详解_pynq 注意力机制_Bubbliiiing的博客-CSDN博客 【计算机视觉】详解 自注意力:Non-local 模块与 Self-attention (视觉注意力机制 (一))_自注意力模块_何处闻韶的博客-CS…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
