分片算法代码
<?php
namespace App\Repositories\Redis;
use App\Repositories\BaseRepository;
class RedisSharding extends BaseRepository{
private static $instance = null;
private $isPersistent = 1;
private $shardingHashSlot = [];
private $slotCount = 1024;
private $redis = null;
private $thisNodeName = '';
private $redisConfigs = [];
private $useConfig = '';
private function __construct() {
App()->configure('redis');
$this->useConfig = 'redis.data_cache';
$this->redisConfigs = config($this->useConfig, []);
}
public static function getInstance($isPersistent = 1, $useConfig = 'database.redis'){
if(is_null(self::$instance) || !isset(self::$instance)){
self::$instance = new self();
}
if($useConfig != self::$instance->useConfig){
self::$instance->useConfig = $useConfig;
self::$instance->redisConfigs = config(self::$instance->useConfig, []);
self::$instance->generateShardingHashSlot();
}
self::$instance->isPersistent = $isPersistent;
return self::$instance;
}
public function __call($name, $arguments) {
$key = isset($arguments[0]) ? $arguments[0] : '';
$redis = $this->getConnect($key);
$result = call_user_func_array([$redis, $name], $arguments);
$redis->close();
return $result;
}
public function getThisNodeName(){
return $this->thisNodeName;
}
public function getKeyFallNodeName($key){
$this->getConnectConfig($key);
return $this->thisNodeName;
}
private function getConnect($key){
$redisConfig = $this->getConnectConfig($key);
$timeout = isset($redisConfig['timeout']) ? $redisConfig['timeout'] : 5;
$this->redis = new \Redis();
if($this->isPersistent){
$ret = $this->redis->pconnect($redisConfig['host'], $redisConfig['port'], $timeout);
}else{
$ret = $this->redis->connect($redisConfig['host'], $redisConfig['port'], $timeout);
}
if($ret){
$this->auth($this->redis, $redisConfig['password']);
}
return $this->redis;
}
private function getConnectConfig($key){
$crcid = abs(crc32($key));
$position = $crcid % $this->slotCount;
$redisConfigNodeName = isset($this->shardingHashSlot[$position]) ? $this->shardingHashSlot[$position] : 'default';
$this->thisNodeName = $redisConfigNodeName;
$redisConfig = isset($this->redisConfigs[$redisConfigNodeName]) ? $this->redisConfigs[$redisConfigNodeName] : [];
return $redisConfig;
}
private function generateShardingHashSlot(){
$redisConfigs = $this->redisConfigs;
unset($redisConfigs['cluster']);
if(!isset($redisConfigs['default'])){
throw new \Exception(' Not Found Redis default configure');
}
$this->shardingHashSlot = [];
foreach ($redisConfigs as $key => $redisConfig){
if(!isset($redisConfig['slot'])){
throw new \Exception(' Please configure ' . $key .' slot ');
}
$slot = $redisConfig['slot'];
$min = isset($slot[0]) ? $slot[0] : 0;
$max = isset($slot[1]) ? $slot[1] : 0;
if($min > $max || $max == 0){
throw new \Exception($key .' slot Must max > min ');
}
for($i = $min;$i < $max;$i++){
$this->shardingHashSlot[$i] = $key;
}
}
}
private function auth($redis, $password){
if($password){
return $redis->auth($password);
}
return true;
}
}
配置格式示例
<?php
return [
'data_cache' => [
'default' => [
'host' => '192.168.141.150',
'port' => '6379',
'database' => 0,
'password' => 'admin',
'persistent' => 1,
'timeout' => 5,
'slot' => [0, 512],
],
'redis1' => [
'host' => '192.168.141.150',
'password' => 'admin',
'port' => 6379,
'persistent' => 1,
'database' => 0,
'timeout' => 10,
'slot' => [512, 1024],
],
]
];