使用redis模擬memcach多伺服器承載

fiona8953發表於2014-08-27


如題分享一老外實現思路,拋開redis自身配置主從外模擬memcache中hash多伺服器承載

原文

作者思路不錯,大家可以借鑑

點選(此處)摺疊或開啟

  1. php
  2. /**
  3. * Redisent, a Redis interface for the modest
  4. * @author Justin Poliey
  5. * @copyright 2009 Justin Poliey
  6. * @license php The MIT License
  7. * @package Redisent
  8. */

  9. require \'redisent.php\';

  10. /**
  11. * A generalized Redisent interface for a cluster of Redis servers
  12. */
  13. class RedisentCluster {

  14.         /**
  15.          * Collection of Redisent objects attached to Redis servers
  16.          * @var array
  17.          * @access private
  18.          */
  19.         private $redisents;

  20.         /**
  21.          * Aliases of Redisent objects attached to Redis servers, used to route commands to specific servers
  22.          * @see RedisentCluster::to
  23.          * @var array
  24.          * @access private
  25.          */
  26.         private $aliases;

  27.         /**
  28.          * Hash ring of Redis server nodes
  29.          * @var array
  30.          * @access private
  31.          */
  32.         private $ring;

  33.         /**
  34.          * Individual nodes of pointers to Redis servers on the hash ring
  35.          * @var array
  36.          * @access private
  37.          */
  38.         private $nodes;

  39.         /**
  40.          * Number of replicas of each node to make around the hash ring
  41.          * @var integer
  42.          * @access private
  43.          */
  44.         private $replicas = 128;

  45.         /*** 特殊方法預設到特定連線
  46.          * The commands that are not subject to hashing
  47.          * @var array
  48.          * @access private
  49.          */
  50.         private $dont_hash = array(
  51.                 \'RANDOMKEY\', \'DBSIZE\',
  52.                 \'SELECT\', \'MOVE\', \'FLUSHDB\', \'FLUSHALL\',
  53.                 \'SAVE\', \'BGSAVE\', \'LASTSAVE\', \'SHUTDOWN\',
  54.                 \'INFO\', \'MONITOR\', \'SLAVEOF\'
  55.         );

  56.         /**
  57.          * Creates a Redisent interface to a cluster of Redis servers
  58.          * @param array $servers The Redis servers in the cluster. Each server should be in the format array(\'host\' => hostname, \'port\' => port)
  59.          */
  60.         function __construct($servers) {
  61.                 $this->ring = array();
  62.                 $this->aliases = array();
  63.                 foreach ($servers as $alias => $server) {
  64.                         $this->redisents[] = new Redisent($server[\'host\'], $server[\'port\']);
  65.                         if (is_string($alias)) {
  66.                                 $this->aliases[$alias] = $this->redisents[count($this->redisents)-1];
  67.                         }
  68.                         for ($replica = 1; $replica <= $this->replicas; $replica++) {
  69.                                 $this->ring[crc32($server[\'host\'].\':\'.$server[\'port\'].\'-\'.$replica)] = $this->redisents[count($this->redisents)-1];
  70.                         }
  71.                 }
  72.                 ksort($this->ring, SORT_NUMERIC);
  73.                 $this->nodes = array_keys($this->ring);
  74.         }

  75.         /**
  76.          * Routes a command to a specific Redis server aliased by {$alias}.
  77.          * @param string $alias The alias of the Redis server
  78.          * @return Redisent The Redisent object attached to the Redis server
  79.          */
  80.         function to($alias) {
  81.                 if (isset($this->aliases[$alias])) {
  82.                         return $this->aliases[$alias];
  83.                 }
  84.                 else {
  85.                         throw new Exception(\"That Redisent alias does not exist\");
  86.                 }
  87.         }

  88.         /* Execute a Redis command on the cluster */
  89.         function __call($name, $args) {

  90.                 /* Pick a server node to send the command to */
  91.                 $name = strtoupper($name);
  92.                 if (!in_array($name, $this->dont_hash)) {
  93.                         $node = $this->nextNode(crc32($args[0]));
  94.                         $redisent = $this->ring[$node];
  95.             }
  96.             else {
  97.                         $redisent = $this->redisents[0];
  98.             }

  99.                 /* Execute the command on the server */
  100.             return call_user_func_array(array($redisent, $name), $args);
  101.         }

  102.         /*** 2分法查詢
  103.          * Routes to the proper server node
  104.          * @param integer $needle The hash value of the Redis command
  105.          * @return Redisent The Redisent object associated with the hash
  106.          */
  107.         private function nextNode($needle) {
  108.                 $haystack = $this->nodes;
  109.                 while (count($haystack) > 2) {
  110.                         $try = floor(count($haystack) / 2);
  111.                         if ($haystack[$try] == $needle) {
  112.                                 return $needle;
  113.                         }
  114.                         if ($needle < $haystack[$try]) {
  115.                                 $haystack = array_slice($haystack, 0, $try + 1);
  116.                         }
  117.                         if ($needle > $haystack[$try]) {
  118.                                 $haystack = array_slice($haystack, $try + 1);
  119.                         }
  120.                 }
  121.                 return $haystack[count($haystack)-1];
  122.         }

  123. }


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26477398/viewspace-1258943/,如需轉載,請註明出處,否則將追究法律責任。

相關文章