redis-缓存设计-记录前一个小时和最新的日志

Posted 意犹未尽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis-缓存设计-记录前一个小时和最新的日志相关的知识,希望对你有一定的参考价值。

需求

记录最新的日志 99条

同时记录上一个小时和最近一个小时的 日志出现次数

记录日志代码

 /**
     *
     * @param conn 连接
     * @param name 模块名字
     * @param message 日志信息
     * @param level 日志等级
     * @param timeout 重试时间
     */
    public static void logCommon(
            Jedis conn, String name, String message, String level, int timeout,Date date) {
        //日志出现数量的key
        String commonDest = "common:" + name + ‘:‘ + level;
        //记录当前所处小时数
        String startKey = commonDest + ":start";
        //上一次所属小时数
        String  pstartkey= commonDest + ":pstart";
        //计算重试后时间
        long end = System.currentTimeMillis() + timeout;
        //获得当前所处小时数
        String existing = conn.get(startKey);
        //yyyy-mm-dd  HH:00:00
        String hourStart = ISO_FORMAT.format(date);
        //是否需要重试
        while (System.currentTimeMillis() < end) {
            //对当前所处小时数进行监视 避免其他地方在下一小时切换 比如多线程调用
            conn.watch(startKey);

            Transaction trans = conn.multi();
            //表示第一次运行 进行初始化
            if (existing == null) {
                //保存当前最新小时数
                trans.set(startKey, hourStart);
                existing=hourStart;
            }
            //如果是下一个小时了 将原来的日志的key重新命名
            if (existing != null && COLLATOR.compare(existing, hourStart) < 0) {
                //通过重命名记录当前记录的key 归档到上一个小时
                trans.rename(commonDest, pstartkey);
                //记录最新的小时数
                trans.set(startKey, hourStart);
            }

            //记录日志出现次数 对日志出现数进行+1  这里只是记录日志出现次数
            trans.zincrby("common:" + name + ‘:‘ + level,1,message);
            //存储日志
            String recentDest = "recent:" + name + ‘:‘ + level;
            //消息追加到队列
            trans.lpush(recentDest,  message);
            //只保留0-99条
            trans.ltrim(recentDest, 0, 99);
            List<Object> results = trans.exec();
            // null response indicates that the transaction was aborted due to
            // the watched key changing.
            if (results == null) {
                continue;
            }
            return;
        }
    }

 

返回上一次或者下一次日志

 /**
     * 打印日志信息
     * @param conn 连接
     * @param type top为上一次  current为当前
     */
    public static void printLog(Jedis conn,String name, String level,String type){
        String hourStart=null;
        String commonDest = "common:" + name + ‘:‘ + level;
        if(type=="top"){
            commonDest=commonDest+":pstart";
        }
        Set<Tuple> common = conn.zrevrangeWithScores(commonDest, 0, -1);
        for (Tuple tuple : common) {
            System.out.println("消息:  " + tuple.getElement() + ",出现次数 " + tuple.getScore());
        }
    }

 

测试

 public static final Collator COLLATOR = Collator.getInstance();

    /**
     * 用于比较是否是上一小时了
     */
    public static final SimpleDateFormat TIMESTAMP =
            new SimpleDateFormat("EEE MMM dd HH:00:00 yyyy");
    /**
     * 用于格式化为yyyy-MM-dd hh:00:00
     */
    private static final SimpleDateFormat ISO_FORMAT =
            new SimpleDateFormat("yyyy-MM-dd‘T‘HH:00:00");
    static {
        ISO_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    public static void main(String[] args)
            throws Exception {
        Jedis conn = new Jedis("127.0.0.1", 6379);
        conn.flushDB();
        //录入100条日志信息
        for(int i=0;i<10;i++){
            logCommon(conn,"促销","前一个小时测试嗷嗷"+i,"info",2000,new Date());
        }
        //模拟切换到下一小时i
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(new Date());
        //追加一个小时
        calendar.add(Calendar.HOUR,1);
        for(int i=0;i<3;i++){
            logCommon(conn,"促销","当前一个小时测试嗷嗷"+i,"info",2000,calendar.getTime());
            //测试重复消息
            logCommon(conn,"促销","我是重复数据"+i,"info",2000,calendar.getTime());
            //
            logCommon(conn,"促销","我是重复数据"+i,"info",2000,calendar.getTime());
        }
        //===================获得前一个小时的日志信息====================
        System.out.println("获得前一个小时的日志信息");
        printLog(conn,"促销","info","top");
        //===================获取当前的日志新====================
        System.out.println("获得当前最新的日志信息");
        printLog(conn,"促销","info","current");

    }

打印

得前一个小时的日志信息
消息:  前一个小时测试嗷嗷9,出现次数 1.0
消息:  前一个小时测试嗷嗷8,出现次数 1.0
消息:  前一个小时测试嗷嗷7,出现次数 1.0
消息:  前一个小时测试嗷嗷6,出现次数 1.0
消息:  前一个小时测试嗷嗷5,出现次数 1.0
消息:  前一个小时测试嗷嗷4,出现次数 1.0
消息:  前一个小时测试嗷嗷3,出现次数 1.0
消息:  前一个小时测试嗷嗷2,出现次数 1.0
消息:  前一个小时测试嗷嗷1,出现次数 1.0
消息:  前一个小时测试嗷嗷0,出现次数 1.0
获得当前最新的日志信息
消息:  我是重复数据2,出现次数 2.0
消息:  我是重复数据1,出现次数 2.0
消息:  我是重复数据0,出现次数 2.0
消息:  当前一个小时测试嗷嗷2,出现次数 1.0
消息:  当前一个小时测试嗷嗷1,出现次数 1.0
消息:  当前一个小时测试嗷嗷0,出现次数 1.0

 

以上是关于redis-缓存设计-记录前一个小时和最新的日志的主要内容,如果未能解决你的问题,请参考以下文章

Redis缓存 + 定时写入DB,仿微信点赞模块设计

终于搞清楚了!我花5小时肝出这篇Redis缓存解决方案,带你起飞!

架构设计:系统存储(15)——Redis基本概念和安装使用

Redis我可以讲一个小时

对比Memcached和Redis,谁才是适合你的缓存?

Redis高频面试题之缓存穿透缓存击穿和缓存雪崩