一尘不染

Laravel + Predis + Redis集群-已移动/未连接到127.0.0.1:6379

redis

我有一个带有redis的laravel(5.3)应用程序,用于会话(使用predis)。只要我使用单个redis节点(使用 config /
database.php中的

默认方法),一切都可以正常工作。一旦我切换到Redis集群,尽管我开始像50%的时间一样出现MOVED错误(基于谷歌搜索,我知道这应该由predis管理,但不是这样)。

我尝试将cluster参数更改为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的,我使用的Redis天青缓存集群高级P1,2个碎片(如所描述的在这里)。

更新2

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

  1. 将集群设置为true
  2. 将集群设置为Redis
  3. 添加默认->集群设置为Redis
  4. 添加默认->选项设置为array(’cluster’,’redis’)

我一直都在出现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)],
        ],
    ],

非常感谢您的帮助:)


阅读 617

收藏
2020-06-20

共1个答案

一尘不染

TL; DR:

  • 'cluster' => true 创建一个处理多个节点的聚合客户端时应为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可以处理多个节点的实例,而cluster下键options阵列会告诉实例它需要处理服务器端集群,而不是客户端集群。

验证码

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

我相信这看起来像:

'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与Laravel结合使用,但尚未使用服务器端集群(因此),因此这可能仍然行不通。

我在研究时遇到了一些有用的信息:

Predis讨论连接到Redis集群的问题:https
//github.com/nrk/predis/issues/259#issuecomment-117339028

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

$client = new Predis\Client([$node1, $node2, ...], ['cluster' => 'redis']);

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

MS文章讨论Redis缓存上的群集:https :
//docs.microsoft.com/zh-cn/azure/redis-cache/cache-how-to-premium-
clustering#how-do-i-connect-to-my-启用集群缓存

您可以使用与连接到未启用群集的缓存时使用的端点,端口和键相同的端点连接到缓存。Redis在后端管理集群,因此您不必从客户端进行管理。

用于创建Predis\Client实例的Laravel代码:https
//github.com/laravel/framework/blob/v5.3.28/src/Illuminate/Redis/Database.php#L25-L66
2020-06-20