简单的说明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