小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

實戰(zhàn)中使用 Redis 統(tǒng)計在線用戶人數(shù)

 JhouShuai 2018-12-18

 原文地址:https://blog.csdn.net/fenglei0415/article/details/80607126 

    在構(gòu)建應(yīng)用的時候, 我們經(jīng)常需要對用戶的一舉一動進行記錄, 而其中一個比較重要的操作, 就是對在線的用戶進行記錄。

本文將介紹四種使用 Redis 對在線用戶進行記錄的方案, 這些方案雖然都可以對在線用戶的數(shù)量進行統(tǒng)計, 但每個方案都有一些自己特有的操作, 并且各個方案的性能特征以及資源消耗也各有不同。

 

方案 1 :使用有序集合

每當(dāng)一個用戶上線時, 我們就執(zhí)行 ZADD 命令, 將這個用戶以及它的在線時間添加到指定的有序集合中:

 

ZADD "online_users" <user_id> <current_timestamp>

通過使用 ZSCORE 命令檢查指定的用戶 ID 在有序集合中是否有相關(guān)聯(lián)的分值, 我們可以知道該用戶是否在線:

ZSCORE "online_users" <user_id>

而通過執(zhí)行 ZCARD 命令, 我們可以知道總共有多用戶在線:

ZCARD "online_users"

使用有序集合儲存在線用戶的強大之處在于, 它是本文介紹的所有方案當(dāng)中, 能夠執(zhí)行最多聚合操作的一個方案, 原因在于, 這一方案既可以通過有序集合的成員(也即是用戶的 ID)進行聚合操作, 也可以根據(jù)有序集合的分值(也即是用戶的登錄時間)進行聚合操作。

首先, 通過 ZINTERSTORE 和 ZUNIONSTORE 命令, 我們可以對多個記錄了在線用戶的有序集合進行聚合計算:

  1. # 計算出 7 天之內(nèi)都有上線的用戶,并將它儲存到 7_days_both_online_users 有序集合當(dāng)中
  2. ZINTERSTORE 7_days_both_online_users 7 "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
  3. # 計算出 7 天之內(nèi)總共有多少人上線了
  4. ZUNIONSTORE 7_days_total_online_users 7 "day_1_online_users" ... "day_7_online_users"

此外, 通過 ZCOUNT 命令, 我們可以統(tǒng)計出在指定的時間段之內(nèi)有多少用戶在線, 而 ZRANGEBYSCORE 命令則可以讓我們獲取到這些用戶的名單:

  1. # 統(tǒng)計指定時間段內(nèi)上線的用戶數(shù)量
  2. ZCOUNT "online_users" <start_timestamp> <end_timestamp>
  3. # 獲取指定時間段內(nèi)上線的用戶名單
  4. ZRANGEBYSCORE "online_users" <start_timestamp> <end_timestamp> WITHSCORES

通過這一方法, 我們可以知道網(wǎng)站在不同時間段的上線人數(shù)以及上線用戶名單, 比如說, 我們可以用這個方法來分別獲知網(wǎng)站在早晨、上午、中午、下午和夜晚的上線人數(shù)。

 

方案 2 :使用集合

正如上一節(jié)所說, 使用有序集合能夠同時儲存在線用戶的名單以及各個用戶的上線時間, 但如果我們只想要記錄在線用戶的名單, 而不想要儲存用戶的上線時間, 那么也可以使用集合來代替有序集合, 對在線的用戶進行記錄。

在這種情況下, 每當(dāng)一個用戶上線時, 我們就執(zhí)行以下 SADD 命令, 將它添加到在線用戶名單當(dāng)中:

SADD "online_users" <user_id>

通過使用 SISMEMBER 命令, 我們可以檢查一個指定的用戶當(dāng)前是否在線:

SISMEMBER "online_users" <user_id>

而統(tǒng)計在線人數(shù)的工作則可以通過執(zhí)行 SCARD 命令來完成:

SCARD "online_users"

通過集合運算操作, 我們可以像有序集合方案一樣, 對不同時間段或者日期的在線用戶名單進行聚合計算。 比如說, 通過 SINTER 或者 SINTERSTORE 命令, 我們可以計算出一周都有在線的用戶:

SINTER "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

此外, 通過 SUNION 命令或者 SUNIONSTORE 命令, 我們可以計算出一周內(nèi)在線用戶的總數(shù)量:

SUNION "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

而通過執(zhí)行 SDIFF 命令或者 SDIFFSTORE 命令, 我們可以知道哪些用戶今天上線了, 但是昨天沒有上線:

SDIFF "today_online_users" "yesterday_online_users"

又或者工作日上線了, 但是假日沒有上線:

  1. # 計算工作日上線名單
  2. SINTERSTORE "weekday_online_users" "monday_online_users" "tuesday_online_users" ... "friday_online_users"
  3. # 計算假日上線名單
  4. SINTERSTORE "holiday_online_users" "saturday_online_users" "sunday_online_users"
  5. # 計算工作日上線但是假日未上線的名單
  6. SDIFF "weekday_online_users" "holiday_online_users"

方案 3 :使用 HyperLogLog

雖然使用有序集合和集合能夠很好地完成記錄在線人數(shù)的工作, 但以上這兩個方案都有一個明顯的缺點, 那就是, 這兩個方案耗費的內(nèi)存會隨著被統(tǒng)計用戶數(shù)量的增多而增多: 如果你的網(wǎng)站用戶數(shù)量比較多, 又或者你需要記錄多天/多個時段的在線用戶名單并進行聚合計算, 那么這兩個方案可能會消耗你大量內(nèi)存。

另一方面, 在有些情況下, 我們只想要知道在線用戶的人數(shù), 而不需要知道具體的在線用戶名單, 這時有序集合和集合儲存的信息就會顯得多余了。

在需要盡可能地節(jié)約內(nèi)存并且只需要知道在線用戶數(shù)量的情況下, 我們可以使用 HyperLogLog 來對在線用戶進行統(tǒng)計: HyperLogLog 是一個概率算法, 它可以對元素的基數(shù)進行估算, 并且每個 HyperLogLog 只需要耗費 12 KB 內(nèi)存, 對于用戶數(shù)量非常多但是內(nèi)存卻非常緊張的系統(tǒng), 這一方案無疑是最佳之選。

在這一方案下, 我們使用 PFADD 命令去記錄在線的用戶:

PFADD "online_users" <user_id>

使用 PFCOUNT 命令獲取在線人數(shù):

PFCOUNT "online_users"

因為 HyperLogLog 也提供了計算交集的 PFMERGE 命令, 所以我們也可以用這個命令計算出多個給定時間段或日期之內(nèi), 上線的總?cè)藬?shù):

  1. # 統(tǒng)計 7 天之內(nèi)總共有多少人上線了
  2. PFMERGE "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
  3. PFCOUNT "7_days_both_online_users"

方案 4 :使用位圖(bitmap)

回顧上面介紹的三個方案, 我們可以得出以上結(jié)論:

  • 使用有序集合或者集合能夠儲存具體的在線用戶名單, 但是卻需要消耗大量的內(nèi)存;
  • 而使用 HyperLogLog 雖然能夠有效地減少統(tǒng)計在線用戶所需的內(nèi)存, 但是它卻沒辦法準確地記錄具體的在線用戶名單。

那么是否存在一種既能夠獲得在線用戶名單, 又可以盡量減少內(nèi)存消耗的方法存在呢? 這種方法的確存在 —— 使用 Redis 的位圖就可以辦到。

Redis 的位圖就是一個由二進制位組成的數(shù)組, 通過將數(shù)組中的每個二進制位與用戶 ID 進行一一對應(yīng), 我們可以使用位圖去記錄每個用戶是否在線。

當(dāng)一個用戶上線時, 我們就使用 SETBIT 命令, 將這個用戶對應(yīng)的二進制位設(shè)置為 1 :

  1. # 此處的 user_id 必須為數(shù)字,因為它會被用作索引
  2. SETBIT "online_users" <user_id> 1

通過使用 GETBIT 命令去檢查一個二進制位的值是否為 1 , 我們可以知道指定的用戶是否在線:

GETBIT "online_users" <user_id>

而通過 BITCOUNT 命令, 我們可以統(tǒng)計出位圖中有多少個二進制位被設(shè)置成了 1 , 也即是有多少個用戶在線:

BITCOUNT "online_users"

跟集合一樣, 用戶也能夠?qū)Χ鄠€位圖進行聚合計算 —— 通過 BITOP 命令, 用戶可以對一個或多個位圖執(zhí)行邏輯并、邏輯或、邏輯異或或者邏輯非操作:

  1. # 計算出 7 天都在線的用戶
  2. BITOP "AND" "7days_both_online_users" "day1_online_users" "day2_online_users" ... "day7_online_users"
  3. # 計算出 7 在的在線用戶總?cè)藬?shù)
  4. BITOP "OR" "7days_total_online_users" "day1_online_users" "day2_online_users" ... "day_7_online_users"
  5. # 計算出兩天當(dāng)中只有其中一天在線的用戶
  6. BITOP "XOR" "only_one_day_online" "day1_online_users" "day2_online_users"


HyperLogLog 方案記錄一個用戶是否在線需要花費 1 個二進制位, 對于用戶數(shù)為 100 萬的網(wǎng)站來說, 使用這一方案只需要耗費 125 KB 內(nèi)存, 而對于用戶數(shù)為 1000 萬的網(wǎng)站來說, 使用這一方案也只需要花費 1.25 MB 內(nèi)存。

雖然位圖節(jié)約內(nèi)存的效果不及 HyperLogLog 那么顯著, 但是使用位圖可以準確地判斷一個用戶是否上線, 并且能夠像集合和有序集合一樣, 對在線用戶名單進行聚合計算。 因此對于想要盡量節(jié)約內(nèi)存, 但又需要準確地知道用戶是否在線, 又或者需要對用戶的在線名單進行聚合計算的應(yīng)用來說, 使用位圖可以說是最佳之選。

 

總結(jié)

以下表格總結(jié)了以上四個方案的特點:

方案 特點
有序集合 能夠同時儲存在線用戶的名單以及用戶的上線時間,能夠執(zhí)行非常多的聚合計算操作,但是耗費的內(nèi)存也非常多。
集合 能夠儲存在線用戶的名單,也能夠執(zhí)行聚合計算,消耗的內(nèi)存比有序集合少,但是跟有序集合一樣,這個方案消耗的內(nèi)存也會隨著用戶數(shù)量的增多而增多。
HyperLogLog 無論需要統(tǒng)計的用戶有多少,只需要耗費 12 KB 內(nèi)存,但由于概率算法的特性,只能給出在線人數(shù)的估算值,并且也無法獲取準確的在線用戶名單。
位圖 在盡可能節(jié)約內(nèi)存的情況下,記錄在線用戶的名單,并且能夠?qū)@些名單執(zhí)行聚合操作。

 

 

 

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多