Rumah  >  Artikel  >  pembangunan bahagian belakang  >  有关laravel5.2和redis_cluster配置的介绍

有关laravel5.2和redis_cluster配置的介绍

巴扎黑
巴扎黑asal
2017-08-17 08:57:541980semak imbas


摘要:laravel中redis集群的应用这部分我想分享下laravel5.2中redis集群的配置(官网也有redis集群的配置讲解,但是5.2版还是有点不足,只是说了将cluster配置项设为true,但光这样一个选项不能代表,一个新手直接可用redis集 ...

laravel中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');就存到集群中了.

predis对redis集群的底层实现

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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn