原文地址:https://blog.csdn.net/fenglei0415/article/details/80607126 在構(gòu)建應(yīng)用的時候, 我們經(jīng)常需要對用戶的一舉一動進行記錄, 而其中一個比較重要的操作, 就是對在線的用戶進行記錄。 本文將介紹四種使用 Redis 對在線用戶進行記錄的方案, 這些方案雖然都可以對在線用戶的數(shù)量進行統(tǒng)計, 但每個方案都有一些自己特有的操作, 并且各個方案的性能特征以及資源消耗也各有不同。
方案 1 :使用有序集合每當(dāng)一個用戶上線時, 我們就執(zhí)行 ZADD 命令, 將這個用戶以及它的在線時間添加到指定的有序集合中:
通過使用 ZSCORE 命令檢查指定的用戶 ID 在有序集合中是否有相關(guān)聯(lián)的分值, 我們可以知道該用戶是否在線:
而通過執(zhí)行 ZCARD 命令, 我們可以知道總共有多用戶在線:
使用有序集合儲存在線用戶的強大之處在于, 它是本文介紹的所有方案當(dāng)中, 能夠執(zhí)行最多聚合操作的一個方案, 原因在于, 這一方案既可以通過有序集合的成員(也即是用戶的 ID)進行聚合操作, 也可以根據(jù)有序集合的分值(也即是用戶的登錄時間)進行聚合操作。 首先, 通過 ZINTERSTORE 和 ZUNIONSTORE 命令, 我們可以對多個記錄了在線用戶的有序集合進行聚合計算:
此外, 通過 ZCOUNT 命令, 我們可以統(tǒng)計出在指定的時間段之內(nèi)有多少用戶在線, 而 ZRANGEBYSCORE 命令則可以讓我們獲取到這些用戶的名單:
通過這一方法, 我們可以知道網(wǎng)站在不同時間段的上線人數(shù)以及上線用戶名單, 比如說, 我們可以用這個方法來分別獲知網(wǎng)站在早晨、上午、中午、下午和夜晚的上線人數(shù)。
方案 2 :使用集合正如上一節(jié)所說, 使用有序集合能夠同時儲存在線用戶的名單以及各個用戶的上線時間, 但如果我們只想要記錄在線用戶的名單, 而不想要儲存用戶的上線時間, 那么也可以使用集合來代替有序集合, 對在線的用戶進行記錄。 在這種情況下, 每當(dāng)一個用戶上線時, 我們就執(zhí)行以下 SADD 命令, 將它添加到在線用戶名單當(dāng)中:
通過使用 SISMEMBER 命令, 我們可以檢查一個指定的用戶當(dāng)前是否在線:
而統(tǒng)計在線人數(shù)的工作則可以通過執(zhí)行 SCARD 命令來完成:
通過集合運算操作, 我們可以像有序集合方案一樣, 對不同時間段或者日期的在線用戶名單進行聚合計算。 比如說, 通過 SINTER 或者 SINTERSTORE 命令, 我們可以計算出一周都有在線的用戶:
此外, 通過 SUNION 命令或者 SUNIONSTORE 命令, 我們可以計算出一周內(nèi)在線用戶的總數(shù)量:
而通過執(zhí)行 SDIFF 命令或者 SDIFFSTORE 命令, 我們可以知道哪些用戶今天上線了, 但是昨天沒有上線:
又或者工作日上線了, 但是假日沒有上線:
方案 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 命令去記錄在線的用戶:
使用 PFCOUNT 命令獲取在線人數(shù):
因為 HyperLogLog 也提供了計算交集的 PFMERGE 命令, 所以我們也可以用這個命令計算出多個給定時間段或日期之內(nèi), 上線的總?cè)藬?shù):
方案 4 :使用位圖(bitmap)回顧上面介紹的三個方案, 我們可以得出以上結(jié)論:
那么是否存在一種既能夠獲得在線用戶名單, 又可以盡量減少內(nèi)存消耗的方法存在呢? 這種方法的確存在 —— 使用 Redis 的位圖就可以辦到。 Redis 的位圖就是一個由二進制位組成的數(shù)組, 通過將數(shù)組中的每個二進制位與用戶 ID 進行一一對應(yīng), 我們可以使用位圖去記錄每個用戶是否在線。 當(dāng)一個用戶上線時, 我們就使用 SETBIT 命令, 將這個用戶對應(yīng)的二進制位設(shè)置為 1 :
通過使用 GETBIT 命令去檢查一個二進制位的值是否為 1 , 我們可以知道指定的用戶是否在線:
而通過 BITCOUNT 命令, 我們可以統(tǒng)計出位圖中有多少個二進制位被設(shè)置成了 1 , 也即是有多少個用戶在線:
跟集合一樣, 用戶也能夠?qū)Χ鄠€位圖進行聚合計算 —— 通過 BITOP 命令, 用戶可以對一個或多個位圖執(zhí)行邏輯并、邏輯或、邏輯異或或者邏輯非操作:
雖然位圖節(jié)約內(nèi)存的效果不及 HyperLogLog 那么顯著, 但是使用位圖可以準確地判斷一個用戶是否上線, 并且能夠像集合和有序集合一樣, 對在線用戶名單進行聚合計算。 因此對于想要盡量節(jié)約內(nèi)存, 但又需要準確地知道用戶是否在線, 又或者需要對用戶的在線名單進行聚合計算的應(yīng)用來說, 使用位圖可以說是最佳之選。
總結(jié)以下表格總結(jié)了以上四個方案的特點:
|
|