實現統計在線用戶的幾種方式,歡迎你們發表觀點!

最近在考慮作個統計在線用戶的功能。之前也作過,用的一些比較簡單的方法,可是缺點也很明顯:精確統計和服務器、數據庫壓力之間要作出平衡。
因此想找一個既能精確統計又能不佔用太多服務器資源的方法。先說說一些日常的作法:html

一,每次用戶操做更新其在線時間

這個方法很直接,在用戶表裏加一個字段update_time,每次用戶進行操做,都更新這個字段爲當前時間,通常是在一個被全部Action繼承的基類裏寫這個操做。
而後定義一個過時時間,好比10分鐘,表示10分鐘沒進行任何操做的用戶默認爲不在線。這樣,統計當前在線用戶的sql語句大概是這樣web

  1. select count(*) from think_user where update_time>now()-10*60

優勢:實現簡單,通俗易懂
缺點:1,對「在線」的定義模糊,萬一用戶看一篇文章時間比較長,10分鐘內沒進行任何操做,他就被忽略了;2,若是user表數據量很大,那效率將極差ajax

二,將在線用戶單獨放入一張表

對於方法一的改進。新建一張表think_inline,字段有user_id、update_time,每次用戶操做時,先判斷表裏有沒有該用戶的記錄,沒有則新增,有就更新update_time。
並同時加上刪除失效數據操做sql

delete from think_inline where update_time<now()-10*60

這樣,統計在線就能夠直接count這張表就好了。並且這表的數據量不會很大(至少要比用戶表小的多)

優勢:減小數據庫壓力
缺點:仍然對「在線」的定義不許確數據庫

三,用JS定時器

這個方法是綜合了一和二。新建一張表think_inline,也是在基類中定義每次用戶操做時更新時間,參考二的作法。
不一樣之處是,在每一個html模板裏,加上一個js定時器,setInterval('updateTime', 10*3600);每隔10分鐘發送一次ajax請求,更新update_time字段。這樣,即便用戶在一個頁面停留時間過長,也不會被誤認爲不在線了。而且能夠經過減小請求的間隔,來增長精確度,固然了,對服務器的壓力就更大了。

優勢:對在線的判斷較爲準確
缺點:仍然不能既精確又不增長服務器壓力,必須在二者之間進行取捨。瀏覽器

四,使用TP的SessionDb驅動進行最優化設計


這也就是網上有人說的session存入數據庫的方法,這種方法優勢不少。服務器

 

 

1,爲何要將session存入數據庫?

session是存儲在服務器的一組臨時數據。通常狀況下,咱們在作用戶登陸時,會將用戶數據存入session。這樣,在任何頁面均可以方便調用,並且每一個客戶端會產生惟一的session_id,不會混餚。而且在關閉瀏覽器後,服務器會有session回收機制,自動刪除過時session。

這是session的優勢:惟一性、方便調用、不會過多佔用資源。可是也有缺點:在客戶端是以cookie方式保存的,禁用cookie就沒用了。

那麼,服務器是如何存放session的呢?他是默認將session以文件的方式保存在硬盤上的。但是,對於咱們碼農來講,操做數據庫要比讀文件方便的多,而且能夠對session數據進行各類操做。

而統計在線用戶人數就是經過統計有多少條session記錄來實現的。cookie

 

 

 

 

 

 

2,如何把session存入數據庫?


TP的SessionDb驅動就實現了這個功能。原理就是經過改寫PHP默認的session操做來實現,核心函數session_set_save_handler(),有興趣的能夠研究一下。該驅動將session的增、讀、取、和刪都放入了數據庫。
使用方法也很簡單:1,建表,驅動的註釋裏的sql語句運行下就好
2,添加配置:session

 

 

 

//Session配置
'SESSION_TYPE'          => 'db',            //數據庫存儲session
'SESSION_TABLE'         => 'think_session',    //存session的表
'SESSION_EXPIRE'        => 600,                //session過時時間

 

這樣,只要咱們在程序裏使用了session()函數,數據庫裏就會有記錄。

 函數

3,利用數據庫session實現統計在線用戶


1,統計在線總人數

  1. $map = array('session_expire'=>array('gt',NOW_TIME));
    $inline = D('Session')->where($map)->count();

     

2,統計遊客(未登陸)人數

  1. $map = array('session_expire'=>array('gt',NOW_TIME),'session_data'=>array('eq',''));
    $huiyuan = D('Session')->where($map)->count();

     

3,統計會員(已登陸)人數

  1. $map = array('session_expire'=>array('gt',NOW_TIME),'session_data'=>array('neq',''));
    $huiyuan = D('Session')->where($map)->count();

     

4,判斷一個用戶是否在線。
在用戶表裏新增一個字段:session_id。
(1)在登陸操做裏,保存該用戶的session_id,

  1. $session_id = session_id();
    D('User')->where(array('id'=>$user_id))->save('session_id'=>$session_id);

     

(2)檢查session表裏是否存在該session_id,未過時而且有值,

  1. $map = array('session_id'=>$session_id,'session_expire'=>array('gt',NOW_TIME),'session_data'=>array('neq',''));
    $res = D('Session')->where($map)->find();
    if($res){
       dump('該用戶在線。')
    }else{
       dump('該用戶不在線。')
    }

     


碼字太麻煩啦,先寫這麼多,後面總結該方法的幾大優勢以及注意事項。

 

 

4,總結


1,實現步驟:用戶表新增字段保存session_id;使用TP的SessionDb驅動。是否是很簡單?

2,優勢
(1)比上面三種方法對數據庫和服務器的壓力都小,操做簡單
(2)可以區分在線用戶是會員仍是遊客(session_data字段是否有值),discuz就是這樣作的
(3)能夠經過刪除某用戶的session記錄,實現將其「踢下線」的功能

3,缺點
(1)仍然不能精確統計,只能說,XX秒內在線多少人

4,注意事項
(1)因爲該方法的SessionDb驅動必須使用session()函數才能觸發,因此必須配置自動開啓session(默認就是開啓)。TP在執行流程裏會使用session()函數,因此你什麼都不寫,session數據也會存入數據庫。
(2)由於數據庫的session數據是不會本身刪除的,因此對於過時的數據,必須調用session()方法纔會刪。
這也就意味着,若是你的網站一我的都沒有訪問,那麼數據庫的過時session記錄會一直存在。

也就是因爲這種機制,對於一些突發事件(用戶直接X瀏覽器、直接關機、發生地震……),在其關閉瀏覽器的一段時間(session過時時間)後,其餘用戶對網站的訪問,會觸發session回收,刪除過時記錄。因此,就不怕統計出來的數據不許確了。
固然了,就算沒人訪問,你也能夠在count時加上session_expire>time()來統計。

可是也有偏差,就是session過時時間,5分鐘後過時,就有5分鐘的偏差。時間設的越小,對數據庫的操做就越頻繁;越大,精確度就越低。

(3)這個session過時時間就意味着,若是用戶5分鐘內不進行任何操做,其就會自動退出登陸。因此,爲了用戶體驗好,請加上cookie自動登陸功能。目前官網就是這麼作的。

(4)評論裏有人提到,驗證碼也會存入session,因此咱們判斷的時候,就不能值統計有值的記錄了。
須要先獲取有值的數據,再判斷裏面有沒有保存用戶信息的參數名。雖然session_data字段是用二進制存儲的,可是查詢出來就是一個字符串。
好比,咱們用的user下標來保存的用戶信息,

 

 

  1. session('user',$data);//用戶登陸信息
    //獲取真實會員數
    //查詢有值的session記錄
    $list = D('Session')->where(array('session_data'=>array('NEQ',''),'session_expire'=>array('lt',NOW_TIME)))->select();
    //判斷值裏是否有會員標識
    foreach($list as $k=>$value){
      if(strpos($value['session_data'],'user') === false){
                    $count++;
                }
    dump($count);//真實會員人數
    }

     

(5)因爲每種瀏覽器都有各自的session機制,因此,若是一我的在一臺電腦上同時開了5種瀏覽器,則數據庫會保存5條不一樣的記錄
實際使用時,仍須要考慮搜索引擎的偏差。在其抓取咱們的頁面時,也會產生session。

 

 

五,最終結論

因爲HTTP協議的限制:請求完成後就會斷開與客戶端的鏈接。因此實際上,

 

 

咱們根本沒法精確而實時地統計在線人數


儘管有各類各樣的方法來增長統計的精確度,然而都是治標不治本。

惟有放棄HTTP協議,使用「長鏈接」的連接方式,才能精確判斷用戶在仍是離



至此,完結


後續,官網將推出聊天室的功能,相似於webQQ,更加方便你們的交流。元芳,你怎麼看?
 

求「贊」求「收藏」

相關文章
相關標籤/搜索