PHP共享內存的應用shmop系列

簡單的說明php

可能不多狀況會使用PHP來操控共享內存,一方面在內存的控制上,MC已經提供了一套很好的方式,另外一方面,本身來操控內存的難度較大,內存的讀寫與轉存,包括後面可能會用到的存儲策略,要是沒有必定計算機組成原理的基礎,想作這些不是一件容易的事情。那爲何還要使用它呢?若是我想進行管道通訊,爲其它的應用服務準備數據;我想創建本身的數據緩存體系,使用MC有點大炮打蒼蠅的感受。那麼shmop會是一個選擇,固然,在操做內存前,必定要謹慎。數據庫

系統要求apache

shmop系列函數只是在unix/Linux下可用,能夠經過命令:緩存

 

Plain代碼 
  1. ipcs -m  


 

來查看當前的共享內存使用狀況。其中,各個部分解釋以下:服務器

key :共享內存的惟一的key值,共享內存經過該key來判斷你讀取的是哪一塊內存。網絡

shmid:當使用key來獲取內存時,你得到的是這個id的值。它做爲你操做內存塊的標識。架構

owner:建立該共享內存塊的用戶app

perms:該共享內存的讀寫權限,8禁止,能夠是777,與文件的讀寫權限一致。函數

bytes:該內存塊的大小ui

nattch:鏈接該內存塊的進程數

status:當前狀態,如:dest,即將刪除等。

使用示例

具體的使用說明,在PHP手冊中有詳細介紹,這裏不進行贅述。這裏將寫一些簡單的操做例子。

寫入

 

Php代碼 
  1. <?php  
  2. /** 
  3.   * SHMOP共享內存操做示例 
  4.   * @author monkee 
  5.  **/  
  6. $key = 0x4337b700;  
  7. $size = 4096;  
  8. $shmid = @shmop_open($key, 'c', 0644, $size);  
  9. if($shmid === FALSE){  
  10.     exit('shmop_open error!');  
  11. }  
  12.   
  13. $data = '世界,你好!我將寫入不少的數據,你能罩得住麼?';  
  14.   
  15. $length = shmop_write($shmid, pack('a*',$data), 0);  
  16. if($length === FALSE){  
  17.     exit('shmop_write error!');  
  18. }  
  19.   
  20. @shmop_close($shmid);  
  21.   
  22. exit('succ');  
  23. ?>  

 

 

讀取

 

Php代碼 
  1. <?php  
  2. /** 
  3.   * SHMOP共享內存操做示例 
  4.   * @author monkee 
  5.  **/  
  6. $key = 0x4337b700;  
  7. $size = 256;  
  8. $shmid = @shmop_open($key, 'c', 0644, $size);  
  9. if($shmid === FALSE){  
  10.     exit('shmop_open error!');  
  11. }  
  12.   
  13. $data = unpack('a*', shmop_read($shmid, 0, 256));  
  14. if($data === FALSE){  
  15.     exit('shmop_read error!');  
  16. }  
  17. @shmop_close($shmid);  
  18.   
  19. exit($data[1]);  
  20. ?>  


這裏使用到了函數:pack() 這個函數用來將內存裏的內容轉化爲二進制內容,具體請查看手冊內容。

 

多服務器內存同步

已經在本地作好了這個服務,如今須要在多臺服務器上進行內存數據同步。雖然這個時候能夠放棄共享內存的方式來處理數據了,然而你被要求須要這麼作。因而,同步我想不是問題,作好「主-從」的架構,我同步好的內存及時推送過去就能夠了。然而,我是否是須要在從機上作一個監聽程序呢?這樣的代價有點大,好的一點是,從機上有apache。也就是說可使用HTTP協議來進行通訊了。

同步策略

如何同步?看似無聊的問題,卻又產生了疑惑。同步數據唄,可是同步什麼數據!一種方式是主機的內存改變後,程序讀取全部內存數據而後發送到從機進行同步;若是我只是更改一些簡單的操做位的話,那麼小的更新卻要引發整個內存塊的同步,彷佛有些浪費。還有一種,是更新變化。將變化進行更新。這種比較複雜,由於你須要定義每一種操做的處理。幸運的是,你須要操做的數據並很少,還有,你要定義的操做也很少:write,delete(read能夠不要,由於你不多會從從機上讀取數據)。那麼好了,咱們選擇其中一種來作吧。

主機發送

 

Php代碼 
  1. <?php  
  2.   
  3. /**  
  4.   * 共享內存操做,支持遠程內存同步。 
  5.   * @author hufeng@ 
  6.   * @since 2011-08-10 
  7.   * 
  8.   */  
  9. define('PSHMOP_HOST', '192.168.0.1');   
  10. define('PSHMOP_SEPE', "\r\n----------CKSJFIOWKJDFOCKJVNBBSDF----------\r\n");  
  11. class Pshmop   
  12. {  
  13.     static private $data = array();  
  14.     static public function write($key, $offset, $data, $size = 0){   
  15.         $h = array('key' => $key, 'offset' => $offset, 'size' => $size, 'ac' => 'write');   
  16.         return self::add($h, $data);   
  17.     }   
  18.        
  19.     static public function del($key){   
  20.         $h = array('key' => $key, 'ac' => 'delete');   
  21.         return self::add($h);   
  22.     }  
  23.   
  24.     static private function add($dataheader, $databody=''){  
  25.         self::$data[] = serialize($dataheader)."\n".$databody;   
  26.     }  
  27.    
  28.     static private function send(){   
  29.         $d = & self::$data;  
  30.         if(count($d) == 0){  
  31.             return ;   
  32.         }  
  33.         $http_entity_body = join(PSHMOP_SEPE, $d);  
  34.         $http_entity_length = strlen($http_entity_body);  
  35.         $fp = fsockopen(PSHMOP_HOST, 80, $errno, $error);   
  36.         if(!$fp){   
  37.             return -1;   
  38.         }   
  39.   
  40.         fputs($fp, "PUT /pshmop.php HTTP/1.1\r\n");   
  41.         fputs($fp, 'Host: '.PSHMOP_HOST."\r\n");   
  42.         fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");   
  43.         fputs($fp, "Content-Length: {$http_entity_length}\r\n");   
  44.         fputs($fp, "Connection: close\r\n\r\n");   
  45.         fputs($fp, $http_entity_body . "\r\n\r\n");   
  46.         $d = '';   
  47.         while(!feof($fp)){   
  48.             $d .= fgets($fp, 4096);   
  49.         }   
  50.         fclose($fp);   
  51.         return $d;   
  52.     }   
  53. }   


使用的時候,進行:

 

 

Php代碼 
  1. Pshmop::write();  
  2. Pshmop::write();  
  3. Pshmop::write();  
  4. Pshmop::send();  


PS:爲了支持多個更新一次傳遞的原則,以上即是舉例。

 

從機監聽

 

Php代碼 
  1. <?php  
  2.   
  3. /** 
  4.   * 共享內存遠程處理類 
  5.   * 對從遠端傳輸到的數據進行處理、內存同步更新 
  6.   * @author hufeng@ 
  7.   * @since 2011-08-11 
  8.   **/  
  9. define('RSHMOP_SEPE', "\r\n----------CKSJFIOWKJDFOCKJVNBBSDF----------\r\n");  
  10. class Rshmop  
  11. {  
  12.     static public function run($data){  
  13.         $items = @explode(RSHMOP_SEPE, $data);  
  14.         if($items === NULL){  
  15.             return -1;  
  16.         }  
  17.         $result = array('succ' => 0, 'error' => 0);  
  18.         foreach($items as $k => $i){  
  19.             self::op($i) === 0 ? $result['succ']++ : $result['error']++;  
  20.             unset($items[$k]);  
  21.         }  
  22.         return $result;  
  23.     }  
  24.     static public function op($str){  
  25.         $p = strpos($str, "\n");  
  26.         $header = @unserialize(substr($str, 0, $p));  
  27.         if($header === FALSE){  
  28.             return 'Data Format Error!';  
  29.         }  
  30.         $body = substr($str, $p+1);  
  31.         $shmid = null;  
  32.         if($header['size'] > 0){  
  33.             $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);  
  34.         }  
  35.         if(!$shmid){  
  36.             $cmd = "ipcs -m | grep '{$header['key']}'";  
  37.             $em = exec($cmd);  
  38.             $em = preg_replace('/ +/', ' ', $em);  
  39.             $ems = explode(' ', $em);  
  40.             $header['size'] = intval($ems[4]);  
  41.             if($header['size'] == 0){  
  42.                 if($headerreturn ['ac'] == 'delete'){  
  43.                     return 0;  
  44.                 }else{  
  45.                     return 'Param `size` required!';  
  46.                 }  
  47.             }  
  48.             $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);  
  49.         }  
  50.         if($header['ac'] == 'write'){  
  51.             shmop_write($shmid, $body, $header['offset']);  
  52.         }  
  53.         if($header['ac'] == 'delete'){  
  54.             shmop_delete($shmid);  
  55.         }  
  56.         shmop_close($shmid);  
  57.         return 0;  
  58.     }  
  59. }  


若是遇到主機有而從機未有的數據塊(可能由網絡問題形成,也能夠有其它解決辦法),能夠選擇delete而後再進行其它操做。

 

緩存使用的策略

以爲使用MC代價有點高,能夠本身來控制內存和使用。固然,小部分的數據能夠容易使用,可是當數據多的時候,決定哪部分數據進入內存,哪部分數據進入硬盤都是值得商榷的。這也就是爲何要提策略。

常見的策略無非是 FIFO,LUR,LAR等,但並非說這些策略就是好的。實際狀況中,根據具體的業務需求,來組織相應的策略。最多見的,咱們是將從數據庫查詢時間長的、獲取數據耗時(從其它機器上獲取)、計算耗時的、須要及時使用的放入內存中。

這部分的代碼就不寫了,但願有所幫助。

 

轉載自:http://tubaluer.iteye.com/blog/1349797 做者 tubaluer

相關文章
相關標籤/搜索