
最近沉迷于业务开发无法自拔 ,有一段时间没有更新博文了,后续博文内容计划把一些业务场景下的实战方案,或者比较好的设计思路进行分享,就不像之前围绕着一个主题,消耗很多的时间去整理相关内容(憋大招),后续可能一篇的内容量就没那么丰富,但是尽可能针对一个点进行更细化,或者更深入的分析,通过不断分享和自我复盘,进行经验的沉淀,同时提高博文分享的频率
场景
场景1
留言功能限制,30秒 内只能评论 10次,超出次数不让能再评论,并提示:过于频繁
场景2
点赞功能限制,10秒 内只能点赞 10次,超出次数后不能再点赞,并禁止操作 1个小时,提示:过于频繁,被禁止操作1小时
场景3
上传记录功能,限制一天只能上传 100次,超出次数不让能再上传,并提示:超出今日上线
抽离本质
在业务开发的过程中,我们不断的参与各种业务场景的方案设计,往往很容易碰到很类似的场景,只不过当前所属的业务模块不一样,其实这些需求的本质是解决同一个问题,当遇到这种场景的时候,我们需要根据自己经验分析抽离出需求的本质问题,实现一个通用的解决方案,让自己的解决方案更有价值,这可能就是区别于你是有灵魂的工程师还是cp(copy paste)最强王者吧。
分析上面3个业务场景,可以从中发现其中有相似的逻辑,称它为同类的问题,现在我们就是要抽离这个问题,设计一个通用的解决方案,勾画相同逻辑流程图:

通过分析上面的需求场景,抽离出他们都需要的那些条件:
限制对象:用户限制操作(评论,点赞,记录, ...)时间范围X秒内限制操作数Y次超出后禁止操作时间Z(秒/具体时间)超出后不让再操作,并提示

白瓜面试
白瓜面试 - AI面试助手,辅助笔试面试神器
162
查看详情
(最小时间单位用秒:天/小时/分钟都可换算成秒,用秒可以解决更多的场景)
如果把功能抽离成一个通用函数是不是大概是这样:
<?php/**
* 频率限制
* @param string $action 操作动作
* @param int $userId 发起操作的用户ID
* @param int $time 时间范围X秒内
* @param int $number 限制操作数Y次
* @param array $expire 超出封印时间Z ['type'=>1,'ttl'=>过期时间/秒] ['type'=>2,'ttl'=>具体过期时间戳] 二选一
* @return bool
* @throws \Exception
*/public static function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = []){ // todo 根据用户操作动作时间范围,进行频率的控制和失效释放}解决方案落地
功能中需要对用户发起的操作和时间,以及累计次数进行存储,并且需要失效过期的清理,如果这个时候我们依赖mysql做存储,想想都觉的挺痛苦,这里主角:redis 终于登场了,基于redis特性,incr的原子操作和key 支持过期机制,内存存储的效率优势,可以相对简单灵活并且又高效的完成目的。
这里简单实现个通用功能的代码:
<?php/**
* 频率限制
* @param string $action 操作动作
* @param int $userId 发起操作的用户ID
* @param int $time 时间范围X秒内
* @param int $number 限制操作数Y次
* @param array $expire 超出封印时间Z ['type'=>1,'ttl'=>过期时间/秒] ['type'=>2,'ttl'=>具体过期时间戳] 二选一
* @return bool
* @throws \Exception
*/public function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = []){ if (empty($action) || $userId <= 0 || $time <= 0 || $number <= 0) { throw new \Exception('非法参数');
}
$key = 'act:limit:' . $action . ':' . $userId;
$r = RedisClient::connect(); //获取当前累计次数
$current = intval($r->get($key)); if ($current >= $number) return false; //累计并返回最新值
$current = $r->incr($key); //第一次累加,设置控制操作频率的有效时间
if ($current === 1) $r->expire($key, $time); //未超出限制次数先放过
if ($current < $number) return true; //超出后根据需要重新设置过期失效时间 $current === $number 判断保证只重新设置一次
$type = empty($expire['type']) ? 0 : intval($expire['type']);
$ttl = empty($expire['ttl']) ? 0 : intval($expire['ttl']); if ($current === $number && $ttl > 0 && in_array($type, [1, 2])) { if ($type === 1) $r->expire($key, $ttl); if ($type === 2) $r->expireAt($key, $ttl);
} return false;
}//场景1/**
* 评论限制
* @param int $userId
* @return bool|string
*/public function doComment(int $userId){ try {
$pass = FrequencyLimit::doHandle('comment', $userId, 30, 10); if (!$pass) return '过于频繁'; // todo 评论逻辑
return true;
} catch (\Exception $e) { return $e->getMessage();
}
}//场景2/**
* 点赞限制
* @param int $userId
* @return bool|string
*/public function doLike(int $userId){ try {
$pass = FrequencyLimit::doHandle('like', $userId, 10, 10, ['type' => 1, 'ttl' => 1 * 60 * 60]); if (!$pass) return '过于频繁,被禁止操作1小时'; // todo 点赞逻辑
return true;
} catch (\Exception $e) { return $e->getMessage();
}
}//场景3/**
* 上传限制
* @param int $userId
* @return bool|string
*/public function doUpload(int $userId){ try {
$expire = strtotime(date('Y-m-d', strtotime(+1 . 'days')));
$pass = FrequencyLimit::doHandle('upload', $userId, 1 * 24 * 60 * 60, 100, ['type' => 2, 'ttl' => $expire]); if (!$pass) return '超出今日上线'; // todo 上传逻辑
return true;
} catch (\Exception $e) { return $e->getMessage();
}
}//场景N编码上可以根据你设计这个通用方案的复杂度进行进一步抽象,如抽象成频率限制的功能类等
总结
对相似的业务场景进行分析,发现本质问题并设计通用的解决方案
让解决方案更有价值,做一个有灵魂的开发者
熟练掌握redis,充分利用它的特性和优势
更多Redis相关技术文章,请访问Redis教程栏目进行学习!
以上就是Redis实战之限制操作频率的详细内容,更多请关注其它相关文章!
# 相关内容
# 网站规划与建设实验心得
# 推广网站的创意怎么弄
# 南京品牌网站优化哪家好
# 江门网站内容建设
# 廊坊户型优化分享网站
# 沧州手机网站建设价格
# 综合网站推广有用吗
# 县政府网站建设
# 营销推广的目的是什么
# phpcms 栏目seo标题
# Redis
# 今日
# 自己的
# 如何实现
# 网络带宽
# 能再
# 封印
# 更有
# 博文
# 上传
# 限制操作频率
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
PHP动态导航按钮:根据用户登录状态切换链接与文本
《豆瓣》私信用户方法
折叠屏手机充不进电是什么问题? 特殊结构带来的维修难点
CSS如何控制元素外边距_margin实现布局间隔
《tt语音》超级玩家开通方法
123网页端官方登录页 123邮箱网页版即时通讯服务
一点万象签到领积分指南
mysql如何管理数据库账户_mysql数据库账户管理技巧
谷歌学术论文搜索引擎 谷歌学术官网入口论坛永久链接
行者app怎样导出日志
疯狂小鸟微信小游戏入口 疯狂小鸟网页版秒玩
Sublime怎么快速复制文件路径_Sublime右键菜单增强技巧
外卖小程序对接第三方配送
c++20的指定初始化(Designated Initializers)怎么用_c++ C风格结构体初始化
mysql归档数据怎么导出为csv_mysql归档数据导出为csv文件的方法
mysql如何限制远程访问_mysql远程访问限制方法
《猎聘》筛选猎头岗位方法
J*a中的值传递到底指什么_值传递模型在参数传递中的真正含义说明
51漫画网实时入口 51漫画网页版官方免费漫画入口
如何快速去除厨房重油污? 2025年最好用的厨房清洁剂推荐
win11怎么更改账户类型 Win11标准用户和管理员权限切换【教程】
冬季去寒冷地区旅游,以下哪种做法有助于缓解冻伤
铁路12306买票怎么选双人铺 铁路12306卧铺分配规则说明
Dash应用多值文本输入处理与类型转换教程
如何测试您的网站全球打开速度-网站海外测速工
荣耀盒子应用管理技巧
edge浏览器怎么修改语言为中文_Edge界面语言切换教程
优酷官网登录入口电脑版 优酷官网网址入口
PHP中实现JSON数据数组分页的教程
SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南
抖音号已注销怎么解绑企业认证?不解绑企业认证会怎样?
《健康大兴》注册方法介绍
如何高效地基于键列值映射DataFrame中的多个列
解决Windows上Composer PATH变量冲突导致的命令无法识别问题
解决Flex容器横向滚动内容截断与偏移问题
cad视图选项卡不见了怎么办_cad视图标签恢复显示方法
苹果自助维修计划支持哪些设备机型
b站网页版入口 哔哩哔哩官方网站直接进入
Python测试中模块导入路径解析的最佳实践
steam缓存文件在哪儿_steam缓存文件的路径查找方法与结构说明
qq邮箱怎么注册_QQ邮箱注册步骤与注意事项
淘口令快速解析技巧
苹果手机如何清理系统缓存数据 iPhone非越狱清理垃圾文件的技巧【系统优化】
《edge浏览器》关闭翻译功能方法
餐馆菜篮选购指南
抖音号升级企业号怎么改名字?升级企业号有哪些好处?
使用AI在VS Code中将代码从一种语言翻译成另一种
《一起考教师》账号注销方法
海棠阅读登录教程_详细讲解海棠登录操作
小米倒班助手添加日历提醒
2019-06-26
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。