<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用Spark Streaming實時計算海量用戶UV

          共 2030字,需瀏覽 5分鐘

           ·

          2021-07-17 10:31

          提出需求
          實時統(tǒng)計業(yè)務(wù)系統(tǒng)(web,APP之類)的訪問人數(shù),即所謂UV,或者DAU指標(biāo).
          這個需求怕是流計算最最最常見的需求了.
          計算UV的關(guān)鍵點就在于去重,即同一個人訪問兩次是只計一個UV的.在離線計算中統(tǒng)計UV比較容易想到的方法就是用group或distinct機制來去重.但是在實時計算場景,還用group就不太科學(xué)了,一個是全量數(shù)據(jù)的group是比較費時的,第二個是全量數(shù)據(jù)的group是很費內(nèi)存和CPU的.特別是當(dāng)用戶量巨大的時候,還要做到秒級更新就更難了.
          總結(jié)起來,需求就是:海量用戶場景UV實時計算.
          接受挑戰(zhàn)
          不難發(fā)現(xiàn),問題的主要難點就是去重.
          Spark Streaming目前沒有給出內(nèi)置方案(這個其實可以有),但是海量數(shù)據(jù)去重問題早就有解決辦法了.
          所以Spark Streaming程序完全可以利用其他系統(tǒng)的現(xiàn)有方案解決去重問題,比如Redis.
          Redis的海量去重計數(shù)方案
          Bitmap方案
          所謂的Bitmap就是用一個bit位來標(biāo)記某個元素對應(yīng)的Value,比如ID為2的用戶,就用第2個bit位來表示,然后用該位的值來表示該用戶是否訪問過.如果要計算UV,那就只要數(shù)一下有多少個1就行啦.
          假設(shè)我們有40億用戶,使用Bitmap需要2^32個bit位,算下來也就500M左右.
          你可能沒想到的是,Redis中最常用的數(shù)據(jù)結(jié)構(gòu)string,就可以實現(xiàn)bitmap算法.
          Redis提供了如下命令

          // 插入setbit key offset value//獲取getbit key offset//計數(shù)BITCOUNT key [start] [end]
          這里offset最大值就是2^32.
          比如ID為2的用戶,可以setbit uv 2 1,來記錄.
          最后要計算UV,就直接 BITCOUNT uv. 這步計數(shù)非???復(fù)雜度是O(1).
          HyperLogLog方案
          若要計算很多頁面的UV,用bitmap還是比較費空間的,N個頁面就得有N個500M.這時候HyperLogLog結(jié)構(gòu)就是一個比較好的選擇.
          Redis 在 2.8.9 版本添加了 HyperLogLog 結(jié)構(gòu)。
          Redis HyperLogLog 是用來做基數(shù)統(tǒng)計的算法,HyperLogLog 的優(yōu)點是,在輸入元素的數(shù)量或者體積非常非常大時,計算基數(shù)所需的空間總是固定 的、并且是很小的。
          在 Redis 里面,每個 HyperLogLog 鍵只需要花費 12 KB 內(nèi)存,就可以計算接近 2^64 個不同元素的基 數(shù)。這和計算基數(shù)時,元素越多耗費內(nèi)存就越多的集合形成鮮明對比。
          但是,因為 HyperLogLog 只會根據(jù)輸入元素來計算基數(shù),而不會儲存輸入元素本身,所以 HyperLogLog 不能像集合那樣,返回輸入的各個元素。
          也就是說HyperLogLog是一種基數(shù)統(tǒng)計算法,計算結(jié)果是近似值, 12 KB 內(nèi)存就可以計算2^64 個不同元素的基數(shù).
          Redis命令如下:
          redis 127.0.0.1:6379> PFADD runoobkey "redis"

          1) (integer) 1

          redis 127.0.0.1:6379> PFADD runoobkey "mongodb"

          1) (integer) 1

          redis 127.0.0.1:6379> PFADD runoobkey "mysql"

          1) (integer) 1

          redis 127.0.0.1:6379> PFCOUNT runoobkey

          (integer) 3
          代碼實現(xiàn)
          下面給出HyperLogLog方案的參考實現(xiàn):
          stream.foreachRDD { rdd => //統(tǒng)計人數(shù) rdd.foreachPartition { partition => //從分區(qū)所屬executor的redis線程池獲取一個連接. val redis = RedisUtil.getRedis partition.foreach { case (date, userId) => //統(tǒng)計當(dāng)前userId redis.pfadd(s"uv:$date", userId) } redis.close() }}

          關(guān)于Redis的連接,如果是用java或scala可以使用JedisPool,注意處理序列化即可.
          原文鏈接:https://blog.csdn.net/liam08/article/details/80155006
          瀏覽 47
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷五缴天国产激情 | 人操人操人人摸 | 日韩免费网站 | 99热国| 综合第一页 |