基于redis消费队列的一个使用(二)

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

上篇文章介绍了基于redis消费队列的一个使用,但是当时用的的一些原子操作类都是基于单一系统的,如果服务器是集群部署的就不能用了,因为每个系统是独立的需要借助第三方的共享系统例如缓存系统、数据库,这里借助redis再一点一点的完善。

redis中对原子操作类AtomicInteger替代

  • 操作的对象注意是数字类型的
  • incr递增1并返回递增后的结果;
  • incrby根据指定值做递增或递减操作并返回递增或递减后的结果(incrby递增或递减取决于传入值的正负);
  • decr递减1并返回递减后的结果;
  • decrby根据指定值做递增或递减操作并返回递增或递减后的结果(decrby递增或递减取决于传入值的正负);

消费线程参数由系统的原子类改为redis的key

注意一点这里的redis客户端为新启的一个,因为限流那里用了事务,可能会导致这里崩掉,后续有时间了再在这里补充吧

        /**
	 * 消费测试
	 * @param key   队列名称
	 * @param count 消费多少笔数据
	 * @param isEnd 活动是否结束
	 */
	public void consumeTestRedis(String key,String count,String isEnd) 
复制代码

效果图

image.png

对于消费还缺失防止刷单

请求频率的问题

一个用户5s内只准访问提交一次

  • 法1 对于用户ID和消费物品设置个key过期时间为5s,key存在则说明以进行了消费,不存在放行
  • 法2 利用有序集合和事务进行控制,下面是jedis的实现例子,也可以参考之前写的:限流和单元测试的例子
/**
	 * @param key 限流
	 * @param maxAllow 最大允许
	 * @param time 间隔时间毫秒
	 * @return
	 */
	public boolean isRateAllow(Jedis jedis,String key,int maxAllow,long time) {
		Transaction transaction=jedis.multi();
		long currentTime=System.currentTimeMillis();
                //添加请求
		transaction.zadd(key,currentTime,currentTime+":"+Thread.currentThread().getName());
                //移除到这段时间差的请求   
		transaction.zremrangeByScore(key, 0,currentTime-time);
                //统计当前的请求数量
		transaction.zcard(key);
	        List<Object> result=transaction.exec();
	        Long size=(Long)result.get(2);
	        System.out.println(result+"   "+Thread.currentThread().getName()+":"+size);
		return size<=maxAllow;
	}
复制代码

限流后效果

image.png

注意!这里有个问题就是事务控制可能客户端不是串行的时候会报错,需要单独实例化个客户端

  • 法3使用组件 Redis-Cell

消费个数的问题

  • 可以为这个用户维护个计数器,key 物品id+用户id

效果大概如下 image.png

猜你喜欢

转载自juejin.im/post/7087005262434795557