Laravel + predis + Redis集群 - MOVED /无连接到127.0.0.1:6379

时间:2016-12-11 20:59:11

标签: laravel redis azure-caching

我有一个laravel(5.3)应用程序,其中redis用于会话(使用predis)。只要我使用单个redis节点(使用 config / database.php 中的默认方法),一切正常。一旦我切换到Redis集群,虽然我开始得到MOVED错误,如50%的时间(基于谷歌搜索,我知道这应该由predis管理,但不知何故不是)。

我尝试将群集参数更改为true,但后来我得到了一个奇怪的错误

No connection could be made because the target machine actively refused it. [tcp://127.0.0.1:6379] 

虽然我使用的redis群集部署在Azure中(并通过.env文件配置),但在使用单个节点时接受参数没有任何问题。

配置

这是我的laravel配置(如前所述,它是标准默认值)

'redis' => [

        'client' => 'predis',
        'cluster' => false,

        'default' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

    ],

对于Redis,我使用Azure Redis缓存群集Premium P1,2个分片(如here所述)。

更新2

到目前为止,我还尝试了以下配置变体:

  1. 将群集设置为true
  2. 将群集设置为redis
  3. 添加默认值 - > cluster set to redis
  4. 添加默认值 - >选项设置为数组('cluster','redis')
  5. 我一直收到MOVED错误...

    我的Redis版本是3.2,predis / predis包1.1.1

    为predis 1.1 +

    工作配置
    'redis' => [
            'cluster' => true,
    
            'default' => [
                'host' => env('REDIS_HOST', 'localhost'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
            ] ,
            'options' => [
                'cluster' => 'redis',
                 'parameters' => ['password' => env('REDIS_PASSWORD', null)],
            ],
        ],
    

    非常感谢你的帮助:)

6 个答案:

答案 0 :(得分:9)

TL; DR:

  • 'cluster' => true应该是真的,可以创建一个处理多个节点的聚合客户端。
  • 'options' => ['cluster' => 'redis']需要作为default(不是孩子)的兄弟添加到配置中,以告知Predis处理Azure提供的服务器端群集。
  • 如果将auth用于服务器端群集,则需要'options' => [ 'cluster' => 'redis', 'parameters' => ['password' => env('REDIS_PASSWORD', null)], ]来验证新发现的群集节点。

全文

在redis配置中,您可以设置多个redis实例的多个连接。 cluster选项告诉Laravel如何处理这些多个已定义的连接。

如果cluster设置为false,Laravel将为每个连接创建单独的\Predis\Client个实例。每个连接都可以单独访问,与其他连接没有任何关系。

如果cluster设置为true,Laravel将使用所有已定义的连接创建聚合\Predis\Client实例。没有其他配置,这是一种"假的"簇。它使用客户端分片来分配密钥空间,可能需要外部监控和维护,以确保正确的密钥负载平衡。

然而,您遇到的问题是Azure(可能是)实现了一个真正的服务器端Redis集群,它处理密钥空间的自动分片。在这种情况下,节点彼此了解并且彼此交谈,并且可以上下移动。这是MOVEDASK响应的来源。

Predis库可以自动处理这些响应,但只有当您告诉它需要时才会这样。在这种情况下,您需要告诉Predis客户端它需要处理群集,这是由Laravel通过options配置上的redis数组完成的。

redis配置中,options密钥应该是您的连接的兄弟(即default),而不是孩子。此外,选项应指定为key => value对。

因此,您的配置应如下所示:

'redis' => [
    'cluster' => true,

    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
    ],

    'options' => [
        'cluster' => 'redis',
    ],
],

cluster配置下的redis密钥将告诉Laravel创建一个可以处理多个节点的聚合Predis\Client实例,以及{{1}下的cluster密钥数组将告诉该实例它需要处理服务器端集群,而不是客户端集群。

验证

原始连接参数(包括身份验证)不会与通过options-MOVED响应发现的新节点的连接共享。因此,您之前从-ASK响应中获得的任何错误现在只会转换为-MOVED错误。但是,服务器端NOAUTH配置允许'cluster'兄弟,它定义了与新发现的节点一起使用的参数列表。您可以在此处将auth参数用于新节点。

我相信这看起来像是:

'parameters'

公平警告,这是我刚从研究和代码潜水中得到的所有信息。虽然我已经将Redis与Laravel一起使用,但我还没有使用过服务器端集群,所以这仍然可能无效。

我在调查时发现了一些有用的信息:

Predis问题讨论连接到redis-cluster:
https://github.com/nrk/predis/issues/259#issuecomment-117339028

  

看起来您没有将Predis配置为使用redis-cluster,而是使用普通的旧客户端分片逻辑(这也是默认行为)。您应该使用值redis配置客户端设置选项集群,让客户端知道它必须与redis-cluster一起使用。快速举例:

     

'redis' => [ 'cluster' => true, 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], 'options' => [ 'cluster' => 'redis', 'parameters' => ['password' => env('REDIS_PASSWORD', null)], ], ],

     

这样做可以使客户端自动处理来自Redis节点的-MOVED或-ASK响应。

MS文章讨论redis缓存上的群集:
https://docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-premium-clustering#how-do-i-connect-to-my-cache-when-clustering-is-enabled

  

您可以使用连接到未启用群集的缓存时使用的相同端点,端口和密钥连接到缓存。 Redis管理后端的群集,因此您无需从客户端管理群集。

用于创建$client = new Predis\Client([$node1, $node2, ...], ['cluster' => 'redis']);个实例的Laravel代码:
https://github.com/laravel/framework/blob/v5.3.28/src/Illuminate/Redis/Database.php#L25-L66

答案 1 :(得分:0)

对于AWS elasticcache redis群集,上述配置无效,但下面的内容对我有用。文档中还提到了https://laravel.com/docs/5.4/redis#configuration

'redis' => [
    'client' => 'predis',
    'options' => [
        'cluster' => 'redis',
    ],
    'clusters' => [
        'default' => [
            [
                'host' => env('REDIS_HOST', 'localhost'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
            ],
        ],
    ],
],

答案 2 :(得分:0)

相关:Laravel + Redis Cache via SSL?

我已在此回答:https://stackoverflow.com/a/48876398/663058

以下相关详情:

如果您有群集 TLS,那么您需要以下配置(使用AWS Elasticache进行测试):

'redis' => [
        'client' => 'predis',
        'cluster' => env('REDIS_CLUSTER', false),

        // Note! for single redis nodes, the default is defined here.
        // keeping it here for clusters will actually prevent the cluster config
        // from being used, it'll assume single node only.
        //'default' => [
        //    ...
        //],

        // #pro-tip, you can use the Cluster config even for single instances!
        'clusters' => [
            'default' => [
                [
                    'scheme'   => env('REDIS_SCHEME', 'tcp'),
                    'host'     => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port'     => env('REDIS_PORT', 6379),
                    'database' => env('REDIS_DATABASE', 0),
                ],
            ],
            'options' => [ // Clustering specific options
                'cluster' => 'redis', // This tells Redis Client lib to follow redirects (from cluster)
            ]
        ],
        'options' => [
            'parameters' => [ // Parameters provide defaults for the Connection Factory
                'password' => env('REDIS_PASSWORD', null), // Redirects need PW for the other nodes
                'scheme'   => env('REDIS_SCHEME', 'tcp'),  // Redirects also must match scheme
            ],
            'ssl'    => ['verify_peer' => false], // Since we dont have TLS cert to verify
        ]
    ]

解释上述内容:

  • 'client' => 'predis':这指定要使用的PHP Library Redis驱动程序(predis)。
  • 'cluster' => 'redis':这告诉Predis假设服务器端群集。这只是意味着"遵循重定向" (例如-MOVED回复)。使用群集运行时,节点将使用-MOVED响应您必须要求输入特定密钥的节点。
    • 如果您没有使用Redis群集启用此功能,Laravel将抛出-MOVED例外1 / n 次, n 为该号码Redis集群中的节点(它很幸运,每隔一段时间就会问一次正确的节点)
  • 'clusters' => [...]:指定节点列表,但只设置一个'默认'并将其指向AWS 'Configuration endpoint'将让它动态地找到任何/所有其他节点(推荐用于Elasticache,因为您不知道节点何时出现,或者是goin')。
  • 'options':对于Laravel,可以在顶级,群集级别和节点选项中指定。 (他们在被传递到Predis之前被合并在Illuminate中)
  • 'parameters':这些'覆盖' Predis用于新连接的默认连接设置/假设。由于我们明确设置了默认值'连接,这些都没有使用。但对于群集设置,它们至关重要。 A'主人'节点可以发回重定向(-MOVED),除非为passwordscheme设置参数,否则它将假设默认值,并且与新节点的新连接将失败。

答案 3 :(得分:0)

请参阅[{https://laravel.com/docs/5.5/redis]。

确保您拥有正确的库

composer require predis/predis

在config / database.php和config / queue.php中[如果您的队列也使用集群reddis]

'redis' => [

    'client' => 'predis',
    'options' => [
        'cluster' => 'redis',
    ],
    'clusters' => [
        'default' => [
            [
                'host' => env('REDIS_HOST', 'localhost'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
            ],
        ],
    ],

]

答案 4 :(得分:0)

这对我有用:

entryComponents

要查看我如何到达那里,请查看我的答案here

答案 5 :(得分:0)

这个结果出现在谷歌的 predis+redis-cluster 中(没有 laravel)。我和我的团队在这个问题上苦苦挣扎了几个小时,所以我把这个答案放在这里给那些在尝试直接连接到 Redis 集群时发现这个页面出现错误的人:

$redis = new Predis\Client(
   ['tcp://127.0.0.1:6379'],
   ['cluster' => 'redis']
);