摘要:laravel中redis集群的应用这部分我想分享下laravel5.2中redis集群的配置(官网也有redis集群的配置讲解,但是5.2版还是有点不足,只是说了将cluster配置项设为true,但光这样一个选项不能代表,一个新手直接可用redis集 ...
这部分我想分享下laravel5.2中redis集群的配置(官网也有redis集群的配置讲解,但是5.2版还是有点不足,只是说了将cluster配置项设为true,但光这样一个选项不能代表,一个新手直接可用redis集群,这部分还包括predis客户端的事,所以后面我也会分享下关于predis的源码分析)。
redis—cluster的搭建:Easy Building Redis-cluster (轻松搭建reids集群)
系统软件清单:
laravel版本:5.2
redis版本:>=3.0下载最新版即可
predis:>=1.0下载地址
配置文件:config/database.php
'redis' => [ 'cluster' => env('REDIS_CLUSTER', true),
**'options'=>['cluster'=>'redis']**, //官网没说这个,这是必须的!!后面会讲为什么这么配?
'default' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), //任选一个master节点
'port' => env('REDIS_PORT',6379), 'database' => 0, 'timeout'=>15, 'read_write_timeout'=>1800 //redis客户端连接以后的读写超时时间(默认是60s)
], 'extra'=>[
'host'=>env('REDIS_EXTRA_HOST','127.0.0.1'), //任意一个集群中的节点即可
'port'=>env('REDIS_EXTRA_PORT',7001)
]
]ok,配完上面的步骤,redis集群就可以用了.
具体使用redis集群的应用场景根据业务需求有很多种,比如集群存session等.
app('request')->session()->put('key','value');就存到集群中了.
ok,想要了解配置文件中的参数,还是得看源代码,当然也是predis,上代码.
IlluminateSupportServiceProviderRedisServiceProvider; public function register()
{ $this->app->singleton('redis', function ($app) { return new Database($app['config']['database.redis']);
});
}
IlluminateRedisDatabase;
public function __construct(array $servers = [])
{
$cluster = Arr::pull($servers, 'cluster'); //获取'cluster'的键值
$options = (array) Arr::pull($servers, 'options'); //options 就是database.php中'options'的键值,是一个数组(但官网没有提到,是个坑.)
if ($cluster) {
$this->clients = $this->createAggregateClient($servers, $options); //集群模式'cluster=true'
} else {
$this->clients = $this->createSingleClients($servers, $options); //单机模式 'cluster=false'
}
} protected function createAggregateClient(array $servers, array $options = [])
{
return ['default' => new Client(array_values($servers), $options)]; //predis的Client类
}
----------
注意:这里提醒一下各参数的值:
此时$servers=[
[ 'host' => env('REDIS_HOST', '127.0.0.1'), 'port' => env('REDIS_PORT',6379), 'database' => 0, 'timeout'=>15, 'read_write_timeout'=>1800
],
[ 'host'=>env('REDIS_EXTRA_HOST','127.0.0.1'), 'port'=>env('REDIS_EXTRA_PORT',7001)
]
]
$options = ['cluster'=>'redis']
其实到这儿,就可以解释在database.php中增加options选项,而且是必选项,因为底层代码需要判断数据切片的方式.
除了看源码,
predis的包文档也做了解释.https://packagist.org/packages/predis/predis-------接下来我们看看这些底层要初始化的类吧.
PredisClient; public function __construct($parameters = null, $options = null)
{ $this->options = $this->createOptions($options ?: array()); #$this->connection = $this->createConnection($parameters ?: array());
#$this->profile = $this->options->profile;
}
protected function createOptions($options)
{ if (is_array($options)) { return new Options($options); //如你所见,实例化Options类
} if ($options instanceof OptionsInterface) { return $options;
} throw new InvalidArgumentException('Invalid type for client options.');
}
public function __construct(array $options = array())
{ $this->input = $options; $this->options = array(); $this->handlers = $this->getHandlers();
}$this->connection = $this->createConnection($parameters ?: array())
PredisClient 文件
protected function createConnection($parameters)
{
# if ($parameters instanceof ConnectionInterface) {
# return $parameters;
# }
# if ($parameters instanceof ParametersInterface || is_string($parameters)) {
# return $this->options->connections->create($parameters);
# }
# if (is_array($parameters)) {
# if (!isset($parameters[0])) {
# return $this->options->connections->create($parameters);
# } $options = $this->options;
# if ($options->defined('aggregate')) {
# $initializer = $this->getConnectionInitializerWrapper($options->aggregate);
# $connection = $initializer($parameters, $options);
# } else {
# if ($options->defined('replication') && $replication = $options->replication) {
# $connection = $replication;
# } else {
$connection = $options->cluster; //
# } $options->connections->aggregate($connection, $parameters);
# }
return $connection;
# }
# if (is_callable($parameters)) {
# $initializer = $this->getConnectionInitializerWrapper($parameters);
# $connection = $initializer($this->options);
# return $connection;
# }
# throw new InvalidArgumentException('Invalid type for connection parameters.');
}
PredisConfigurationOptions;
protected function getHandlers()
{
return array( 'cluster' => 'PredisConfigurationClusterOption', 'connections' => 'PredisConfigurationConnectionFactoryOption',
#'exceptions' => 'PredisConfigurationExceptionsOption',
#'prefix' => 'PredisConfigurationPrefixOption',
#'profile' => 'PredisConfigurationProfileOption',
#'replication' => 'PredisConfigurationReplicationOption',
);
}
public function __get($option)
{
#if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
# return $this->options[$option];
#} if (isset($this->input[$option]) || array_key_exists($option, $this->input)) { $value = $this->input[$option];
unset($this->input[$option]);
# if (is_object($value) && method_exists($value, '__invoke'){
# $value = $value($this, $option);
# } if (isset($this->handlers[$option])) { $handler = $this->handlers[$option]; $handler = new $handler(); //会实例化PredisConfigurationClusterOption类
$value = $handler->filter($this, $value);
}
return $this->options[$option] = $value;
}
# if (isset($this->handlers[$option])) {
# return $this->options[$option] = $this->getDefault($option);
# }
# return;
}
PredisConfigurationClusterOption文件
public function filter(OptionsInterface $options, $value)
{ if (is_string($value)) { $value = $this->createByDescription($options, $value);
}
# if (!$value instanceof ClusterInterface) {
# throw new InvalidArgumentException(
# "An instance of type 'PredisConnectionAggregateClusterInterface' was expected."
# );
# }
return $value;
}
protected function createByDescription(OptionsInterface $options, $id)
{
switch ($id) {
* Abstraction for a cluster of aggregate connections to various Redis servers
* implementing client-side sharding based on pluggable distribution strategies.
# case 'predis':
# case 'predis-cluster':
# return new PredisCluster();
//这个模式是客户端通过CRC16算法在客户端进行数据切片,
显然这种模式的集群是脆弱的,如果一个master节点挂了,
那其备节点若也挂了,那么获取数据就成问题了;
再有这种模式扩展性很差,维护成本高,
因此这个模式不推荐.当然用最新predis不存在这个问题.
我这边predis,1.0算比较老了.
case 'redis':
case 'redis-cluster':
return new RedisCluster($options->connections); //这种模式是基于服务端的数据切片,相较于第一种模式,优点也显而易见,维护成本低,扩展性好等.
default:
return;
}
}
public function __get($option)
{
#if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
# return $this->options[$option];
#}
# if (isset($this->input[$option]) || array_key_exists($option, $this->input)) {
# $value = $this->input[$option];
# unset($this->input[$option]);
# if (is_object($value) && method_exists($value, '__invoke'){
# $value = $value($this, $option);
# }
# if (isset($this->handlers[$option])) {
# $handler = $this->handlers[$option];
# $handler = new $handler();
# $value = $handler->filter($this, $value);
# }
# return $this->options[$option] = $value;
#} if (isset($this->handlers[$option])) { //$options='connections'
return $this->options[$option] = $this->getDefault($option);
# }
# return;
}
public function getDefault($option)
{ if (isset($this->handlers[$option])) { $handler = $this->handlers[$option]; //$handler = 'PredisConfigurationConnectionFactoryOption';
$handler = new $handler();
return $handler->getDefault($this);
}
}
PredisConfigurationConnectionFactoryOption文件
public function getDefault(OptionsInterface $options)
{
return new Factory(); //最后实例化了一个'工厂'类
}$this->profile = $this->options->profile;
PredisConfigurationProfileOption文件
public function __get($option)
{
#if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
# return $this->options[$option];
#}
# if (isset($this->input[$option]) || array_key_exists($option, $this->input)) {
# $value = $this->input[$option];
# unset($this->input[$option]);
# if (is_object($value) && method_exists($value, '__invoke'){
# $value = $value($this, $option);
# }
# if (isset($this->handlers[$option])) {
# $handler = $this->handlers[$option];
# $handler = new $handler();
# $value = $handler->filter($this, $value);
# }
# return $this->options[$option] = $value;
#} if (isset($this->handlers[$option])) { //$options='profile'
return $this->options[$option] = $this->getDefault($option);
# }
# return;
}
public function getDefault($option)
{ if (isset($this->handlers[$option])) { $handler = $this->handlers[$option]; //$handler = 'PredisConfigurationProfileOption';
$handler = new $handler();
return $handler->getDefault($this);
}
}
PredisConfigurationProfileOption文件
public function getDefault(OptionsInterface $options)
{ $profile = Factory::getDefault(); //实例化了PredisProfileRedisVersion300类
$this->setProcessors($options, $profile);
return $profile;
}| 欢迎光临 一起源码网 (https://www.171739.xyz/) | Powered by Discuz! X3.3 |