redis在java中的应用

本文介绍了Redis中的zset数据类型及其在Java应用中的使用,包括添加、查询、删除、排序和分数操作。通过示例展示了如何利用zset实现访问限制功能,如设置拦截器来限制用户在特定时间内的请求次数。
摘要由CSDN通过智能技术生成

redis做客户端访问限流

Redis中zset数据类型介绍

这里主要使用了redis的set数据类型,即:有序集合
语法规则:
zadd key score member [score member…]
zrange test:1 0 -1 withscores //查看点赞(分数)与成员名
zscore test:2 james //查看james的点赞数(分数)

zrank user:3 james //返回名次:第3名返回2,从0开始到2,共3名
zrevrank user:3 james //返回0, 反排序,点赞数越高,排名越前
zrem user:3 jame mike 删除成员
zincrby user:3 10 lee //成员lee的分数加10

leemikejames
100120200

zremrangebyscore user:5 100 300 //删除分数在100与300范围的成员
zremrangebyscore user:5 (100 +inf //删除分数大于100(不包括100)

有序集合交集:
格式:zinterstore destination numkeys key … [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
destination:交集产生新的元素存储键名称
numkeys: 要做交集计算的键个数
key :元素键值
weights:每个被选中的键对应值乘weight, 默认为1

解决方法

对用户所发出的请求进行计算,得出结果。在设定的访问次数内是符合规则的,否则视为违规操作(提示用户当前访问过快或流量已达到最大限度)。
具体可以定义拦截器拦截用户请求加以处理,在设定时间内,请求数量不大于限制请求数。定义两个zset集合,用于存储用户访问当前时间和计数量。

1,配置一个拦截器:
public class LimitRaterInterceptor extends HandlerInterceptorAdapter {

/**
 * 预处理回调方法,实现处理器的预处理(如登录检查) 第三个参数为响应的处理器,即controller 返回true,表示继续流程,调用下一个拦截器或者处理器
 * 返回false,表示流程中断,通过response产生响应
 */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	// IP限流 在线Demo所需 一秒限10个请求
	String token1 = redisRaterLimiter.acquireTokenFromBucket("XMALL" + IPInfoUtil.getIpAddr(request), 10, 1000);
	if (StrUtil.isBlank(token1)) {
		throw new MallException("你手速怎么这么快,请点慢一点");
	}
	return true;
}

}

public class RedisRaterLimiter {

private final static Logger log= LoggerFactory.getLogger(RedisRaterLimiter.class);

@Autowired
private JedisPool jedisPool;

private static final String BUCKET = "BUCKET_";
private static final String BUCKET_COUNT = "BUCKET_COUNT";
private static final String BUCKET_MONITOR = "BUCKET_MONITOR_";

public String acquireTokenFromBucket(String point, int limit, long timeout) {

    Jedis jedis = jedisPool.getResource();
    try{
        //UUID令牌
        String token = UUID.randomUUID().toString();
        long now = System.currentTimeMillis();
        //开启事务
        Transaction transaction = jedis.multi();

        //删除信号量 移除有序集中指定区间(score)内的所有成员 ZREMRANGEBYSCORE key min max
        transaction.zremrangeByScore((BUCKET_MONITOR + point).getBytes(), "-inf".getBytes(), String.valueOf(now - timeout).getBytes());
        //为每个有序集分别指定一个乘法因子(默认设置为 1) 每个成员的score值在传递给聚合函数之前都要先乘以该因子
        ZParams params = new ZParams();
        params.weightsByDouble(1.0, 0.0);
        //计算给定的一个或多个有序集的交集
        transaction.zinterstore(BUCKET + point, params, BUCKET + point, BUCKET_MONITOR + point);

        //计数器自增
        transaction.incr(BUCKET_COUNT);
        List<Object> results = transaction.exec();
        long counter = (Long) results.get(results.size() - 1);

        transaction = jedis.multi();
        //Zadd 将一个或多个成员元素及其分数值(score)加入到有序集当中
        transaction.zadd(BUCKET_MONITOR + point, now, token);
        transaction.zadd(BUCKET + point, counter, token);
        transaction.zrank(BUCKET + point, token);
        results = transaction.exec();
        //获取排名,判断请求是否取得了信号量
        long rank = (Long) results.get(results.size() - 1);
        if (rank < limit) {
            return token;
        } else {
            //没有获取到信号量,清理之前放入redis中垃圾数据
            transaction = jedis.multi();
            //Zrem移除有序集中的一个或多个成员
            transaction.zrem(BUCKET_MONITOR + point, token);
            transaction.zrem(BUCKET + point, token);
            transaction.exec();
        }
    }catch (Exception e){
        log.error("限流出错"+e.toString());
    }finally {
        if(jedis!=null){
            jedis.close();
        }
    }
    return null;
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值