摘要: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,上代码.
Illuminate\Support\ServiceProvider\RedisServiceProvider; public function register() { $this->app->singleton('redis', function ($app) { return new Database($app['config']['database.redis']); }); } Illuminate\Redis\Database; 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-------
接下来我们看看这些底层要初始化的类吧.
Predis\Client; 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())
Predis\Client 文件 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.'); } Predis\Configuration\Options; protected function getHandlers() { return array( 'cluster' => 'Predis\Configuration\ClusterOption', 'connections' => 'Predis\Configuration\ConnectionFactoryOption', #'exceptions' => 'Predis\Configuration\ExceptionsOption', #'prefix' => 'Predis\Configuration\PrefixOption', #'profile' => 'Predis\Configuration\ProfileOption', #'replication' => 'Predis\Configuration\ReplicationOption', ); } 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(); //会实例化Predis\Configuration\ClusterOption类 $value = $handler->filter($this, $value); } return $this->options[$option] = $value; } # if (isset($this->handlers[$option])) { # return $this->options[$option] = $this->getDefault($option); # } # return; } Predis\Configuration\ClusterOption文件 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 'Predis\Connection\Aggregate\ClusterInterface' 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 = 'Predis\Configuration\ConnectionFactoryOption'; $handler = new $handler(); return $handler->getDefault($this); } } Predis\Configuration\ConnectionFactoryOption文件 public function getDefault(OptionsInterface $options) { return new Factory(); //最后实例化了一个'工厂'类 }
$this->profile = $this->options->profile;
Predis\Configuration\ProfileOption文件 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 = 'Predis\Configuration\ProfileOption'; $handler = new $handler(); return $handler->getDefault($this); } } Predis\Configuration\ProfileOption文件 public function getDefault(OptionsInterface $options) { $profile = Factory::getDefault(); //实例化了Predis\Profile\RedisVersion300类 $this->setProcessors($options, $profile); return $profile; }
Atas ialah kandungan terperinci 有关laravel5.2和redis_cluster配置的介绍. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!