欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-03-24 19:20:10
...


摘要: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;  
    }

以上就是有关laravel5.2和redis_cluster配置的介绍的详细内容,更多请关注其它相关文章!