Redis实现广告投放的简单频控

原理是借助redis的incr原子操作实现

代码如下,当先项目中就是如此实现的。可以参考一下。

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;

import javax.annotation.Resource;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;

@Component
public class FrequencyControlCache {

    private static Logger logger = LogManager.getLogger(FrequencyControlCache.class);

    // region 缓存相关的配置
    /**
     * redis缓存中广告频控缓存的过期时间,秒
     */
    @Value("${router.frequency.ad.redis.timeout}")
    private int adFrequencyRedisCacheTime = 30;

    /**
     * redis缓存中 广告-用户维度 频控缓存的过期时间,秒
     */
    @Value("${router.frequency.aduser.redis.timeout}")
    private int adUserFrequencyRedisCacheTime = 1 * 24 * 3600;
    /**
     * 一个用户每天同一个广告最多能看到的次数
     */
    @Value("${router.frequency.aduser.maxadcountperday}")
    private int adUserMaxadCountPerDay = 3;

    // endregion


    @Resource(name = "frequencyJedisCluster")
    private JedisCluster frequencyJedisCluster;



    /**
     * 判断频率是否可以投递。
* 一个用户,相同的广告在一段时间内(如30秒)最多投放一定次数(如1次)
* 一个用户对同一个广告,24小时内只能看最多3次。时间跨度和次数可调整
* @param userid 用户id * @param adid 广告id * @return true表示能投递,false表示不可以投递 */
public boolean frequencyStatus(String userid, String adid){ if(StringUtils.isBlank(userid) || StringUtils.isBlank(adid)){ return false; } // key里面的 _s_ 表示second,是秒级控制的意思 String adFrequencyKey = new StringBuilder(userid).append("_s_").append(adid).toString(); // 1.广告频控是否合格 Long count = frequencyJedisCluster.incr(adFrequencyKey); long c = Optional.ofNullable(count).orElse(-1L); logger.info("userid:{},adid:{},广告投放频率控制,count:{}",userid,adid,c); // 恰好是1,表示没投过 if(c == 1){ // 更新redis Long result = frequencyJedisCluster.expire(adFrequencyKey, adFrequencyRedisCacheTime); logger.info("userid:{},adid:{},广告投放频率控制expire result:{}",userid,adid,result); }else{ // 不为1,表示频控不合格 // adfrequencyFlag = false; return false; } // 2.固定用户,广告投放数量的控制 // key里面的 _d_ 表示day,是天级控制的意思 String adCountKey = new StringBuilder(userid).append("_d_").append(adid).toString(); Long uCount = frequencyJedisCluster.incr(adCountKey); long uc = Optional.ofNullable(uCount).orElse(adUserMaxadCountPerDay + 1L); // 空了的话,不投了,所以默认值取得大一点的 logger.info("userid:{},adid:{},广告-用户投放总量控制,count:{}",userid,adid,uc); if(uc <= adUserMaxadCountPerDay){ // 更新redis if(uc == 1){ // 只有第一次才需要设置过期时间。后面几次不用设置过期时间了 Long result = frequencyJedisCluster.expire(adCountKey, adUserFrequencyRedisCacheTime); logger.info("userid:{},adid:{},广告-用户投放总量控制expire result:{}",userid,adid,result); }else{ logger.info("userid:{},adid:{},广告-用户投放总量控制",userid,adid); } return true; }else{ return false; } } }

你可能感兴趣的:(Java,Redis,广告,频控,incr)