redis热key的发现管理淘汰

redis热key的发现管理淘汰

场景

本地–> nginx —> web服务 ----DB —> dfs —> 网络代理

npm的tgz包请求特点: 高并发、热点包、读多写少

需要发现热点包,缓存到本地,减少web服务和db、dfs的交互,减少网络链路。直接从本地ssd下载文件

热key的发现

1.系统预热,载入业务预估的热key
2.热key自动发现

热key主动发现:基于时间窗口的计数器

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;

import java.util.Set;

/**
*  思路: 基于每个key存储统计,在窗口的时间范围内的key值
*
**/
public class RedisHotKeyWindowCounter {
    
    

    private Jedis jedis;

    public RedisHotKeyWindowCounter(String host, int port) {
    
    
        this.jedis = new Jedis(host, port);
    }

    /**
     * 记录一次关键字key的访问
     *
     * @param key                  关键字
     * @param windowSizeInSeconds  时间窗口大小(秒)
     */
    public void recordAccess(String key, long windowSizeInSeconds) {
    
    
        long timestamp = System.currentTimeMillis() / 1000; // 当前时间戳
        long cutoff = timestamp - windowSizeInSeconds; // 时间窗口的右端点
        String zsetKey = key; // 存储访问记录的ZSET的key
        jedis.zadd(key, timestamp, timestamp); // 将时间戳加入set,做file和分数
        // 移出已经不在时间窗口右端的记录
        jedis.zremrangeByScore(zsetKey, 0, cutoff); 
    }

    /**
     * 获取某个关键字在时间窗口内的访问次数
     *
     * @param key                  关键字
     * @param windowSizeInSeconds  时间窗口大小(秒)
     * @return 访问次数
     */
    public int getWindowCount(String key, long windowSizeInSeconds) {
    
    
        long timestamp = System.currentTimeMillis() / 1000; // 当前时间戳
        long cutoff = timestamp - windowSizeInSeconds; // 时间窗口的右端点
        // 通过分数返回有序集合指定区间内的成员
        Set<Tuple> results = jedis.zrangeByScoreWithScores(key, cutoff, timestamp);
        // 遍历ZSET中的所有成员,并累加score,最后返回累加结果
        int count = 0;
        for (Tuple tuple : results) {
    
    
            if (tuple.getElement().equals(key)) {
    
    
                count ++
            }
        }
        return count;
    }
}

热key处理

基于上面我们发现的热key,来写伪代码处理

public class NpmDowndload {
    
    
    public void download(string url, HttpServletResponse) {
    
    
         long windowSizeInSeconds =  60 * 60 ;
         // 认为是热点包
         int hotDownCount = 100;
         recordAccess(url, windowSizeInSeconds)int count =  getWindowCount(url, windowSizeInSeconds);
        if (count >=  hotDownCount) {
    
    
                // 1. 达到热点
                //  1.1 本地ssd是否缓存
                    // 1.1.1 本地有直接从本地下载
                    // 1.1.2 本地没有,从网络DFS下载,并且缓存到本地
                //2. redis记录已经被认为是热点包, 定时任务,处理,如果不是热点了,清理缓存
        } else {
    
    
            // 没有达到热点要求,走网络DFS下载
        }
    }
}

key的淘汰

redis有提供几种key的淘汰策略如下,根据上面我们的业务场景,使用上面我们手动管理过期 + 根据maxMemorry的淘汰策略

  1.被动删除
    2.主动删除
    3.当使用内存达到maxMemory时根据配置淘汰规则
        3.1 TTL
        3.2 LRU
            3.2.1 只对设置了过期时间的key进行lru算法删除
            3.2.2 对所有key进行lru算法删除
        3.3 LFU
            3.3.1 只对设置了过期时间的key进行LFU算法删除
            3.3.2 对所有key进行lFU算法删除
        3.4 random
            3.4.1 随机删除设置了过期时间的key
            3.4.2 随机删除key
        3.5 noeviction 永不过期,返回异常(默认的淘汰策略)
  


猜你喜欢

转载自blog.csdn.net/u013565163/article/details/130273109