php 实现memcached的分不化

2012年4月2日 发表评论 阅读评论

基本知识 http://tech.idv2.com/2008/07/24/memcached-004/

该函数库实现了分布式功能,是memcached标准的分布式方法。

根据余数计算分散

Memcached的分布式方法简单来说,就是“根据服务器台数的余数进行分散”。
求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。

下面将Memcached简化成以下的Perl脚本来进行说明。

use strict;
use warnings;
use String::CRC32;

my @nodes = (‘node1′,’node2′,’node3′);
my @keys = (‘tokyo’, ‘kanagawa’, ‘chiba’, ‘saitama’, ‘gunma’);

foreach my $key (@keys) {
my $crc = crc32($key); # CRC値
my $mod = $crc % ( $#nodes + 1 );
my $server = $nodes[ $mod ]; # 根据余数选择服务器
printf “%s => %s\n”, $key, $server;

}

根据余数计算分散的缺点

余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。
那就是当添加或移除服务器时,缓存重组的代价相当巨大。
添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,
从而影响缓存的命中率。用Perl写段代码来验证其代价。

Consistent Hashing的简单说明

Consistent Hashing如下所示:首先求出memcached服务器(节点)的哈希值,
并将其配置到0~232的圆(continuum)上。
然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。
然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。
如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。

php代码,自己写了下已调试

<?php
class MemcacheClass
{
  private $_mc = null;
  private $_mc_host = ”;
  private $_mc_port = ”;
  public function __construct($host=”,$port=”)
  {
    $this->_mc_host = $host;
    $this->_mc_port = $port;
  }

  public function connect($host, $port)
  {
    $_mc_host = empty($host)?$this->_mc_host:$host;
    $_mc_port = empty($port)?$this->_mc_port:$port;
    if(empty($_mc_host) || empty($_mc_port)) return false;
    $this->_mc = new MemCache;
    return $this->_mc->connect($_mc_host, $_mc_port);
  }

  public function __destruct()
  {
        $this->_mc = null;
  }

  public function get($key)
  {
    $res = “”;
    if($this->_mc)
    {
      $res = $this->_mc->get($key);
      return $res;
    }
    return $res;
  }

  public function set($key,$val,$expire=500)
  {
      $this->_mc->set($key, $val, 0, $expire);
  }
}

$m = MemcachedClass::getInstance();

for($i=0;$i<10;$i++)
{
    $m-> set_cache($i,$i);
    echo “<br>”;
}
echo $m->get_cache(0);
/*memcache 分布式缓冲机制
 采用Consistent Hashing 的算法
 说明:没有考虑,当其中的一台memcached服务器当掉数据处理的情况
 */
class MemcachedClass
{
    static $_mobjs = null; // 返回memcached 实例
    private $_mservers = array(‘<font color=red>memcachehost:11211</font>’); //分布服务器
    private $_mketama_points = 255; //分布服务器点数 最多可增加的服务器数
    static $_mhash_servers = null; //哈希后对应的服务器
    static $_mserver_points = 0; //服务器台数
    static protected $_instance = null;
    var $_error = true;
    private function __construct()
    {
        $this->calc_hash_server();
    }
    
     /**
      * 获得MemcachedClass类的全局唯一实例的唯一方法
      *
      * @return MemcachedClass
      */  
     static public function getInstance()  
     {  
         if(self::$_instance === null)  
         {  
             self::$_instance = new self();  
         }  
         return self::$_instance;  
     }  

    /*
     * 设置服务器
     * @param array or string $servers 格式:array(’192.168.0.1:11211′,’192.168.0.1:11212′) or 192.168.0.1:11211
     * @reuturn void
    */
    public function set_servers($servers)
    {
        if(empty($servers)) return false;
        if(is_array($servers)){
            $this->_mservers = $servers;
        }else{
            $this->_mservers = array($servers);
        }
    }

    /*
     * 添加服务器
     * @param string $server 192.168.0.1:11211
     * @return void
    */
    public function add_server($server)
    {
        if(empty($server)) return false;
        $this->_mservers[] = $server;
        $this->calc_hash_server();
    }

    /*
     * 获取服务器格式
     * return int A
    */
    public function get_server_points()
    {
        return $this->_mserver_points;
    }

    /*
     * 生成 0~255之间的哈希数
     * @param string $str 哈希前的字符串
     * @return int A
    */
    private function calc_hash($str){        
        $h = sprintf(“%u”, crc32($str));
        $h1 = intval($h / $this->_mketama_points);        
        $h2 = $h1 % $this->_mketama_points;
        return $h2;
    }
    
    /*
     * 把服务器(节点)映射到 0~255 的圆上
     * @return void
    */
    private function calc_hash_server(){
        $nser_count = count($this->_mservers);
        for($i = 0; $i < $nser_count; $i++){
            $this->_mhash_servers[$i] = $this->calc_hash($i);
        }
        asort($this->_mhash_servers,SORT_NUMERIC);
        $this->_mserver_points = $nser_count;
    }

    /*
     * 获取当前键值映射到的服务器序号
     * @param int $u 键值哈希后的数值
     * @return int A 返回服务器序号
    */
    private function get_server_id($u){
        if(!isset($u) || !is_int($u)) return false;    
        $ni = 0;
        $nk = 0;
        foreach($this->_mhash_servers as $key => $val){
            if($ni == 0) {
                $nk = $key;
                $ni++;
            }
            if($u <= $val) return $key;
        }
        return $nk;
    }

    /*
     * 获取服务器对象
     * @param string $key 存取键值
     * @return object A
    */
    private function router_server($key){
        $u = $this->calc_hash($key);
        $this->error_mgs($u);
        $nserver_id = $this->get_server_id($u);
        if(is_object($this->_mobjs[$nserver_id])){
            return $this->_mobjs[$nserver_id];
        }
        $server = $this->_mservers[$nserver_id];
        $this->error_mgs($server);
        $server = strip_tags($server,”);
        //获取memcached对象并返回
        $aserver = explode(‘:’,$server);
        $omem = new MemcacheClass();
        if($omem->connect($aserver[0],$aserver[1]))
            $this->_mobjs[$nserver_id] = $omem;
        else
            $this->_mobjs[$nserver_id] = null;
        
        return $this->_mobjs[$nserver_id];
    }

    /*
     * 设置内容
     * @param string $key 键
     * @param mixed $value 值
     * @param int $expire 60 存储时间 默认60s
     * @return void
    */
    public function set_cache($key,$value,$expire=60){
        if(!isset($key) || !isset($value)) return false;
        $obj_mem = $this->router_server($key);
        /*
        保存数据
        ……
        */
        $obj_mem->set($key,$value,$expire);
    }

    /*
     * 获取内容
     * @param string $key jian
     * @return mixed A
    */
    public function get_cache($key){
        if(!isset($key)) return false;
        $obj_mem = $this->router_server($key);
        /*
        获取数据
        ……
        */
        return $obj_mem->get($key);
    }

    private function error_mgs($str)
    {
        if($this->_error) echo $str,”|”;
    }

    public function __destruct()
    {
        
    }
}

?>


转载请注明来自:[MSN Spaces]http://msn.shandian.biz/149.html

  1. 本文目前尚无任何评论.