<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>

          如何優(yōu)雅的實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)功能?

          共 4818字,需瀏覽 10分鐘

           ·

          2024-07-18 09:19

          往期熱門(mén)文章:

          
             

          1、JetBrains再出手,這波秀翻了。。
          2、FullGC 40次/天到10天1次,真牛B!!
          3、不服不行,這才是后端API接口應(yīng)該有的樣子!
          4、一個(gè)強(qiáng)大的分布式鎖框架——Lock4j
          5、Stream很好,Map很酷,但答應(yīng)我別用toMap()


          前言


          在線人數(shù)統(tǒng)計(jì)這個(gè)功能相信大家一眼就明白是啥,這個(gè)功能不難做,實(shí)現(xiàn)的方式也很多,這里說(shuō)一下我常使用的方式:使用Redis的有序集合(zset)實(shí)現(xiàn)。核心方法是這四個(gè):zaddzrangeByScorezremrangeByScorezrem



          實(shí)現(xiàn)步驟







          1、如何認(rèn)定用戶是否在線?

          認(rèn)定用戶在線的條件一般跟網(wǎng)站有關(guān),如果網(wǎng)站需要登錄才能進(jìn)入,那么這種網(wǎng)站就是根據(jù)用戶的token令牌有效性判斷是否在線;如果網(wǎng)站是公開(kāi)的,是那種不需要登錄就可以瀏覽的,那么這種網(wǎng)站一般就需要自定一個(gè)規(guī)則來(lái)識(shí)別用戶,也有很多方式實(shí)現(xiàn)如IPdeviceId瀏覽器指紋,推薦使用瀏覽器指紋的方式實(shí)現(xiàn)。

          瀏覽器指紋可能包括以下信息的組合:用戶代理字符串 (User-Agent string)、HTTP請(qǐng)求頭信息、屏幕分辨率和顏色深度、時(shí)區(qū)和語(yǔ)言設(shè)置、瀏覽器插件詳情等。現(xiàn)成的JavaScript庫(kù),像 FingerprintJS 或 ClientJS,可以幫助簡(jiǎn)化這個(gè)過(guò)程,因?yàn)樗鼈円呀?jīng)實(shí)現(xiàn)了收集上述信息并生成唯一標(biāo)識(shí)的算法。

          使用起來(lái)也很簡(jiǎn)單,如下:

          // 安裝:npm install @fingerprintjs/fingerprintjs

          // 使用示例:
          import FingerprintJS from '@fingerprintjs/fingerprintjs';

          // 初始化指紋JS Library
          FingerprintJS.load().then(fp => {
            // 獲取訪客ID
            fp.get().then(result => {
              const visitorId = result.visitorId;
              console.log(visitorId);
            });
          });

          這樣就可以獲取一個(gè)訪問(wèn)公開(kāi)網(wǎng)站的用戶的唯一ID了,當(dāng)用戶訪問(wèn)網(wǎng)站的時(shí)候,將這個(gè)ID放到訪問(wèn)鏈接的Cookie或者h(yuǎn)eader中傳到后臺(tái),后端服務(wù)根據(jù)這個(gè)ID標(biāo)示用戶。


          2、zadd命令添加在線用戶

          zadd命令介紹 zadd命令有三個(gè)參數(shù)

          ?

          key:有序集合的名稱(chēng)。score1、score2 等:分?jǐn)?shù)值,可以是整數(shù)值或雙精度浮點(diǎn)數(shù)。member1、member2 等:要添加到有序集合的成員。例子:向名為 myzset 的有序集合中添加一個(gè)成員:ZADD myzset 1 "one"

          添加在線用戶標(biāo)識(shí)到有序集合中

          // expireTime給用戶令牌設(shè)置了一個(gè)過(guò)期時(shí)間
          LocalDateTime expireTime = LocalDateTime.now().plusSeconds(expireTimeout);
          String expireTimeStr = DateUtil.formatFullTime(expireTime);
          // 添加用戶token到有序集合中
          redisService.zadd("user.active", Double.parseDouble(expireTimeStr), userToken);
          ?

          由于一個(gè)用戶可能戶會(huì)重復(fù)登錄,這就導(dǎo)致userToken也會(huì)重復(fù),但為了不重復(fù)計(jì)算這個(gè)用戶的訪問(wèn)次數(shù),zadd命令的第二個(gè)參數(shù)很好的解決了這個(gè)問(wèn)題。我這里的邏輯是:每次添加一個(gè)在線用戶時(shí),利用當(dāng)前時(shí)間加上過(guò)期時(shí)間計(jì)算出一個(gè)分?jǐn)?shù),可以有效保證當(dāng)前用戶只會(huì)存在一個(gè)最新的登錄態(tài)。


          3、zrangeByScore命令查詢?cè)诰€人數(shù)

          zrangeByScore命令介紹

          ?

          key:指定的有序集合的名字。min 和 max:定義了查詢的分?jǐn)?shù)范圍,也可以是 -inf 和 +inf(分別表示“負(fù)無(wú)窮大”和“正無(wú)窮大”)。例子:查詢分?jǐn)?shù)在 1 到 3之間的所有成員:ZRANGEBYSCORE myzset 1 3

          查詢當(dāng)前所有的在線用戶

          // 獲取當(dāng)前的日期
          String now = DateUtil.formatFullTime(LocalDateTime.now());
          // 查詢當(dāng)前日期到"+inf"之間所有的用戶
          Set<String> userOnlineStringSet = redisService.zrangeByScore("user.active", now, "+inf");
          ?

          利用zrangeByScore方法可以查詢這個(gè)有序集合指定范圍內(nèi)的用戶,這個(gè)userOnlineStringSet也就是在線用戶集,它的size就是在線人數(shù)了。


          4、zremrangeByScore命令定時(shí)清除在線用戶

          zremrangeByScore命令介紹

          ?

          key:指定的有序集合的名字。min 和 max:定義了查詢的分?jǐn)?shù)范圍,也可以是 -inf 和 +inf(分別表示“負(fù)無(wú)窮大”和“正無(wú)窮大”)。例子:刪除分?jǐn)?shù)在 1 到 3之間的所有成員:ZREMRANGEBYSCORE myzset 1 3

          定時(shí)清除在線用戶

          // 獲取當(dāng)前的日期
          String now = DateUtil.formatFullTime(LocalDateTime.now());
          // 清除當(dāng)前日期到"-inf"之間所有的用戶
          redisService.zremrangeByScore(""user.active"","-inf", now);      
          ?

          由于有序集合不會(huì)自動(dòng)清理下線的用戶,所以這里我們需要寫(xiě)一個(gè)定時(shí)任務(wù)去定時(shí)刪除下線的用戶。


          5、zrem命令用戶退出登錄時(shí)刪除成員

          zrem命令介紹

          ?

          key:指定的有序集合的名字。members:需要?jiǎng)h除的成員 例子:刪除名為xxx的成員:ZREM myzset "xxx"

          定時(shí)清除在線用戶

          // 刪除名為xxx的成員
          redisService.zrem("user.active""xxx");      
          ?

          刪除 zset中的記錄,確保主動(dòng)退出的用戶下線。



          小結(jié)一下





          這種方案的核心邏輯就是,創(chuàng)建一個(gè)在線用戶身份集合為key,利用用戶身份為member,利用過(guò)期時(shí)間為score,然后對(duì)這個(gè)集合進(jìn)行增刪改查,實(shí)現(xiàn)起來(lái)還是比較巧妙和簡(jiǎn)單的,大家有興趣可以試試看。


          文章來(lái)源:https://juejin.cn/post/7356065093060427816

             
          往期熱門(mén)文章:

          1、你合并代碼用 merge 還是用 rebase ?
          2、99%的時(shí)間里只使用這14個(gè)Git命令就夠了!!!
          3、再見(jiàn) Navicat ?不好意思,它免費(fèi)了!
          4、@Transactional(readOnly=true)真的是提高性能的靈丹妙藥嗎?
          5、8種方案解決重復(fù)提交問(wèn)題!
          6、教你用三種方式模擬兩個(gè)線程搶票
          7、MySQL中varchar(50)和varchar(500)區(qū)別是什么?
          8、頂級(jí)Javaer都在使用的類(lèi)庫(kù),真香!
          9、最適合程序員的畫(huà)圖工具?
          10、Logback 與 log4j2 性能哪個(gè)更強(qiáng)?

          瀏覽 323
          1點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          1點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  围产精品久久久久久久 | www,五月天 | 爱逼综合网| 99精品免费在线 | 日本黄色中文字幕 |