日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
打點統(tǒng)計——3(go日志讀取分析寫入)

uid是服務端給客戶端種下的cookie。比如訪問百度,同一臺電腦同一個瀏覽器,不管是百度哪個頁面,都是這個uid:
打點統(tǒng)計——3(go日志讀取分析寫入)

創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比河源網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式河源網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋河源地區(qū)。費用合理售后完善,十余年實體公司更值得信賴。


區(qū)分PV、IV、UV如下:
1、pv訪問量(Page View),即頁面訪問量,每打開一次頁面PV計數(shù)+1,刷新頁面也是。

2、UV訪問數(shù)(Unique Visitor)指獨立訪客訪問數(shù),一臺電腦終端為一個訪客。

3、IV是初始向量(IV,Initialization Vector)。


redis數(shù)據(jù)結構HyperLogLog
如果我們要實現(xiàn)記錄網(wǎng)站每天訪問的獨立IP數(shù)量這樣的一個功能

集合實現(xiàn):

使用集合來儲存每個訪客的 IP ,通過集合性質(集合中的每個元素都各不相同)來得到多個獨立 IP ,
然后通過調用 SCARD 命令來得出獨立 IP 的數(shù)量。
舉個例子,程序可以使用以下代碼來記錄 2014 年 8 月 15 日,每個網(wǎng)站訪客的 IP :
ip = get_vistor_ip()
SADD '2014.8.15::unique::ip' ip
然后使用以下代碼來獲得當天的唯一 IP 數(shù)量:
SCARD '2014.8.15::unique::ip'

集合實現(xiàn)的問題

使用字符串來儲存每個 IPv4 地址最多需要耗費 15 字節(jié)(格式為 'XXX.XXX.XXX.XXX' ,比如
'202.189.128.186')。
下表給出了使用集合記錄不同數(shù)量的獨立 IP 時,需要耗費的內(nèi)存數(shù)量:
獨立 IP 數(shù)量一天一個月一年
一百萬15 MB 450 MB 5.4 GB
一千萬150 MB 4.5 GB 54 GB
一億1.5 GB 45 GB 540 GB
隨著集合記錄的 IP 越來越多,消耗的內(nèi)存也會越來越多。
另外如果要儲存 IPv6 地址的話,需要的內(nèi)存還會更多一些

為了更好地解決像獨立 IP 地址計算這種問題,
Redis 在 2.8.9 版本添加了 HyperLogLog 結構。

HyperLogLog介紹

HyperLogLog 可以接受多個元素作為輸入,并給出輸入元素的基數(shù)估算值:
? 基數(shù):集合中不同元素的數(shù)量。比如 {'apple', 'banana', 'cherry', 'banana', 'apple'} 的基數(shù)就是 3 。
? 估算值:算法給出的基數(shù)并不是精確的,可能會比實際稍微多一些或者稍微少一些,但會控制在合
理的范圍之內(nèi)。
HyperLogLog 的優(yōu)點是,即使輸入元素的數(shù)量或者體積非常非常大,計算基數(shù)所需的空間總是固定
的、并且是很小的。
在 Redis 里面,每個 HyperLogLog 鍵只需要花費 12 KB 內(nèi)存,就可以計算接近 2^64 個不同元素的基
數(shù)。這和計算基數(shù)時,元素越多耗費內(nèi)存就越多的集合形成鮮明對比。
但是,因為 HyperLogLog 只會根據(jù)輸入元素來計算基數(shù),而不會儲存輸入元素本身,所以
HyperLogLog 不能像集合那樣,返回輸入的各個元素。

將元素添加至 HyperLogLog
PFADD key element [element ...]
將任意數(shù)量的元素添加到指定的 HyperLogLog 里面。
這個命令可能會對 HyperLogLog 進行修改,以便反映新的基數(shù)估算值,如果 HyperLogLog 的基數(shù)估算
值在命令執(zhí)行之后出現(xiàn)了變化, 那么命令返回 1 , 否則返回 0 。
命令的復雜度為 O(N) ,N 為被添加元素的數(shù)量。

返回給定 HyperLogLog 的基數(shù)估算值
PFCOUNT key [key ...]
當只給定一個 HyperLogLog 時,命令返回給定 HyperLogLog 的基數(shù)估算值。
當給定多個 HyperLogLog 時,命令會先對給定的 HyperLogLog 進行并集計算,得出一個合并后的
HyperLogLog ,然后返回這個合并 HyperLogLog 的基數(shù)估算值作為命令的結果(合并得出的
HyperLogLog 不會被儲存,使用之后就會被刪掉)。
當命令作用于單個 HyperLogLog 時, 復雜度為 O(1) , 并且具有非常低的平均常數(shù)時間。
當命令作用于多個 HyperLogLog 時, 復雜度為 O(N) ,并且常數(shù)時間也比處理單個 HyperLogLog 時要
大得多。

PFADD 和 PFCOUNT 的使用示例
redis> PFADD unique::ip::counter '192.168.0.1'
(integer) 1
redis> PFADD unique::ip::counter '127.0.0.1'
(integer) 1
redis> PFADD unique::ip::counter '255.255.255.255'
(integer) 1
redis> PFCOUNT unique::ip::counter
(integer) 3

合并多個 HyperLogLog
PFMERGE destkey sourcekey [sourcekey ...]
將多個 HyperLogLog 合并為一個 HyperLogLog ,合并后的 HyperLogLog 的基數(shù)估算值是通過對所有
給定 HyperLogLog 進行并集計算得出的。
命令的復雜度為 O(N) , 其中 N 為被合并的 HyperLogLog 數(shù)量, 不過這個命令的常數(shù)復雜度比較高。

PFMERGE 的使用示例
redis> PFADD str1 "apple" "banana" "cherry"
(integer) 1
redis> PFCOUNT str1
(integer) 3
redis> PFADD str2 "apple" "cherry" "durian" "mongo"
(integer) 1
redis> PFCOUNT str2
(integer) 4
redis> PFMERGE str1&2 str1 str2
OK
redis> PFCOUNT str1&2
(integer) 5

HyperLogLog 實現(xiàn)獨立 IP 計算功能

獨立 IP 數(shù)量一天一個月一年一年(使用集合)
一百萬12 KB 360 KB 4.32 MB 5.4 GB
一千萬12 KB 360 KB 4.32 MB 54 GB
一億12 KB 360 KB 4.32 MB 540 GB
下表列出了使用 HyperLogLog 記錄不同數(shù)量的獨立 IP 時,需要耗費的內(nèi)存數(shù)量:
可以看到,要統(tǒng)計相同數(shù)量的獨立 IP ,HyperLogLog 所需的內(nèi)存要比集合少得多。


打點統(tǒng)計——3(go日志讀取分析寫入)


package main

import (
    "flag"
    "github.com/sirupsen/logrus"
    "time"
    "os"
    "bufio"
    "io"
    "strings"
    "github.com/mgutz/str"
    "net/url"
    "crypto/md5"
    "encoding/hex"
    "github.com/mediocregopher/radix.v2/pool"
    "strconv"
)

const HANDLE_DIG = " /dig?"
const HANDLE_MOVIE = "/movie/"
const HANDLE_LIST = "/list/"
const HANDLE_HTML = ".html"

type cmdParams struct {
    logFilePath string
    routineNum int
}
type digData struct{
    time   string
    url    string
    refer  string
    ua        string
}
type urlData struct {
    data   digData
    uid    string
    unode  urlNode
}
type urlNode struct {
    unType     string // 詳情頁 或者 列表頁 或者 首頁
    unRid  int       // Resource ID 資源ID
    unUrl  string // 當前這個頁面的url
    unTime  string // 當前訪問這個頁面的時間
}
type storageBlock struct {
    counterType       string
    storageModel   string
    unode        urlNode
}

var log = logrus.New()

func init() {
    log.Out = os.Stdout //聲明用什么輸出日志
    log.SetLevel( logrus.DebugLevel ) //設置日志的等級
}

func main() {
    // 獲取參數(shù)
    logFilePath := flag.String( "logFilePath", "F:/phpStudy/PHPTutorial/nginx/logs/access.log", "log file path" ) //日志文件路徑
    routineNum := flag.Int( "routineNum", 5, "consumer numble by goroutine" ) //routine數(shù)量,默認為5
    l := flag.String( "l", "./log.log", "this programe runtime log target file path" ) //go生成的日志存放路徑
    flag.Parse()

    params := cmdParams{ *logFilePath, *routineNum }

    // 打日志
    logFd, err := os.OpenFile( *l, os.O_CREATE|os.O_WRONLY, 0644 ) //打開go生成的日志
    if err == nil {
        log.Out = logFd //打開出錯,則用日志文件存錯誤信息
        defer logFd.Close() //關閉文件
    }
    log.Infof( "Exec start." ) //提示日志文件啟動
    log.Infof( "Params: logFilePath=%s, routineNum=%d", params.logFilePath, params.routineNum ) //提示輸入的/默認參數(shù)

    // 初始化一些channel,用于數(shù)據(jù)傳遞
    var logChannel = make(chan string, 3*params.routineNum) //讀取日志文件量更大,設置為3倍
    var pvChannel = make(chan urlData, params.routineNum)
    var uvChannel = make(chan urlData, params.routineNum)
    var storageChannel = make(chan storageBlock, params.routineNum)

    // Redis Pool
    redisPool, err := pool.New( "tcp", "localhost:6379", 2*params.routineNum ); //連接池,2*params.routineNum是連接池數(shù)
    if err != nil{
        log.Fatalln( "Redis pool created failed." )
        panic(err)
    } else {
        //空閑時間過了后,客戶端(也就是連接池和遠端服務器會斷開)。所以以一定的間隔去ping
        go func(){
            for{
                redisPool.Cmd( "PING" )
                time.Sleep( 3*time.Second )
            }
        }()
    }

    // 日志消費者
    go readFileLinebyLine( params, logChannel )

    // 創(chuàng)建一組日志處理
    for i:=0; i列表頁≥首頁
    pos1 := str.IndexOf( url, HANDLE_MOVIE, 0)
    if pos1!=-1 {
        pos1 += len( HANDLE_MOVIE )
        pos2 := str.IndexOf( url, HANDLE_HTML, 0 )
        idStr := str.Substr( url , pos1, pos2-pos1 )
        id, _ := strconv.Atoi( idStr )
        return urlNode{ "movie", id, url, t }
    } else {
        pos1 = str.IndexOf( url, HANDLE_LIST, 0 )
        if pos1!=-1 {
            pos1 += len( HANDLE_LIST )
            pos2 := str.IndexOf( url, HANDLE_HTML, 0 )
            idStr := str.Substr( url , pos1, pos2-pos1 )
            id, _ := strconv.Atoi( idStr )
            return urlNode{ "list", id, url, t }
        } else {
            return urlNode{ "home", 1, url, t}
        } // 如果頁面url有很多種,就不斷在這里擴展
    }
}

//去重需要在一定的時間內(nèi)
func getTime( logTime, timeType string ) string {
    var item string
    switch timeType {
    case "day":
        item = "2006-01-02"
        break
    case "hour":
        item = "2006-01-02 15"
        break
    case "min":
        item = "2006-01-02 15:04"
        break
    }
    t, _ := time.Parse( item, time.Now().Format(item) )
    return strconv.FormatInt( t.Unix(), 10 ) //將unix時間戳轉換為10位字符串
}

分享題目:打點統(tǒng)計——3(go日志讀取分析寫入)
本文網(wǎng)址:http://www.dlmjj.cn/article/ihssgg.html