Redis 项目常见场景
需求:
用户回复频率控制
- 项目的社区功能里,不可避免的总是会遇到垃圾内容,一觉醒来你会发现首页突然会被某些恶意的帖子和广告刷屏了,如果不采取适当的机制来控制就会导致用户体验受到严重的影响
- 控制广告垃圾贴的策略很多,高级一点的可以通过AI,最简单的方式是通过关键词扫描,还有比较常用的一种方式是频率控制,限制单个用户内容的生产速度,不同等级的用户会有不同的频率控制参数
- 使用Redis来实现频率控制(青铜1小时3贴 白银1小时5贴 黄金1小时8贴)
方案一:
第一步:记录某个IP访问API频率
- 用
IP+当前小时
为key在Redis
中记录某个IP的调用次数,缓存过期时间为1小时
第二步:限制用户调用API
-
我们限制 [3] 的值超过阈值,则在
Redis
中写入[小黑屋+ip]
为key的一个键值对,再设置过期时间( 到某个时间戳EXPIREAT < timestamp> 命令用于将键key 的过期时间设置为timestamp所指定的秒数时间戳
),不到缓存过期时间就不允许API再被这个IP调用。 -
在API再次调用的时候,判断
Redis
中是否存在[小黑屋+ip]
的这个键值对,如果存在,则返回:此ip访问频率受到限制。
伪代码:
public boolean islimited(String ip) {
// 获取小黑屋的ip
String limitip = "小黑屋"+ip;
//判断ip是否关进了小黑屋
if(redis.get1(limitip))
return true;
//用来记录Ip 一小时内访问次数的KEY
long hour = System.currentTimeMillis() / 1000 / (60 * 60);
String ipCountKey = "ipCount"+ip+":"+hour;
// 判断 ipCountKey是否存在
int count = redis.get2(ipCountKey);
count++;
if(count > 3) {//阈值3
redis.set(limitip, 3/*缓存一段时间*/);
return false;
}else {
redis.set(ipCountKey, count);
return true;
}
}
//伪代码
class Redis{
public boolean get1(String limitip) {
return false;
}
public int get2(String limitip) {
return 1;
}
public void set(String str,int c) {}
}
方案二:
- 使用
Redis
中list类型,当用户发帖时,优先查看用户信息(ip|用户户名)
是否存在。 - 如果存在则再判断当前时间与第一次发帖时间的
时间差
,并且时间差
在1小时内,则再判断是否大于会员限制的数量**【例如3】** 大于则发帖成功,否则发帖失败。 - 如果
时间差
不在一个小时内,则清空 list列表中第一个数据,计算第二个位置的数据与当前时间戳的时间差
,如再次不满足条件则继续重复该操作。 - 如果不存在,则记录
用户信息(ip|用户户名)+时间戳
为 key ,类型为 list 的对列中存入第一个数据。
伪代码:
private static void postmsg(String ip, String msg) {
Redis redis = new Redis();
List<String> list = new ArrayList<String>();
// 创建用户信息
String userinfo = "userinfo"+ip;
//判断用户信息是否存在
if(redis.get1(userinfo)) {
//获取第一个数据+时间戳
String msgAndTimestamp = list.get(0);
//获取第一个数据的时间戳
long timestamp = Long.valueOf(msgAndTimestamp.split("::::")[2]);
//获取当前时间戳
long nowtimestamp = System.currentTimeMillis();
//判断两次时间戳是否小于1小时
if(nowtimestamp - timestamp < "一小时") {
list.add(msg+nowtimestamp);
}else {
list.remove(0);
postmsg(ip,msg);
return ;
}
}else {//不存在
list.add(msg);
redis.set(userinfo, list);
}