/** * 根据key获取redis实例 * 这边还是用取模的方式,一致性hash用php实现性能开销过大。取模的方式对只有几台机器的情况足够用了 * 如果有集群需要,直接使用redis3.0+自带的集群功能就好了。不管是可用性还是性能都比用php自己实现好 * * @param $key * * @return \Redis */ private function hash($key) { $success = sprintf('%u', crc32($key)) % count($this->conf['server']); if (!isset($this->redis[$success]) || !is_object($this->redis[$success])) { $instance = new \Redis(); if ($instance->pconnect($this->conf['server'][$success]['host'], $this->conf['server'][$success]['port'], 1.5)) { $this->redis[$success] = $instance; } else { \Cml\throwException(Lang::get('_CACHE_CONNECT_FAIL_', 'Redis', $this->conf['server'][$success]['host'] . ':' . $this->conf['server'][$success]['port'])); } if (isset($this->conf['server'][$success]['password']) && !empty($this->conf['server'][$success]['password'])) { $instance->auth($this->conf['server'][$success]['password']) || \Cml\throwException('redis password error!'); } } return $this->redis[$success]; }
/** * 根据key获取redis实例 * 这边还是用取模的方式,一致性hash用php实现性能开销过大。取模的方式对只有几台机器的情况足够用了 * 如果有集群需要,直接使用redis3.0+自带的集群功能就好了。不管是可用性还是性能都比用php自己实现好 * * @param $key * * @return \Redis */ private function hash($key) { $serverNum = count($this->conf['server']); $success = sprintf('%u', crc32($key)) % $serverNum; if (!isset($this->redis[$success]) || !is_object($this->redis[$success])) { $instance = new \Redis(); $connectToRedisFunction = function ($host, $port, $isPersistentConnect) use($instance) { if ($isPersistentConnect) { return $instance->pconnect($host, $port, 1.5); } else { return $instance->connect($host, $port, 1.5); } }; $isPersistentConnect = !(isset($this->conf['server'][$success]['pconnect']) && $this->conf['server'][$success]['pconnect'] === false); $connectResult = $connectToRedisFunction($this->conf['server'][$success]['host'], $this->conf['server'][$success]['port'], $isPersistentConnect); $failOver = null; if (!$connectResult && !empty($this->conf['back'])) { $failOver = $this->conf['back']; $isPersistentConnect = !(isset($failOver['pconnect']) && $failOver['pconnect'] === false); $connectResult = $connectToRedisFunction($failOver['host'], $failOver['port'], $isPersistentConnect); } if (!$connectResult && $serverNum > 1) { $failOver = $success + 1; $failOver >= $serverNum && ($failOver = $success - 1); $failOver = $this->conf['server'][$failOver]; $isPersistentConnect = !(isset($failOver['pconnect']) && $failOver['pconnect'] === false); $connectResult = $connectToRedisFunction($failOver['host'], $failOver['port'], $isPersistentConnect); } if (!$connectResult) { Plugin::hook('cml.cache_server_down', [$this->conf['server'][$success]]); throw new CacheConnectFailException(Lang::get('_CACHE_CONNECT_FAIL_', 'Redis', $this->conf['server'][$success]['host'] . ':' . $this->conf['server'][$success]['port'])); } $password = false; if (is_null($failOver)) { if (isset($this->conf['server'][$success]['password']) && !empty($this->conf['server'][$success]['password'])) { $password = $this->conf['server'][$success]['password']; } isset($this->conf['server'][$success]['db']) && $instance->select($this->conf['server'][$success]['db']); } else { if (isset($failOver['password']) && !empty($failOver['password'])) { $password = $failOver['password']; } isset($failOver['db']) && $instance->select($failOver['db']); Log::emergency('redis server down', ['downServer' => $this->conf['server'][$success], 'failOverTo' => $failOver]); Plugin::hook('cml.redis_server_down_fail_over', ['downServer' => $this->conf['server'][$success], 'failOverTo' => $failOver]); } if ($password && !$instance->auth($password)) { throw new \RuntimeException('redis password error!'); } $instance->setOption(\Redis::OPT_PREFIX, $this->conf['prefix']); $this->redis[$success] = $instance; } return $this->redis[$success]; }