1. 程式人生 > >原創 Memcache分組和同步機制的實現

原創 Memcache分組和同步機制的實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

 

[原創] Memcache分組和同步機制的實現

作者:heiyeluren
部落格:
http://blog.csdn.net/heiyeshuwu
時間:2007-06-25


【Memcache同步類的實現思想】

首先我們明確瞭解就是Memcache是一個簡單、快速、高效的分散式基於記憶體的快取工具,一般用於網站等資料庫資料快取、高速交換資訊的快取,比如Session資料等等。Memcache最主要的特點就是兩個:一是它是基於記憶體的高效Hash類快取方式,二是使用了LUR演算法來進行資料有效期控制,這兩點就能夠很好的滿足我們的普通網站的應用。(關於Memcache的使用和協議請參考我的另一篇文章:《Memcache的使用和協議分析詳解http://blog.csdn.net/heiyeshuwu/archive/2006/11/13/1380838.aspx

Memcache本身也存在一些不足,不能說是不足,至少是為了滿足它高效的存取,所以沒有去實現的功能,包括:一是本身沒有內建分散式功能,無法實現使用多臺Memcache伺服器來儲存不同的資料,最大程度的使用相同的資源;二是無法同步資料,容易造成單點故障。

那麼其實都可以通過我們的Memcache的客戶端程式來解決的,首先我們PHP的PECL中的Memcache擴充套件能夠有效的解決Memcache的分散式問題,主要的介面就是 addServer() 函式,具體關於addServer()函式的實現可以參考該擴充套件原始碼。那麼現在就存在第二個問題,就是說無法同步資料,可以理解為MySQL中Master/Slave的機制,就是說如果我們有多臺的Memcache伺服器,使用addServer函式的話,每個伺服器儲存的資料都是唯一的,那麼任何一臺伺服器宕機的話,那麼這臺伺服器上的儲存資料將丟失無法訪問,這樣肯定是無法充分發揮我們Memcache威力的,那麼我們就需要一個方式來解決這個問題,這個就是本文主要要探討解決的問題:關於在多臺Memcache伺服器中分組和同步資料的問題。

針對這個問題我構建了一個PHP寫的Class,大致的思想就是把多臺Memcache伺服器分成兩組,每組的伺服器數量可能是一樣的(如果總數是複數的話),數量不一樣也沒關係,寫資料的時候往兩組伺服器都寫,資料是一樣的,那麼A組伺服器的資料和B組伺服器的資料是一樣的,如果A組伺服器中某一臺機器宕機了,則能夠從B組伺服器中提取出資料來,這樣能夠有效的避免單點故障,特別是在高效能要求的網站當中。當然,相應的操作也是有開銷的,主要的開銷在於網路連線,就是說連線到A組伺服器中發現沒有資料,則去訪問B組伺服器。另外還有就是在訪問資料過程中,都是從A組開始的,那麼併發量很高的情況下,A組伺服器的壓力比較大,那麼我還實現了對A組和B組伺服器隨機訪問的機制,如果在隨機的組中沒有發現數據則訪問另外一個組,這樣A組和B組的壓力就是1/2了,能夠有效的面對高負載的情況。

同樣的,這個類是可以擴充套件的,比如你可以修改成為能夠滿足兩組以上的伺服器,但是這樣邏輯會更復雜,我基於簡便期間,目前就考慮了兩組伺服器的情況,畢竟一般公司來說,沒有很多機器去做Memcache的快取,所以兩組已經能夠滿足大部分要求了。

PS:如果有興趣的話,可以完全自己重新實現Memcache的addServer擴充套件,比如增加addGroup之類的方法,能夠更有效的解決同步和分組的問題。同樣的,如果想節省資源的使用,可以把Memcached當作執行緒的方式來執行。


【Memcache同步類的實現程式碼】

本類經過我大致的各種測試,執行還算穩定,當然,使用時還是請多加註意。

 

<? php
/* *
 * Memcache 操作類 (支援同步和分組訪問)
 * 
 * author     : heiyeluren <http://blog.csdn.net/heiyeshuwu>
 * created    : 2007-06-21
 * lastModifed: 2007-06-21
 
*/

/* *
 * Memcache操作類
 
*/
class  MemcacheOpt
{
    
// ---------------------
    //  屬性定義
    //---------------------

   
    
/* *
     * 是否進行多組同步 
     
*/
    
var   $isGroup      =   true ;
    
    
/* *
     * 多組同步情況下是否使用減輕負載的隨機存取 
     
*/
    
var   $isRandom     =   true ;

    
/* *
     * 預設的Memcache伺服器埠 
     
*/
    
var   $mmcPort      =   11211 ;

    
/* *
     * 儲存原始組資訊
     
*/
    
var   $groups       =   array ();

    
/* *
     * 儲存第一、二組Memcache伺服器資訊
     
*/
    
var   $group1       =   array ();
    
var   $group2       =   array ();
    
    
/* *
     * 儲存第一、二組連線物件
     
*/
    
var   $mmc1         =   ''
    
var   $mmc2         =   ''
    

    
// ---------------------
    //   內部操作方法
    //---------------------


    
/* *
     * 顯示錯誤資訊
     *
     * @param string $msg 需要顯示訊息的內容
     * @param string $type 訊息型別,error是普通錯誤訊息,fatal 是致命錯誤,將終止程式執行, message 是普通訊息,預設狀


     * @return bool true
     
*/
    
function  showMessage( $msg ,   $type ){
        
$msg   .=   " " ;
        
switch ( $type ){
            
case   ' error ' :
                
echo ( " Memcache Error:  " .   $msg );
                
break ;
            
case   ' fatal ' :
                
die ( " Memcache Fatal:  " .   $msg );
                
break ;
            
case   ' message ' :
                
echo ( " Memcache Message:  " .   $msg );
                
break ;
            
default :
                
echo ( " Memcache Error:  " .   $msg );
        }
        
return   true ;
    }


    
/* *
     * 建構函式 (初始化分組和連線到伺服器)
     
*/
    
function  MemcacheOpt( $hostArray ,   $hostArray2 = array ()){
        
if  ( ! is_array ( $hostArray ||   empty ( $hostArray )){
            
$this -> showMessage( ' Memcache host list invalid ' ,   ' fatal ' );
        }
        
$this -> groups  =   array_merge ( $hostArray ,   $hostArray2 );
        
$this -> splitGroup( $hostArray ,   $hostArray2 );
        
$this -> connect();
    }

    
/* *
     * 對組進行切分 (按照是否需要分組進行相應的切分)
     *
     * @param array $hostArray 主機陣列列表1
     * @param array $hostArray2 主機陣列列表2
     * @return void
     
*/
    
function  splitGroup( $hostArray ,   $hostArray2 = array ()){
        
// 如果只有一臺機器則不使用分組
         if  ( count ( $hostArray <   2   &&   empty ( $hostArray2 )){
            
$this -> isGroup  =   false ;
        }

        
// 使用分組
         if  ( $this -> isGroup){
            
if  ( is_array ( $hostArray2 &&   ! empty ( $hostArray2 )){
                
$this -> group1  =   $hostArray ;
                
$this -> group2  =   $hostArray2 ;
            }
else {
                
$count   =   ceil ( count ( $hostArray /   2 );
                
$this -> group1  =   array_splice ( $hostArray ,   0 ,   $count );
                
$this -> group2  =   array_splice ( $hostArray ,   0 );
            }
        }
else {
            
$this -> group1  =   $hostArray
        } 
    }

    
/* *
     * 連線到Memcache伺服器
     
*/
    
function  connect(){
        
if  ( ! is_array ( $this -> group1)  ||   empty ( $this -> group1)){
            
$this -> showMessage( " Memcache host1 array invalid " ,   ' error ' );
            
return   false ;
        }

        
// 連線第一組Memcache伺服器
         $this -> mmc1  =   new  Memcache;
        
foreach ( $this -> group1  as   $hosts ){
            
$tmp   =   explode ( " : " ,   $hosts );
            
$host   =   $tmp [ 0 ];
            
$port   =  ( ! isset ( $tmp [ 1 ])  ||   $tmp [ 1 ] == '' ?   $this -> mmcPort  :   $tmp [ 1 ];
            
$this -> mmc1 -> addServer( $host ,   $port );
        }

        
// 如果需要分組則連線第二組Memcache伺服器
         if  ( $this -> isGroup){
            
if  (  ! is_array ( $this -> group2)  ||   empty ( $this -> group2) ){
                
$this -> showMessage( " Memcache host2 array invalid " ,   ' error ' );
                
return   false ;
            }
            
$this -> mmc2  =   new  Memcache;
            
foreach ( $this -> group2  as   $hosts ){
                
$tmp   =   explode ( " : " ,   $hosts );
                
$host   =   $tmp [ 0 ];
                
$port   =  ( ! isset ( $tmp [ 1 ])  ||   $tmp [ 1 ] == '' ?   $this -> mmcPort  :   $tmp [ 1 ];
                
$this -> mmc2 -> addServer( $host ,   $port );
            }
        }
    }

    
/* *
     * 關閉Memcache伺服器連線
     
*/
    
function  close(){
        
if  ( is_object ( $this -> mmc1)){
            
$this -> mmc1 -> close();
        }
        
if  ( is_object ( $this -> mmc1)){
            
$this -> mmc1 -> close();
        }        
        
return   true ;
    }

    
/* *
     * 資料操作核心函式
     *
     * @param string $optType 操作型別,主要有 add, set, replace, delete, flush
     * @param string $key 關鍵字,如果是 add,set,replace,delete 需要提交key引數
     * @param string $val 關鍵字對應的值,如果是 add, set,replace 需要提交value引數
     * @param int $expire 資料有效期,如果是 add,set,replace需要提交expire引數
     * @return mixed 不同的需要產生不同的返回
     
*/
    
function  opt( $optType ,   $key = '' ,   $val = '' ,   $expire = '' ){
        
if  ( ! is_object ( $this -> mmc1)){
            
$this -> showMessage( " Not availability memcache connection object " ,   ' fatal ' );
        }
        
if  ( $this -> isGroup  &&   ! is_object ( $this -> mmc2)){
            
$this -> showMessage( " Group 2 memcache host connection object not availability " ,   ' error ' );
        }

        
// 加入資料操作
         if  ( $optType == ' add '   ||   $optType == ' set '   ||   $optType == ' replace ' ){
            
$this -> mmc1 -> set( $key ,   $val ,   false ,   $expire );
            
if  ( $this -> isGroup  &&   is_object ( $this -> mmc2)){
                
$this -> mmc2 -> set( $key ,   $val ,   false ,   $expire );
            }
            
return   true ;
        }

        
// 獲取資料操作
         if  ( $optType   ==   ' get ' ){

            
// 預設獲取第一組資料
             if  ( ! $this -> isGroup  ||   ! is_object ( $this -> mmc2)){
                
return   $this -> mmc1 -> get( $key );        
            }

            
// 分組情況下逐組訪問
             $num   =  (  $this -> isRandom  ?   rand ( 1 ,   2 :   1  );
            
$obj   =   " mmc " .   $num ;
            
$val   =   $this -> $obj -> get( $key );

            
// 如果沒有提取到資料,則訪問另外一組
             if  ( $val   ==   "" ){
                
switch ( $num ){
                    
case   1 :   $val   =   $this -> mmc2 -> get( $key );  break ;
                    
case   2 :   $val   =   $this -> mmc1 -> get( $key );  break ;
                    
default :   $val   =   $this -> mmc1 -> get( $key );
                }
            }
            
return   $val ;
        }

        
// 刪除資料操作
         if  ( $optType   ==   ' delete ' ){
            
$this -> mmc1 -> delete( $key ,   $expire );
            
if  ( $this -> isGroup  &&   is_object ( $this -> mmc2)){
                
$this -> mmc2 -> delete( $key );        
            }
            
return   true ;
        }

        
// 清空資料操作     
         if ( $optType   ==   ' flush ' ){
            
$this -> mmc1 -> flush ();
            
if  ( $this -> isGroup  &&   is_object ( $this -> mmc2)){
                
$this -> mmc2 -> flush ();        
            }
            
return   true ;
        }
        
    }


    
// ---------------------
    //   外部操作方法
    //---------------------

    //增加一個元素

     function  add( $key ,   $val ,   $expire = '' ){
       
return   $this -> opt( ' add ' ,   $key ,   $val ,   $expire ); 
    }

    
// 增加一個元素
     function  set( $key ,   $val ,   $expire = '' ){
        
return   $this -> opt( ' set ' ,   $key ,   $val ,   $expire );
    }

    
// 替換一個元素
     function  replace( $key ,   $val ,   $expire = '' ){
        
return   $this -> opt( ' replace ' ,   $val ,   $expire );
    }

    
// 獲取一個元素
     function  get( $key ){
        
return   $this -> opt( ' get ' ,   $key );
    }

    
// 刪除一個元素
     function  delete( $key ,   $timeout = '' ){
        
return   $this -> opt( ' delete ' ,   $key ,   '' ,   $timeout );
    }

    
// 讓所有的元素過期 (本介面不要輕易使用)
     function   flush (){
       
return   $this -> opt( ' flush ' ); 
    }


    
/* *
     * 獲取所有Memcache伺服器狀態
     
*/
    
function  getStats(){
        
$status   =   array ();

        
// 單獨連線到每臺Memcache
         foreach ( $this -> groups  as   $key => $hosts ){
            
$tmp   =   explode ( " : " ,   $hosts );
            
$host   =   $tmp [ 0 ];
            
$port   =  ( ! isset ( $tmp [ 1 ])  ||   $tmp [ 1 ] == '' ?   $this -> mmcPort  :   $tmp [ 1 ];

            
$conn   =   new  Memcache;
            
$conn -> connect( $host ,   $port );
            
$s   =   $conn -> getStats();
            
$s [ ' host ' =   $host ;
            
$s [ ' port ' =   $port ;
            
$status [ $key =   $s ;
        }
        
return   $status ;
    }

    
/* *
     * 獲取所有Memcache伺服器版本號
     
*/
    
function  getVersion(){
        
$version   =   array ();
        
$stats   =   $this -> getStats();
        
foreach ( $stats   as   $key => $s ){
            
$v [ ' host ' =   $s [ ' host ' ];
            
$v [ ' port ' =   $s [ ' port ' ];
            
$v [ ' version ' =   $s [ ' version ' ];
            
$version [ $key =   $v ;
        }
        
return   $version ;
    }

}
?>

 

 【Memcache同步類的測試】

在本機開啟多個Memcache守護程序:

[ ~ ] $ ps auxww | grep memcached
heiyeluren  
98466    0.0    0.2    6088   5676   ??  SsJ    7 :50下午    0 : 00.04  /usr/local/memcache/bin/memcached -d -m  32  -l  10.62.240.9  -p  11214
heiyeluren  
98437    0.0    0.2    6088   5676   ??  SsJ    7 :50下午    0 : 00.04  /usr/local/memcache/bin/memcached -d -m  32  -l  10.62.240.9  -p  11213
heiyeluren  
98425    0.0    0.2    6088   5676   ??  SsJ    7 :50下午    0 : 00.05  /usr/local/memcache/bin/memcached -d -m  32  -l  10.62.240.9  -p  11212
heiyeluren  
98228    0.0    0.2    6088   5676   ??  SsJ    7 :48下午    0 : 00.05  /usr/local/memcache/bin/memcached -d -m  32  -l  10.62.240.9  -p  11211


MemcacheOpt類測試程式碼:

 

<? php
require_once ( " MemcacheOpt.class.php " );

// 操作程式碼
$hostArray   =   array ( " 10.62.240.9 " ,   " 10.62.240.9:11212 " ,   " 10.62.240.9:11213 " ,   " 10.62.240.9:11214 " );
$m   =   new  MemcacheOpt( $hostArray );

$m -> add( " key1 " ,   " key1_value " ,   30 );
$m -> add( " key2 " ,   " key2_value " ,   30 );
$m -> set( " key3 " ,   " key3_value " ,   30 );
$m -> set( " key4 " ,   " key4)value " ,   30 );

echo   $m -> get( " key1 " ) .   " " ;
echo   $m -> get( " key2 " ) .   " " ;
echo   $m -> get( " key3 " ) .   " " ;
echo   $m -> get( " key4 " ) .   " " ;

print_r (

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述