zoukankan      html  css  js  c++  java
  • redis-缓存设计-统计1秒 5秒 1分钟 访问数量

    记录统计

    主要是通过精度算出时间各个时间片的开始时间 作为hash 相同时间片开始时间是一致的 天统计 时间片都是从日期的早8点开始

     /**
         * 毫秒为单位 统计1秒 5秒 1分钟 1小时 5小时 1天的统计信息
         */
       static Integer[] preisions = new Integer[]{1000, 5000, 60000, 300000, 3600000, 18000000, 86400000};
    
        public static void updateCounter(Jedis conn, int productId, int count) {
            Long currentDate = System.currentTimeMillis();
            for (int i = 0; i < preisions.length; i++) {
                Integer index = preisions[i];
                //算出指定时间维度的开始时间片
                Long startDate = (Long) (currentDate / index) * index;
                String hash = "product:" + productId;
                //指定时间片的精度+1
                conn.hincrBy(hash, startDate.toString(), count);
                //将清理的key加入到一个回收的set 存储key和精度
                conn.zadd("recovery", 0, String.format("%s_%s_%s", hash, index, startDate));
            }
        }

    获取统计

    通过精度算出开始时间时间片 然后再hash获取统计信息

     /**
         * 获得指定精度的统计数量
         * @param conn
         * @param productId
         * @param preisions
         * @return
         */
        public static String getCounter(Jedis conn,int productId,Integer preisions){
            Long startDate = (Long) (System.currentTimeMillis() / preisions) * preisions;
            String hash = "product:" + productId;
            return conn.hget(hash,startDate.toString());
        }

    数据清理

    随着时间的增长 hash时间片会越来越多,清理老的时间片

       /**
         * 这里应该使用管道,因为方便打印日志 所以没有使用管道
         * @param conn
         */
        public static void clearCounter(Jedis conn)  {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String recoveryKey = "recovery";
                    int index = 0;
                    while (true) {
                        if (conn.zcard("recovery") <= 0) {
                            try {
                                Thread.sleep(1000);//没有可回收的时候直接等待 休息一会儿
                                continue;
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //每次检查回收50个
                        Set<String> hashs = conn.zrange(recoveryKey, 0, 50);
                        for (String hash :
                                hashs) {
                            String[] hashArray = hash.split("_");
                            int preision = Integer.valueOf(hashArray[1]);//取得精度
                            Long startDate = Long.valueOf(hashArray[2]);
                            String productKey = hashArray[0];//取得数据hash key
                            //开始时间加上精度 如果小于当前时间 表示时间片过了 执行删除
                            final Calendar calendar = Calendar.getInstance();
                            calendar.setTime(new Date(startDate));
                            calendar.add(Calendar.MILLISECOND, preision);
                            //在时间片之内
                            if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
                                continue;
                            } else {
                                //执行删除
                                Long result = conn.hdel(productKey, startDate.toString());
                                conn.zrem(recoveryKey,hash);
                                System.out.println(String.format("移除了key:%s,过期数据%s,删除结果:%s", productKey, startDate.toString(), result));
                            }
                        }
                    }
                }
            }).start();
        }

    main方法

      public static void main(String[] args)
                throws Exception {
            Jedis conn = new Jedis("127.0.0.1", 6379);
            Jedis conn2 = new Jedis("127.0.0.1", 6379);
            Jedis conn3 = new Jedis("127.0.0.1", 6379);
            conn.flushDB();
            //启动清理器
            clearCounter(conn2);
            for(int i=0;i<65;i++){
                Thread.sleep(1000);
                updateCounter(conn,1,1);
            }
            //获得 1分钟的统计数量
           System.out.println("一分钟的统计数量:"+getCounter(conn3,1,60000));
    
        }

    打印

  • 相关阅读:
    静态库,动态库
    vim
    消息队列-Rabbitmq处理消息及在Spring中的应用
    消息队列 -- 队列(Queue)和主题(Topic)
    Sing的签名算法
    Jquery
    VUE
    node
    vue 加载静态图片
    vue :style 动态绑定style
  • 原文地址:https://www.cnblogs.com/LQBlog/p/13365191.html
Copyright © 2011-2022 走看看