腾讯在线人数统计_PHP + REDIS 实践:统计在线人数的几种方案分析
(給PHP開發者加星標,提升PHP技能)
轉自:餅bing
blog.csdn.net/hao508506/article/details/52496656
在線人數統計業務是我們開發web肯定要設計的業務邏輯,本文就會給出幾種設計方案,來分析下各個方案的優缺點:
- 使用有序集合
這種方案能夠同時儲存在線的用戶 和 用戶上線時間,能夠執行非常多的聚合計算,但是所消耗的內存也是非常可觀的。
- 使用集合
這種方案能儲存在線的用戶,也能夠執行一定的聚合計算,相對有序集合,所消耗的內存要小些,但是隨著用戶量的增多,消耗內存空間也處于增加狀態
- 使用hyperloglog
這種方案無論統計多少在線用戶, 消耗的內存都是12k,但是只能給出在線用戶的統計信息,無法獲取準確的在線用戶名單
- 使用bitmap
這種方案還是比較好的,在盡可能節省內存空間情況下,記錄在線用戶的情況,而且能做一定的聚合運算
下面我們就用實際例子來說明:
我們先以每天會有10w~30w的小量用戶, 100w的用戶群來說明下面的幾種方案
方案一:使用有序集合
先生成用戶在線記錄數據:
$start_time?=?mktime(0,?0,?0,?9,?5);????//mondayfor?($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?????????$user_id?=?mt_rand(1,?1000000);
????????$redis->zadd('000|online_users_day_'.$i,?mt_rand($day_start_time,?$day_end_time),?$user_id);
????}
}
好了記下來我們就來看看都能統計出哪些信息來吧
//note:?統計每天的在線總人數for?($i=0;?$i?6;?$i++)?{?
????print_r($redis->zsize('000|online_users_day_'.$i).?"\n");
}
//note:?統計最近6天都在線的人數
var_dump($redis->zInter('000|online_users_day_both_6',?
????[
????'000|online_users_day_0',?
????'000|online_users_day_1',?
????'000|online_users_day_2',?
????'000|online_users_day_3',?
????'000|online_users_day_4',?
????'000|online_users_day_5'
????]
????));
//note:?統計出近6天中共有多少上線
$redis->zunion('000|online_users_day_total_6',?['000|online_users_day_0',?'000|online_users_day_1',?'000|online_users_day_2',?'000|online_users_day_3',?'000|online_users_day_4',?'000|online_users_day_5']);
//note:?統計某個時間段總共在線用戶
print_r($redis->zcount('000|online_users_day_5',?mktime(13,?0,?0,?9,?10),?mktime(14,?0,?0,?9,?10)));
//note:?統計某個時間段在線用戶名單
print_r($redis->zrangebyscore('000|online_users_day_5',?mktime(13,?0,?0,?9,?10),?mktime(14,?0,?0,?9,?10),?
????array('withscores'?=>?TRUE)));
不單單只有這些, 我們還能統計出早, 中, 午, 晚 等等時間段的用戶在線情況,還有很多其他的,這就讓我們發揮想象吧,是不是挺多的?只是確實也相當耗費內存空間
方案二:使用集合
還是先來成用戶在線記錄數據:
//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?????????$user_id?=?mt_rand(1,?1000000);
????????$redis->sadd('001|online_users_day_'.$i,?$user_id);
????}
}
好了記下來我們就來看看都能統計出哪些信息來吧
//note?判斷某個用戶是否在線var_dump($redis->sIsMember('001|online_users_day_5',?100030));
//note?每天在線用戶總量的統計
for?($i=0;?$i?6;?$i++)?{?
????print_r($redis->ssize('001|online_users_day_'.$i).?"\n");
}
//note?對不同時間段的在線用戶名單進行聚合
print_r($redis->sInterStore('001|online_users_day_both_4and5',?'001|online_users_day_4',?'001|online_users_day_5').?"\n");
//note?對指定的時間段的在線用戶名單進行統計
print_r($redis->sUnionStore('001|online_users_day_total_4add5',?'001|online_users_day_4',?'001|online_users_day_5').?"\n");
//note?哪天上線哪天沒上線
print_r($redis->sDiffStore('001|online_users_day_diff_4jian5',?'001|online_users_day_4',?'001|online_users_day_5').?"\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?????????$user_id?=?mt_rand(1,?1000000);
????????$redis->pfadd('002|online_users_day_'.$i,?[$user_id]);
????}
}
這種方案,我們來看看都能實現哪些業務呢
$count?=?0;for?($i=0;?$i?3;?$i++)?{?
????$count?+=?$redis->pfcount('002|online_users_day_'.$i);
????print_r($redis->pfcount('002|online_users_day_'.$i).?"\n");
}
var_dump($count);
//note??3?days?total?online?num
var_dump($redis->pfmerge('002|online_users_day_both_3',?['002|online_users_day_0',?'002|online_users_day_1',?'002|online_users_day_2']));
var_dump($redis->pfcount('002|online_users_day_both_3'));
好少啊,是的, 這種方案僅僅只能統計出某個時間段在線人數的總量, 對在線用戶的名單卻無能為力,但是卻挺節省內存的,對統計數據要求不多情況下 ,我們便可以考慮這種方案。
方案四:使用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?????????$user_id?=?mt_rand(1,?1000000);
????????$redis->setbit('003|online_users_day_'.$i,?$user_id,?1);
????}
}
接下來我們看看能滿足的統計信息吧
//note?userid?today?whether?online?var_dump($userid?=?mt_rand(1,?1000000));
var_dump($redis->getbit('003|online_users_day_5',?$userid));
//note?how?many?user?is?online
var_dump($redis->bitcount('003|online_users_day_5'));
//note?6?days?both?online
var_dump($redis->bitop('AND',?'003|online_users_day_both_6',?'003|online_users_day_0',?'003|online_users_day_1',?'003|online_users_day_2',?'003|online_users_day_3',?'003|online_users_day_4',?'003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_both_6'));
//note?6?days?total?online
var_dump($redis->bitop('OR',?'003|online_users_day_total_6',?'003|online_users_day_0',?'003|online_users_day_1',?'003|online_users_day_2',?'003|online_users_day_3',?'003|online_users_day_4',?'003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_total_6'));
//note?6?days?only?one?online
var_dump($redis->bitop('XOR',?'003|online_users_day_only_one_6',?'003|online_users_day_0',?'003|online_users_day_1',?'003|online_users_day_2',?'003|online_users_day_3',?'003|online_users_day_4',?'003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_only_one_6'));
怎么樣?是不是集合能統計的 這家伙也能統計出來?而且消耗的內容還少。
對于這幾種方案其實各有各的好處, 根據業務統計信息 來取相應的方案來實施吧,這樣內存利用也就更合理了
- EOF -
推薦閱讀??點擊標題可跳轉1、如何在 PHP 中進行會話處理?
2、PHP下kafka的實踐
3、PHP 內存泄漏問題解析
看完本文有收獲?請分享給更多人
推薦關注「PHP開發者」,提升PHP技能
點贊和在看就是最大的支持??
總結
以上是生活随笔為你收集整理的腾讯在线人数统计_PHP + REDIS 实践:统计在线人数的几种方案分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring resttemplate
- 下一篇: mysql mysqldumpslow_