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

來查看當前的共享內存使用狀況。其中,各個部分解釋以下:服務器
key :共享內存的惟一的key值,共享內存經過該key來判斷你讀取的是哪一塊內存。網絡
shmid:當使用key來獲取內存時,你得到的是這個id的值。它做爲你操做內存塊的標識。架構
owner:建立該共享內存塊的用戶app
perms:該共享內存的讀寫權限,8禁止,能夠是777,與文件的讀寫權限一致。函數
bytes:該內存塊的大小ui
nattch:鏈接該內存塊的進程數
status:當前狀態,如:dest,即將刪除等。
使用示例
具體的使用說明,在PHP手冊中有詳細介紹,這裏不進行贅述。這裏將寫一些簡單的操做例子。
寫入
- <?php
- $key = 0x4337b700;
- $size = 4096;
- $shmid = @shmop_open($key, 'c', 0644, $size);
- if($shmid === FALSE){
- exit('shmop_open error!');
- }
-
- $data = '世界,你好!我將寫入不少的數據,你能罩得住麼?';
-
- $length = shmop_write($shmid, pack('a*',$data), 0);
- if($length === FALSE){
- exit('shmop_write error!');
- }
-
- @shmop_close($shmid);
-
- exit('succ');
- ?>
讀取
- <?php
- $key = 0x4337b700;
- $size = 256;
- $shmid = @shmop_open($key, 'c', 0644, $size);
- if($shmid === FALSE){
- exit('shmop_open error!');
- }
-
- $data = unpack('a*', shmop_read($shmid, 0, 256));
- if($data === FALSE){
- exit('shmop_read error!');
- }
- @shmop_close($shmid);
-
- exit($data[1]);
- ?>
這裏使用到了函數:pack() 這個函數用來將內存裏的內容轉化爲二進制內容,具體請查看手冊內容。
多服務器內存同步
已經在本地作好了這個服務,如今須要在多臺服務器上進行內存數據同步。雖然這個時候能夠放棄共享內存的方式來處理數據了,然而你被要求須要這麼作。因而,同步我想不是問題,作好「主-從」的架構,我同步好的內存及時推送過去就能夠了。然而,我是否是須要在從機上作一個監聽程序呢?這樣的代價有點大,好的一點是,從機上有apache。也就是說可使用HTTP協議來進行通訊了。
同步策略
如何同步?看似無聊的問題,卻又產生了疑惑。同步數據唄,可是同步什麼數據!一種方式是主機的內存改變後,程序讀取全部內存數據而後發送到從機進行同步;若是我只是更改一些簡單的操做位的話,那麼小的更新卻要引發整個內存塊的同步,彷佛有些浪費。還有一種,是更新變化。將變化進行更新。這種比較複雜,由於你須要定義每一種操做的處理。幸運的是,你須要操做的數據並很少,還有,你要定義的操做也很少:write,delete(read能夠不要,由於你不多會從從機上讀取數據)。那麼好了,咱們選擇其中一種來作吧。
主機發送
- <?php
-
- define('PSHMOP_HOST', '192.168.0.1');
- define('PSHMOP_SEPE', "\r\n----------CKSJFIOWKJDFOCKJVNBBSDF----------\r\n");
- class Pshmop
- {
- static private $data = array();
- static public function write($key, $offset, $data, $size = 0){
- $h = array('key' => $key, 'offset' => $offset, 'size' => $size, 'ac' => 'write');
- return self::add($h, $data);
- }
-
- static public function del($key){
- $h = array('key' => $key, 'ac' => 'delete');
- return self::add($h);
- }
-
- static private function add($dataheader, $databody=''){
- self::$data[] = serialize($dataheader)."\n".$databody;
- }
-
- static private function send(){
- $d = & self::$data;
- if(count($d) == 0){
- return ;
- }
- $http_entity_body = join(PSHMOP_SEPE, $d);
- $http_entity_length = strlen($http_entity_body);
- $fp = fsockopen(PSHMOP_HOST, 80, $errno, $error);
- if(!$fp){
- return -1;
- }
-
- fputs($fp, "PUT /pshmop.php HTTP/1.1\r\n");
- fputs($fp, 'Host: '.PSHMOP_HOST."\r\n");
- fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
- fputs($fp, "Content-Length: {$http_entity_length}\r\n");
- fputs($fp, "Connection: close\r\n\r\n");
- fputs($fp, $http_entity_body . "\r\n\r\n");
- $d = '';
- while(!feof($fp)){
- $d .= fgets($fp, 4096);
- }
- fclose($fp);
- return $d;
- }
- }
使用的時候,進行:
- Pshmop::write();
- Pshmop::write();
- Pshmop::write();
- Pshmop::send();
PS:爲了支持多個更新一次傳遞的原則,以上即是舉例。
從機監聽
- <?php
-
- define('RSHMOP_SEPE', "\r\n----------CKSJFIOWKJDFOCKJVNBBSDF----------\r\n");
- class Rshmop
- {
- static public function run($data){
- $items = @explode(RSHMOP_SEPE, $data);
- if($items === NULL){
- return -1;
- }
- $result = array('succ' => 0, 'error' => 0);
- foreach($items as $k => $i){
- self::op($i) === 0 ? $result['succ']++ : $result['error']++;
- unset($items[$k]);
- }
- return $result;
- }
- static public function op($str){
- $p = strpos($str, "\n");
- $header = @unserialize(substr($str, 0, $p));
- if($header === FALSE){
- return 'Data Format Error!';
- }
- $body = substr($str, $p+1);
- $shmid = null;
- if($header['size'] > 0){
- $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);
- }
- if(!$shmid){
- $cmd = "ipcs -m | grep '{$header['key']}'";
- $em = exec($cmd);
- $em = preg_replace('/ +/', ' ', $em);
- $ems = explode(' ', $em);
- $header['size'] = intval($ems[4]);
- if($header['size'] == 0){
- if($headerreturn ['ac'] == 'delete'){
- return 0;
- }else{
- return 'Param `size` required!';
- }
- }
- $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);
- }
- if($header['ac'] == 'write'){
- shmop_write($shmid, $body, $header['offset']);
- }
- if($header['ac'] == 'delete'){
- shmop_delete($shmid);
- }
- shmop_close($shmid);
- return 0;
- }
- }
若是遇到主機有而從機未有的數據塊(可能由網絡問題形成,也能夠有其它解決辦法),能夠選擇delete而後再進行其它操做。
緩存使用的策略
以爲使用MC代價有點高,能夠本身來控制內存和使用。固然,小部分的數據能夠容易使用,可是當數據多的時候,決定哪部分數據進入內存,哪部分數據進入硬盤都是值得商榷的。這也就是爲何要提策略。
常見的策略無非是 FIFO,LUR,LAR等,但並非說這些策略就是好的。實際狀況中,根據具體的業務需求,來組織相應的策略。最多見的,咱們是將從數據庫查詢時間長的、獲取數據耗時(從其它機器上獲取)、計算耗時的、須要及時使用的放入內存中。
這部分的代碼就不寫了,但願有所幫助。
轉載自:http://tubaluer.iteye.com/blog/1349797 做者 tubaluer