亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

redis應用場景(2)日志記錄及指標統計

發布時間:2020-07-25 22:27:52 來源:網絡 閱讀:11180 作者:randy_shandong 欄目:開發技術

使用redis存儲業務信息,同時也可以存儲系統運維信息,比如日志和計數器來收集系統當前的狀態信息,挖掘正在使用系統的顧客信息,以及診斷系統問題,發現潛在的問題。當然,系統日志信息及統計信息也可以存儲在關系型數據庫中,但是存在一個很大的弊端,影響業務性能。


1.使用redis記錄日志

熟悉java的朋友,記錄日志往往采用的是log4j,sl4j,大多記錄載體選擇文本文件。如果使用web集群的話,造成日志分散在各個web服務器,搜集有效日志信息,非常麻煩。如果選擇數據庫保存的話,解決了文件分散情況,但勢必對業務造成影響,日志畢竟是個輔助支撐而已,不應該和業務系統相提并論。這時候,redis是一個不錯的選擇。如果可以的話,可以對log4j擴展,將數據保存到redis中,當然這不是本章的重點。本章重點,主要簡單討論下如何保存日志。

構建一個系統,判斷哪些信息需要被記錄是一件困難的事情,不同的業務有不同的需求。但一般的日志信息往往關注一下方面。

日志時間,日志內容,服務IP,日志級別,日志發生頻率。

1.1redis日志存儲設計

redis應用場景(2)日志記錄及指標統計

記錄詳情里,可以按要求,增添想要的信息,發生的類名稱,處理IP等。

1.2代碼

public void logCommon(
        Jedis conn, String name, String message, String severity, int timeout) {
    String commonDest = "common:" + name + ':' + severity;
    String startKey = commonDest + ":start";
    long end = System.currentTimeMillis() + timeout;
    while (System.currentTimeMillis() < end){
        conn.watch(startKey);
        //當前所處的小時數
        String hourStart = ISO_FORMAT.format(new Date());
        String existing = conn.get(startKey);

        Transaction trans = conn.multi();
        //如果記錄的是上一個小時的日志
        if (existing != null && COLLATOR.compare(existing, hourStart) < 0){
            trans.rename(commonDest, commonDest + ":last");
            trans.rename(startKey, commonDest + ":pstart");
            trans.set(startKey, hourStart);
        }else{
            trans.set(startKey, hourStart);
        }
         //日志計數器增1
        trans.zincrby(commonDest, 1, message);
        //記錄最近日志詳情
        String recentDest = "recent:" + name + ':' + severity;
        trans.lpush(recentDest, TIMESTAMP.format(new Date()) + ' ' + message);
        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;
    }
}

2.網站點擊量計數器統計

2.1redis計數器存儲設計

redis應用場景(2)日志記錄及指標統計

2.2編碼

//以秒為單位的精度
public static final int[] PRECISION = new int[]{1, 5, 60, 300, 3600, 18000, 86400};
public void updateCounter(Jedis conn, String name, int count, long now){
    Transaction trans = conn.multi();
    //每一次更新,都要更新所有精度的計數器
    for (int prec : PRECISION) {
        long pnow = (now / prec) * prec;//當前時間片的開始時間
        String hash = String.valueOf(prec) + ':' + name;
        trans.zadd("known:", 0, hash);
        trans.hincrBy("count:" + hash, String.valueOf(pnow), count);
    }
    trans.exec();
}

public List<Pair<Integer,Integer>> getCounter(
    Jedis conn, String name, int precision)
{
    String hash = String.valueOf(precision) + ':' + name;
    Map<String,String> data = conn.hgetAll("count:" + hash);
    ArrayList<Pair<Integer,Integer>> results =
        new ArrayList<Pair<Integer,Integer>>();
    for (Map.Entry<String,String> entry : data.entrySet()) {
        results.add(new Pair<Integer,Integer>(
                    Integer.parseInt(entry.getKey()),
                    Integer.parseInt(entry.getValue())));
    }
    Collections.sort(results);
    return results;
}


2.3清楚舊數據


流程圖

redis應用場景(2)日志記錄及指標統計

代碼

public class CleanCountersThread
    extends Thread
{
    private Jedis conn;
    private int sampleCount = 100;
    private boolean quit;
    private long timeOffset; // used to mimic a time in the future.

    public CleanCountersThread(int sampleCount, long timeOffset){
        this.conn = new Jedis("192.168.163.156");
        this.conn.select(15);
        this.sampleCount = sampleCount;
        this.timeOffset = timeOffset;
    }

    public void quit(){
        quit = true;
    }

    public void run(){
        int passes = 0;
        while (!quit){
            long start = System.currentTimeMillis() + timeOffset;
            int index = 0;
            while (index < conn.zcard("known:")){
                Set<String> hashSet = conn.zrange("known:", index, index);
                index++;
                if (hashSet.size() == 0) {
                    break;
                }
                String hash = hashSet.iterator().next();
                int prec = Integer.parseInt(hash.substring(0, hash.indexOf(':')));
                int bprec = (int)Math.floor(prec / 60);
                if (bprec == 0){
                    bprec = 1;
                }
                if ((passes % bprec) != 0){
                    continue;
                }

                String hkey = "count:" + hash;
                String cutoff = String.valueOf(
                    ((System.currentTimeMillis() + timeOffset) / 1000) - sampleCount * prec);
                ArrayList<String> samples = new ArrayList<String>(conn.hkeys(hkey));
                Collections.sort(samples);
                int remove = bisectRight(samples, cutoff);

                if (remove != 0){
                    conn.hdel(hkey, samples.subList(0, remove).toArray(new String[0]));
                    if (remove == samples.size()){
                        conn.watch(hkey);
                        if (conn.hlen(hkey) == 0) {
                            Transaction trans = conn.multi();
                            trans.zrem("known:", hash);
                            trans.exec();
                            index--;
                        }else{
                            conn.unwatch();
                        }
                    }
                }
            }

            passes++;
            long duration = Math.min(
                (System.currentTimeMillis() + timeOffset) - start + 1000, 60000);
            try {
                sleep(Math.max(60000 - duration, 1000));
            }catch(InterruptedException ie){
                Thread.currentThread().interrupt();
            }
        }
    }

    // mimic python's bisect.bisect_right
    public int bisectRight(List<String> values, String key) {
        int index = Collections.binarySearch(values, key);
        return index < 0 ? Math.abs(index) - 1 : index + 1;
    }
}

3.使用redis統計數據

上面提到的計數器,是最簡單的統計數據。除了計數器(count(*)),還是最大值(max),最小值(min).

設計

redis應用場景(2)日志記錄及指標統計

stats:模塊(頁面)名稱:指標名稱

public List<Object> updateStats(Jedis conn, String context, String type, double value){
    int timeout = 5000;
    String destination = "stats:" + context + ':' + type;
    String startKey = destination + ":start";
    long end = System.currentTimeMillis() + timeout;
    while (System.currentTimeMillis() < end){
        conn.watch(startKey);
        String hourStart = ISO_FORMAT.format(new Date());

        String existing = conn.get(startKey);
        Transaction trans = conn.multi();
        if (existing != null && COLLATOR.compare(existing, hourStart) < 0){
            trans.rename(destination, destination + ":last");
            trans.rename(startKey, destination + ":pstart");
            trans.set(startKey, hourStart);
        }
        //借助redis提供的最大值,最小值計算        
        String tkey1 = UUID.randomUUID().toString();
        String tkey2 = UUID.randomUUID().toString();
        trans.zadd(tkey1, value, "min");
        trans.zadd(tkey2, value, "max");

        trans.zunionstore(
            destination,
            new ZParams().aggregate(ZParams.Aggregate.MIN),
            destination, tkey1);
        trans.zunionstore(
            destination,
            new ZParams().aggregate(ZParams.Aggregate.MAX),
            destination, tkey2);

        trans.del(tkey1, tkey2);
        trans.zincrby(destination, 1, "count");
        trans.zincrby(destination, value, "sum");
        trans.zincrby(destination, value * value, "sumsq");

        List<Object> results = trans.exec();
        if (results == null){
            continue;
        }
        return results.subList(results.size() - 3, results.size());
    }
    return null;
}

需要注意的使用redis自帶的最大值最小值,計算,所以創建了2個臨時有序集合。其他的邏輯參照日志相關部分。


參考內容

《redis in action》


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安庆市| 永嘉县| 固原市| 远安县| 阳曲县| 随州市| 政和县| 财经| 板桥市| 靖西县| 尚志市| 合水县| 红河县| 兴安盟| 米林县| 新绛县| 华安县| 万山特区| 东源县| 新余市| 彭山县| 河北区| 抚宁县| 西乌珠穆沁旗| 布拖县| 德令哈市| 天峻县| 宜君县| 桦南县| 朝阳县| 西乌| 武陟县| 祁东县| 永州市| 宁阳县| 陵川县| 宁晋县| 墨竹工卡县| 甘洛县| 如皋市| 长白|