今天,我和大家分享下redis在運維數據分析中的去重統計方式。 為了避免混淆,本文中對於redis的數據結構做如下約定: SET:saddkey member ZSET:zaddkeyscoremember HYPERLOGLOG:pfaddkeyelement STRING:setbitkeyof ...
今天,我和大家分享下redis在運維數據分析中的去重統計方式。
為了避免混淆,本文中對於redis的數據結構做如下約定:
SET:saddkey member
ZSET:zaddkeyscoremember
HYPERLOGLOG:pfaddkeyelement
STRING:setbitkeyoffset value
名詞約定:
維度:比如版本、操作系統類型、操作系統版本、運營商、設備型號、網路類型等
複合維度:由兩個或多個維度交錯產生的維度,比如某個版本下的某個設備型號。
去重統計在數據化運維的指標計算環節,並不是一個陌生的字眼,甚至可以說,在大部分的數據指標的中間計算過程中,最終會分為以下幾種數據集:
最大,最小,穩定性,疊加,去重統計。
這5種指標前面4種在實時處理框架或者大部分nosql中使用相對較小的開銷即可完成計算,基礎指標計算的大部分計算瓶頸還是落在io上面,而導致io瓶頸的問題源自於數據維度的劃分與聚合,特別是對於去重統計類型的數據,如果有一種需要實時顯示的去重指標,維度的切分對於io上的開銷簡直是一種災難。
例如,假定我們需要獲取手機終端中某個應用版本中的某個設備型號或者某個系統的活躍設備數。那麼,目前市場中的設備型號有幾百種,各種系統版本x系統類型也有很多,對指標的去重統計來說每多一個維度,需要的記憶體開銷就要多上一倍,2個維度交叉產生的複合維度可能多達上百個,3個維度的交叉產生的複合維度可能數以千計。
因此,對於實時顯示的去重統計類型指標,最好的處理方式是在設計時儘量規避這種指標。如果實在無法規避,我們需要做的犧牲一部分插入時的性能或者空間上的性能換來該部分指標在讀取時不是o(n)的。
下麵簡單介紹幾種在開發中基於redis研究出來的幾種數據去重方式。
1.於set的去重統計
這種結構的數據應該是最好理解的統計方式,也是常規的統計方式之一,直接把要去重的部分作為member插入一個set中,需要統計的時候直接使用scard統計該數據集的基數,對於時間等維度信息,可以放在key中,然後拿取的時候通過拼接維度欄位的形式拿取。
優點:使用簡單,統計精確。
缺點:無法達成實時統計的功能,要一分鐘統計一次的話需要使用expire命令設置一個很短的回收時間,單一維度時占用空間過大,信息聚合成本過大,有幾個維度就需要幾倍的記憶體空間,3個以上複合維度時基本不需要考慮此方案。
適用場景:需要統計的去重內容的基數非常小的情況下可以考慮,在優雲mobile中,對於用戶基數較小的影響設備數的計算採用了此種方式。
2.基於zset的去重統計
傳統的基於跳錶/B樹的統計方式,key為維度信息,score為時間,member為設備id等原子信息,通過zcount可以拿取所有的成員數量。
優點:插入和統計都是o(log(N))的,可以精確統計從現在開始到某個時間點的用戶,可以保留原子數據。
缺點:只能自定義時間域上的左區間,對於右區間只能定義為現在時間,否則會出現統計值比實際值偏小的情況(因為同一個設備如果出現兩次,則會移除舊的那條),單一維度時占用空間過大,有幾個維度就需要幾倍的記憶體空間,3個以上複合維度時基本不需要考慮此方案。
適用場景:對於查看從現在開始1分鐘5分鐘10分鐘等各種時間跨度的用戶基數時可以考慮,在優雲mobile中,採用了這種方案來統計活躍設備數,早期開發時我們將各種時間維度和各種複合維度全部放在了redis中,結果發現記憶體開銷過大,現在的版本我們只存放了最近2分鐘的一些簡單維度的數據。
3.基於bitset的去重統計
將終端用戶id映射為一個bitset上的一個bit,利用現代處理器的特性進行快速計算。
優點:統計結果精確,對於不同維度可以使用and或者or進行聚合,數據具有原子性,通過較少的操作即可做到跨維度的計算。
缺點:不適用於分鐘級別的統計,並且用戶id的映射較為麻煩。如果使用hash的方式進行映射,將會不可避免的產生hash碰撞,如果使用用戶id進行映射,那麼必然需要維護一份用戶id映射表,這份映射表放在記憶體中會占用大量空間,放在磁碟中則會導致整個系統的處理速率降低。
備註:java中的bitset在一個byte位元組上是由低位到高位進行存儲,redis中則是由高位到低位進行存儲。
適用場景:適用於需要儲存原子數據併進行較大時間跨度或者自由拼接時間跨度聚合的場景。
4.基於hyperloglog的去重統計
hyperloglog是一種基於概率的統計方式,在redis的2.8.9版本後出現的新數據結構
詳細的內容可以查看這幾篇文章:
http://blog.codinglabs.org/tag.html#基數估計
優點:每個hyperloglog只需要12K的空間,並且誤算率只有0.81%,不同的紀錄之間可以進行聚合,也就是可以通過聚合統計出任意時間範圍的去重結果,統計單個hyperloglog時時間複雜度為o(1)。
缺點:對於統計結果要求較為精確的場合併不是非常適用
適用場景:在對誤算率要求不高的情況下,同bitset。
5.基於布隆過濾器的去重統計
布隆過濾器是一種改良的bit映射方案,通過使用多種不同的hash種子,可以做到在較低誤判率以及較高的空間利用率的情況下進行統計,redis中並沒有布隆過濾器這個數據結構,不過可以通過lua腳本的方式實現一個布隆過濾器,詳細源碼可見
https://github.com/erikdubbelboer/redis-lua-scaling-bloom-filter1
優點:對於200萬用戶不超過萬分之一誤算率的統計,只需要8M左右redis記憶體即可完成統計,萬分之一的誤算率是在插入的不同設備數達200萬次時才擁有的誤算率,在這之前的誤算率是從0開始線性增長的,在大多數情況下這個誤算率應該是可以容忍的。
缺點:布隆過濾器的統計結果無法聚合
適用場景:對於一些需要實時顯示的內容並且維度較少的內容,可以採用此數據結構,在優雲mobile中,總覽頁面的活躍設備數採用了此方案來實時顯示今日活躍設備數。
作者簡介:胡翀,廣通軟體旗下--優雲軟體打雜初級java開發工程師一枚,現任優雲大數據平臺開發工程師,負責統計平臺的數據的分析和存儲。