• redis-缓存设计-自动延迟调度,最热商品缓存(二)


    需求

    1.实现任意数据行的可以设计不同的延迟周期进行刷新或者同步任务

    2.最热的2000个商品缓存

    自动延迟调度

    加入调度列表

    /**
         * 将需要主动更新的的数据加入自动调度列表
         * @param conn
         * @param row_id
         * @param delay
         */
        public static void  scheduleRowCache(Jedis conn,String row_id,int delay){
               //记录此id周期多少秒执行一次 刷新
               conn.zadd("delay:",delay,row_id);
               //加入定时执行列表 并设置立即执行
               conn.zadd("schedule:",System.currentTimeMillis(),row_id);
        }

    调度方法

        public static  void  run(Jedis conn){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        //获取需要立即执行的列表
                        Set<String> ids = conn.zrangeByScore("schedule:", 0, System.currentTimeMillis());
                        //没有则释放时间片 同时暂停500毫秒
                        if (ids == null || ids.size() <= 0) {
                            Thread.yield();
                            try {
                                Thread.sleep(500L);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        for (String id :
                                ids) {
    
                            System.out.println(id + "执行了数据刷新");
                            //获得此数据延迟时间
                            Double delay = conn.zscore("delay:", id);
                            //重新加入延迟队列
                            //加入定时执行列表 并设置立即执行
                            conn.zadd("schedule:", System.currentTimeMillis() + (delay * 1000), id);
                        }
                    }
                }
            }).start();;
        }

    测试

      public static final void main(String[] args)
                throws Exception {
            Jedis conn = new Jedis("127.0.0.1", 6379);
            conn.select(15);
            //5秒刷新一次
            scheduleRowCache(conn,"1",5);
            run(conn);
            Thread.sleep(1000000);
        }

    最热商品缓存

    访问商品

    /**
         * 更新rank
         * @param conn
         * @param productId
         * @return
         * @throws InterruptedException
         */
        public static String viewProduct(Jedis conn,String productId) throws InterruptedException {
            //更新评分
            conn.zincrby("viewed:",-1,productId);
            //获得排名
            double rank= conn.zrank("viewed:",productId);
            String html=null;
            //如果<=2000表示走缓存
            if(rank<=2000){
                //先查缓存
                html=  conn.get("product:"+productId);
                if(html==null){
                    html=select(productId);
                    conn.set("product:"+productId,html);
                }
            }else{
                html =select(productId);
            }
            return html;
        }
      /**
         * 模拟db 和生成html
         * @return
         * @throws InterruptedException
         */
        public static String select(String productId) throws InterruptedException {
            Thread.sleep(2000);
            return String.format("<html>我是商品%s的商品详情html</html>",productId);
        }

    定时任务清除非热点数据

     /**
         * 此方法应该定时任务5秒调用一次
         * @param conn
         */
        public static void clearCache(Jedis conn){
                    conn.zremrangeByRank("viewed:",0,-2001);
            //将所有商品的浏览数量降低一半 未测试通过,,,不造咋减半的 书上py是这样写
            conn.zinterstore("viewed:","{'viewed:':0.5");
        }

    2020-08-21:已解决 通过 WEIGHTS 设置乘法因子 默认是1  我们设置0.5 就会在原有的基础上* 0.5

    参考:http://doc.redisfans.com/sorted_set/zunionstore.html#zunionstore

    测试

     public static   void main(String[] args)
                throws Exception {
            Jedis conn = new Jedis("127.0.0.1", 6379);
            conn.select(15);
            viewProduct(conn,"3");
            viewProduct(conn,"3");
            viewProduct(conn,"3");
            viewProduct(conn,"3");
            viewProduct(conn,"3");
            viewProduct(conn,"3");
            //清空2000排名以外的 同时重置2000以内的排名 conn.zscore("viewed:","3")
            clearCache(conn);
            Thread.sleep(1000000);
        }

    实际使用例子

    比如我们线上几千家门店,用户进入门店首页,为了追求性能会在redis增加缓存,但是每个门店都按照传统的 设置缓存加失效时间那么redis内存消耗会很大。

    实际中有些偏远的门店,用户数会很少,所以统计最热门店,使用定时任务每10分钟剔除缓存 然后将最热门店的程序主动刷新。而不那么热门的门店则不使用缓存

  • 相关阅读:
    storm中的Scheduler
    开启flume的远程调试功能
    修改flume源码,使其HTTPSource具备访问路径功能
    非功能测试——效率测试
    python100例
    awk命令
    shell正则表达式
    python的垃圾回收机制
    冯-诺伊曼体系结构
    jmeter读取文件内容做变量
  • 原文地址:https://www.cnblogs.com/LQBlog/p/13276192.html
Copyright © 2020-2023  润新知