作者 主題: IDEA~比 PHP SESSION 使用 MEMCACHE 更有效率的做法 , 實驗中.  (閱讀 4274 次)

0 會員 與 1 訪客 正在閱讀本文。

FIEND

  • 鑽研的研究生
  • *****
  • 文章數: 700
    • 檢視個人資料
    • http://bbs.ecstart.com
剛才.... 無聊又~寫了支很簡單的 元件.

手工DIY 只是想看看 這個做法的 效能....

可以掛到 PHP FPM 或 HTTP SERVER 上.

它的功能是取代 PHP 還要去 連線 MEMCACHE 的方式.

讓 SESSION 的處理 大大的降低 MEMECAHE 或 FILE IO 的 使用率.

原本舊的方法是

CLIENT  <---->  NGINX(APACHE) <---> PHP-FPM <---> 你寫的 AP 程式 <---> MEMCACHE

平均每秒一個 CONNECT 只 可以處理 1600 次. ( 原因是 MEMCACHE 跟 PHP 的溝通還是停留在短連結 , 而且溝通太多層 , 併發測試 會高上很多但是 純碎的效能要看單一 CONNECT 的次數喔. )

很浪費效能和頻寬.


新架構的想法 :

CLIENT <----> NGINX ( PLUGING ) <----> PHP-FPM ( PLUGING )  <--- PHP , 直接搖控 PHP-FPM 的存取內容
                                                   |             |
                                                   |             |
                                                   |             |
                                         ( DIY SESSION SERVER )                   


效能預計應該可以 比 傳統做法快.

要從二個地方下手 -

1. PHP-FPM 或 NGINX:

http://php-fpm.org/

2. PHP-EXTTENSION :

http://pecl.php.net/


這支元件我主要是利用 C++ 的 關聯式容器 MAP , 跟 ITERTOR 來實作.


這裡是核心處理的 CODE .

class session{
public:
        //virtual ~user() {}
        bool addSid(int uid, std::string &sid){
                gettimeofday(&time, 0);
                ret = usid.insert(pair<int,std::string>(uid,sid));
                utime.insert(pair<int,long int>(uid,time.tv_sec));
                if(ret.second == false){
                        return false ;
                }
                return true ;
        }
        int getSize(){
                return usid.size() ;
        }
        std::string getSid(int uid){
                if(usid.count(uid) > 0 ){
                        return usid.find(uid)->second;
                }
                return "0" ;
        }
        long int getSidTime(int uid){
                if(utime.count(uid) > 0 ){
                        return utime.find(uid)->second;
                }
                return 0 ;
        }
        void delSid(int uid){
                if(usid.count(uid) > 0 ){
                        usid.erase(uid);
                }
                if(utime.count(uid) > 0){
                        utime.erase(uid);
                }
        }
        void updateUtime(int uid){
                gettimeofday(&time, 0);
                utime[uid] = time.tv_sec ;
        }
        void updateUsid(int uid ,std::string sid){
                usid[uid] = sid ;
        }
        bool checkSid(int uid){
                if(uid != 0 ){
                        gettimeofday(&time, 0);
                        long int sessionTime = SESSION_TIME ;
                        long int thisTime = time.tv_sec ;
                        long int stime = getSidTime(uid);
                        if( (thisTime-sessionTime) > stime){
                                return false ;
                        }
                        return true ;
                }
                return false ;
        }

        std::string sid ;
        std::map<int,std::string> usid;
        std::map<int,long int> utime;
        std::map<int,std::string> ubid;
        std::map<int,std::string>::iterator it;
        std::pair<map<int,std::string>::iterator,bool> ret;
        timeval time;
private :
};


[root@FIEND wge_server]# ./test/session
test session       :
Connection : 10000 , use time : 0.104417
AVG : 95779 (Request/s)  <<< 很嚇人吧~每秒可以跑 九萬五千多次 SESSION 存取
AVG Toime : 1.044066E-05 (s/Request)


裝上這支~PHP 處理 SESSION 的部份 , 肯定飛起來~~~

不過我還要花時間研究怎麼利用 理想的放到 PHP-EXTENSION 或 NGINX  來跟 遠端的這個 容器做 長連結溝通.

這樣才有法子做到分散式架構....

還好新型態的 PHP 有支援 PHP-FPM 長時間運作的 DEAMON .



研究到下一階段再跟大家報告.~~





« 上次編輯: 2012-08-30 07:54 由 FIEND »
你累了嗎? 這樣不行 , 人要比 LINUX 兇 @@ " ......

FIEND

  • 鑽研的研究生
  • *****
  • 文章數: 700
    • 檢視個人資料
    • http://bbs.ecstart.com
比 PHP SESSION 使用 MEMCACHE 更有效率的做法
« 回覆 #1 於: 2012-08-30 07:51 »
修正了一些BUG~~

用 THREAD 還是 FORK 掛進去....

選擇用 FORK 就要開共用記憶體來丟...


繼續努力~~~


class user{
public:
        //virtual ~user() {}
        bool addSid(int uid, std::string &sid){
                gettimeofday(&time, 0);
                ret = usid.insert(pair<int,std::string>(uid,sid));
                utime.insert(pair<int,long int>(uid,time.tv_sec));
                if(ret.second == false){
                        return false ;
                }
                return true ;
        }
        int getSize(){
                return usid.size() ;
        }
        std::string getSid(int uid){
                if(usid.count(uid) > 0 ){
                        return usid.find(uid)->second;
                }
                return "0" ;
        }
        long int getSidTime(int uid){
                if(utime.count(uid) > 0 ){
                        return utime.find(uid)->second;
                }
                return 0 ;
        }
        void delSid(int uid){
                if(usid.count(uid) > 0 ){
                        usid.erase(uid);
                }
                if(utime.count(uid) > 0){
                        utime.erase(uid);
                }
        }
        void updateUtime(int uid){
                gettimeofday(&time, 0);
                if(utime.count(uid) > 0){
                        utime[uid] = time.tv_sec ;
                }
        }
        void updateUsid(int uid ,std::string &sid){
                if(utime.count(uid) > 0){
                        usid[uid] = sid ;
                }
        }
        bool checkSid(int uid){
                if(uid != 0 ){
                        gettimeofday(&time, 0);
                        long int sessionTime = SESSION_TIME ;
                        long int thisTime = time.tv_sec ;
                        long int stime = getSidTime(uid);
                        if( (thisTime-sessionTime) > stime){
                                return false ;
                        }
                        return true ;
                }
                return false ;
        }
        void clearExpired(){
                int count = 0  ;
                while(true){
                        count++ ;
                        usleep(10000000);
                        std::cout << "Clear Expired Session :  " << count << std::endl;

                        if(utime.empty()){
                                std::cout << "Session Size :  " << getSize() << std::endl;
                                for ( utit=utime.begin() ; utit != utime.end(); utit++ ){
                                        std::cout << (*utit).first << " => " << (*utit).second << std::endl;
                                }
                        }

                }
        }


        /*
        std::string sidFind(int uid){
                return usid.find(uid)->second;
        }
        */
        std::string sid ;
        std::map<int,std::string> usid;
        std::map<int,std::string>::iterator usit;
        std::map<int,long int> utime;
        std::map<int,long int>::iterator utit;
        std::map<int,std::string> ubid;
        std::pair<map<int,std::string>::iterator,bool> ret;
        timeval time;
private :
};

« 上次編輯: 2012-08-30 08:14 由 FIEND »
你累了嗎? 這樣不行 , 人要比 LINUX 兇 @@ " ......

ricky

  • 區域板主
  • 鑽研的研究生
  • *****
  • 文章數: 669
    • 檢視個人資料
    • Ricky 碎碎唸
 ??? php 跟 memcache access 有這麼慢嗎??
平常拿來當Cache處理,效能最少都有 10000 req/s 以上
1600會不會太誇張了。
瓶頸應該是卡在php-fpm的fcgi分發上吧...
我的symfony作品:YOMOpets 寵物誌
有興趣可以一起來討論symfony喔
我的部落格:http://ricky.ez2.us/

FIEND

  • 鑽研的研究生
  • *****
  • 文章數: 700
    • 檢視個人資料
    • http://bbs.ecstart.com
??? php 跟 memcache access 有這麼慢嗎??
平常拿來當Cache處理,效能最少都有 10000 req/s 以上
1600會不會太誇張了。
瓶頸應該是卡在php-fpm的fcgi分發上吧...

你誤會文意囉 , 這個 1600 指的不是 MC 的速度 , 指的是 MC 目前在~PHP 的架構上 走上 NGINX 後 , 所得到 單一個 來源 非併發的可消化數量.

己經很高了 , 平時有流量時應該低於一千 我試過丟到之前公司的服務上測 不到 600.

PHP-FPM 的影響其實沒那麼大~調的好單純只有~FPM 每秒可以到 六千左右~

####
原本舊的方法是

CLIENT  <---->  NGINX(APACHE) <---> PHP-FPM <---> 你寫的 AP 程式 <---> MEMCACHE

平均每秒一個 CONNECT 只 可以處理 1600 次. ( 原因是 MEMCACHE 跟 PHP 的溝通還是停留在短連結 , 而且溝通太多層 , 併發測試 會高上很多但是 純碎的效能要看單一 CONNECT 的次數喔. )  <<< 怕誤會有特別標明原因..
####

所以要想法子往前掛~~

########
新架構的想法 :

CLIENT <----> NGINX ( PLUGING ) <----> PHP-FPM ( PLUGING )  <--- PHP , 直接搖控 PHP-FPM 的存取內容
                                                   |             |
                                                   |             |
                                                   |             |
                                         ( DIY SESSION SERVER )               
########

而且要放棄短連線的做法.

如果沒有改~ULIMIT 會更低.

我在做實驗~~降低 TCP 連線的 LOADING~~~

讓 連線數減少 .

MC 直接在 COMMAND MODE 下 調完 作業系統的 網路參數 我測過最高可以跑到一萬六 ..

所以其實中間那個容器用 MC 也可以 , 但是PHP 跟 MC 之間 PHP元件沒有支援長連線的接口.

主要是它走 HTTP BASE 才會是這樣的架構.

( HTTP <--> PHP-FPM <-->PHP <--> MC ) , 所以它沒有設計長連結的方式 , 要另外中間再做一個 SERVER 來讓 PHP 直接讀取(保持連線). ( 以達到降低連線數的目地 )

如果能剋服這個問題 就可以加速很多.

實際上 MC 在底層夠快 但是一但走到中間的溝通就會降很多.

主軸是 :

1. PHP 怎麼跟 MC 間的 SCOEKT 做長連結接口
2. MC 怎麼直接透過建好的長連結讓 PHP 模組直接使用 , 而不是用 SOCKET 連線的方式來溝通.
3. MC 的 CODE 比較肥 , 所以我先做一個 暫時的容器來替代 MC 這樣實驗起來比較快.

如果說~先解決 SESSION 跟 MC , PHP 的連線問題 , 我想應該網路效能就可以節省很多.

這是我的原意~不好意思~表達不清楚~


#########

實際情況如果在 上百台的分散式架構下 會有更多問題.

個位數的伺服器 對這問題應該興趣會缺缺..

我會有這個想法是因為之前的公司之前花了 200萬 的冤枉錢 去買光纖背板.

就是因為工程師用了太多 MC 了.

之前的公司有五千多萬個會員 , 所以對這個連結數跟網路的消耗 很敏感~~ ^^

« 上次編輯: 2012-08-30 18:44 由 FIEND »
你累了嗎? 這樣不行 , 人要比 LINUX 兇 @@ " ......

FIEND

  • 鑽研的研究生
  • *****
  • 文章數: 700
    • 檢視個人資料
    • http://bbs.ecstart.com
今天無聊 , 又穿插了一個 自動 把 容器內容的 新增 修改 自動廣撥並且插入其它遠端的容器.

等到所有容器都倒滿才會回應新增修改的成功訊息.

然後再去使用 LINUX KERNEL 層的 SHM 元件 MMAP , 來備份及倒回容器.

達到 分散式存取和備份及ROLLBACK 的功能.

而 連結的接口 會有一個 Leader Server 來與 SERVER 做長連結的溝通.

測試起來 , 新增的速度隋然降低了一點點.

但是讀取的效能不變.

每秒與 PHP-FPM 背後自己DIY 開的一個後門程式 , 溝通的速度可以達到 18000 次.

看起來 PHP 在分散式快取上 , 應該還有很大的進步空間.

不過這方法 , 做成 元件庫 應該會有很多 需要 教育訓練還有網路知識要再加強的問題.

原方法 顯然會讓使用者易懂多了.



« 上次編輯: 2012-09-03 19:38 由 FIEND »
你累了嗎? 這樣不行 , 人要比 LINUX 兇 @@ " ......

炎之虛空

  • 可愛的小學生
  • *
  • 文章數: 5
  • 性別: 男
    • 檢視個人資料
但是這種方式僅限於實體主機比較好吧
用在虛擬主機難免會被台灣主機商停權
我很不習慣寫程式XD