首頁  >  文章  >  後端開發  >  PHP+REDIS實務:統計線上人數的幾種方案分析

PHP+REDIS實務:統計線上人數的幾種方案分析

藏色散人
藏色散人轉載
2021-03-17 17:24:263750瀏覽

線上人數統計業務是我們開發web肯定要設計的業務邏輯,本文就會給出幾種設計方案,來分析下各個方案的優缺點:

  • 使用有序集合

這種方案能夠同時儲存線上的使用者和使用者上線時間,能夠執行非常多的聚合計算,但是所消耗的記憶體也是非常可觀的。

  • 使用集合

這個方案能儲存線上的用戶,也能夠執行一定的聚合計算,相對有序集合,所消耗的記憶體要小些,但隨著使用者量的增多,消耗記憶體空間也處於增加狀態

  • #使用hyperloglog

這個方案無論統計多少在線用戶, 消耗的內存都是12k,但是只能給出在線用戶的統計信息,無法獲取準確的在線用戶名單

  • 使用bitmap

#這種方案還是比較好的,在盡可能節省記憶體空間情況下,記錄線上使用者的情況,而且能做一定的聚合運算

#下面我們就用實際範例來說明:

                                           下面的幾種方案

方案一:使用有序集合

先生成用戶在線記錄資料:

$start_time = mktime(0, 0, 0, 9, 5);    //monday
for ($i=0; $i < 6; $i++) {
    $day_start_time  = $start_time + 86400 * $i;    //every day begin time
    $day_end_time =  $day_start_time + 86400;       //every day end time
    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 
    for ($j=1; $j < $online_user_num; $j++) { 
        $user_id = mt_rand(1, 1000000);
        $redis->zadd(&#39;000|online_users_day_&#39;.$i, mt_rand($day_start_time, $day_end_time), $user_id);
    }
}

好了記下來我們就來看看都能統計出哪些資訊來吧

//note: 统计每天的在线总人数
for ($i=0; $i < 6; $i++) { 
    print_r($redis->zsize(&#39;000|online_users_day_&#39;.$i). "\n");
}
//note: 统计最近6天都在线的人数
var_dump($redis->zInter(&#39;000|online_users_day_both_6&#39;, 
    [
    &#39;000|online_users_day_0&#39;, 
    &#39;000|online_users_day_1&#39;, 
    &#39;000|online_users_day_2&#39;, 
    &#39;000|online_users_day_3&#39;, 
    &#39;000|online_users_day_4&#39;, 
    &#39;000|online_users_day_5&#39;
    ]
    ));
//note: 统计出近6天中共有多少上线
$redis->zunion(&#39;000|online_users_day_total_6&#39;, [&#39;000|online_users_day_0&#39;, &#39;000|online_users_day_1&#39;, &#39;000|online_users_day_2&#39;, &#39;000|online_users_day_3&#39;, &#39;000|online_users_day_4&#39;, &#39;000|online_users_day_5&#39;]);
//note: 统计某个时间段总共在线用户
print_r($redis->zcount(&#39;000|online_users_day_5&#39;, mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10)));
//note: 统计某个时间段在线用户名单
print_r($redis->zrangebyscore(&#39;000|online_users_day_5&#39;, mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10), 
    array(&#39;withscores&#39; => TRUE)));

不單單只有這些, 我們還能統計出早, 中, 午, 晚等等時間段的用戶在線情況,還有很多其他的,這就讓我們發揮想像吧,是不是挺多的?只是確實也相當耗費記憶體空間

【推薦:

PHP影片教學

#方案二:使用集合

還是先來成用戶在線記錄數據:

//note set 一般聚合
for ($i=0; $i < 6; $i++) {
    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 
    for ($j=1; $j < $online_user_num; $j++) { 
        $user_id = mt_rand(1, 1000000);
        $redis->sadd(&#39;001|online_users_day_&#39;.$i, $user_id);
    }
}

好了記下來我們就來看看都能統計出哪些信息來吧

//note 判断某个用户是否在线
var_dump($redis->sIsMember(&#39;001|online_users_day_5&#39;, 100030));
//note 每天在线用户总量的统计
for ($i=0; $i < 6; $i++) { 
    print_r($redis->ssize(&#39;001|online_users_day_&#39;.$i). "\n");
}
//note 对不同时间段的在线用户名单进行聚合
print_r($redis->sInterStore(&#39;001|online_users_day_both_4and5&#39;, &#39;001|online_users_day_4&#39;, &#39;001|online_users_day_5&#39;). "\n");
//note 对指定的时间段的在线用户名单进行统计
print_r($redis->sUnionStore(&#39;001|online_users_day_total_4add5&#39;, &#39;001|online_users_day_4&#39;, &#39;001|online_users_day_5&#39;). "\n");
//note 哪天上线哪天没上线
print_r($redis->sDiffStore(&#39;001|online_users_day_diff_4jian5&#39;, &#39;001|online_users_day_4&#39;, &#39;001|online_users_day_5&#39;). "\n");

是不是也挺不錯的,先不要著急,我們接著往下看

方案三:使用hyperloglgo

#先來成用戶線上記錄資料:

// note HyperLogLog 只需要知道在线总人数
for ($i=0; $i < 6; $i++) {
    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 
    var_dump($online_user_num);
    for ($j=1; $j < $online_user_num; $j++) { 
        $user_id = mt_rand(1, 1000000);
        $redis->pfadd(&#39;002|online_users_day_&#39;.$i, [$user_id]);
    }
}

這種方案,我們來看看都能實現哪些業務呢

$count = 0;
for ($i=0; $i < 3; $i++) { 
    $count += $redis->pfcount(&#39;002|online_users_day_&#39;.$i);
    print_r($redis->pfcount(&#39;002|online_users_day_&#39;.$i). "\n");
}
var_dump($count);
//note  3 days total online num
var_dump($redis->pfmerge(&#39;002|online_users_day_both_3&#39;, [&#39;002|online_users_day_0&#39;, &#39;002|online_users_day_1&#39;, &#39;002|online_users_day_2&#39;]));
var_dump($redis->pfcount(&#39;002|online_users_day_both_3&#39;));

好少啊,是的, 這種方案僅只能統計出某個時間段在線人數的總量, 對在線用戶的名單卻無能為力,但是卻挺節省記憶體的,對統計資料要求不多情況下,我們便可以考慮這個方案。

方案四:使用bitmap

筆者對這種方案其實挺喜歡的,消耗的記憶體空間不多, 統計的資訊卻挺多的,還是老步驟,先來產生資料:

//note bitmap 综合前面3个的优缺点
for ($i=0; $i < 6; $i++) {
    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 
    for ($j=1; $j < $online_user_num; $j++) { 
        $user_id = mt_rand(1, 1000000);
        $redis->setbit(&#39;003|online_users_day_&#39;.$i, $user_id, 1);
    }
}

接下來我們來看看能滿足的統計資料吧

//note userid today whether online 
var_dump($userid = mt_rand(1, 1000000));
var_dump($redis->getbit(&#39;003|online_users_day_5&#39;, $userid));
//note how many user is online
var_dump($redis->bitcount(&#39;003|online_users_day_5&#39;));
//note 6 days both online
var_dump($redis->bitop(&#39;AND&#39;, &#39;003|online_users_day_both_6&#39;, &#39;003|online_users_day_0&#39;, &#39;003|online_users_day_1&#39;, &#39;003|online_users_day_2&#39;, &#39;003|online_users_day_3&#39;, &#39;003|online_users_day_4&#39;, &#39;003|online_users_day_5&#39;));
var_dump($redis->bitcount(&#39;003|online_users_day_both_6&#39;));
//note 6 days total online
var_dump($redis->bitop(&#39;OR&#39;, &#39;003|online_users_day_total_6&#39;, &#39;003|online_users_day_0&#39;, &#39;003|online_users_day_1&#39;, &#39;003|online_users_day_2&#39;, &#39;003|online_users_day_3&#39;, &#39;003|online_users_day_4&#39;, &#39;003|online_users_day_5&#39;));
var_dump($redis->bitcount(&#39;003|online_users_day_total_6&#39;));
//note 6 days only one online
var_dump($redis->bitop(&#39;XOR&#39;, &#39;003|online_users_day_only_one_6&#39;, &#39;003|online_users_day_0&#39;, &#39;003|online_users_day_1&#39;, &#39;003|online_users_day_2&#39;, &#39;003|online_users_day_3&#39;, &#39;003|online_users_day_4&#39;, &#39;003|online_users_day_5&#39;));
var_dump($redis->bitcount(&#39;003|online_users_day_only_one_6&#39;));

怎麼樣?是不是集合能統計的 這傢伙也能統計出來?而且消耗的內容還少。

對於這幾種方案其實各有各的好處, 根據業務統計資料 來取對應的方案來實作吧,這樣記憶體利用也就更合理了

以上是PHP+REDIS實務:統計線上人數的幾種方案分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:饼bing。如有侵權,請聯絡admin@php.cn刪除