Laravel + predis + Redis 集群 - 移动 / 没有连接到 127.0.0.1:6379

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41091103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 14:54:28  来源:igfitidea点击:

Laravel + predis + Redis cluster - MOVED / no connection to 127.0.0.1:6379

laravelredisazure-caching

提问by Lech Migdal

I have a laravel (5.3) app with redis used for sessions (using predis). Everything works as long as I use a single redis node (using default approach from config/database.php). As soon as I switch to a Redis cluster though I am starting to get MOVED error like 50% of the time (based on googling I understand that this should be managed by predis, but somehow isn't).

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

I tried changing the cluster parameter to true, but then I get a weird error

我尝试将集群参数更改为 true,但随后出现了一个奇怪的错误

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

Although the redis cluster that I use is deployed in Azure (and is configured via .env file) and the parameters are accepted without any problem when a single node is used.

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

Configuration

配置

Here is the laravel configuration that I have (as mentioned earlier, it's the standard default)

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

'redis' => [

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

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

    ],

For Redis, I use Azure Redis Cache Cluster Premium P1, 2 shards (as described here).

对于Redis的,我使用的Redis天青缓存集群高级P1,2个碎片(如所描述的在这里)。

UPDATE 2

更新 2

So far I also tried the following variations of the config:

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

  1. Setting cluster to true
  2. Setting cluster to redis
  3. Adding default -> cluster set to redis
  4. Adding default -> options set to array('cluster', 'redis')
  1. 将集群设置为 true
  2. 将集群设置为redis
  3. 添加默认 -> 集群设置为 redis
  4. 添加默认 -> 选项设置为 array('cluster', 'redis')

All the time I am getting MOVED error...

我一直收到 MOVED 错误...

My Redis version is 3.2, predis/predis package 1.1.1

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

Working config for predis 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)],
        ],
    ],

Big thank you for all the help :)

非常感谢您的所有帮助:)

回答by patricus

TL;DR:

特尔;博士:

  • 'cluster' => trueshould be true to create one aggregate client that handles multiple nodes.
  • 'options' => ['cluster' => 'redis']needs to be added to the configuration as a sibling of default(not a child) in order to tell Predis to handle the server-side clustering provided by Azure.
  • if using auth with server-side clustering, 'options' => [ 'cluster' => 'redis', 'parameters' => ['password' => env('REDIS_PASSWORD', null)], ]will be needed to auth newly discovered cluster nodes.
  • 'cluster' => true创建一个处理多个节点的聚合客户端应该是正确的。
  • 'options' => ['cluster' => 'redis']需要作为兄弟default(不是子)添加到配置中,以便告诉 Predis 处理 Azure 提供的服务器端集群。
  • 如果将身份验证与服务器端集群一起使用,'options' => [ 'cluster' => 'redis', 'parameters' => ['password' => env('REDIS_PASSWORD', null)], ]则需要对新发现的集群节点进行身份验证。

Full Text

全文

In the redis configuration, you can set up multiple connections to multiple redis instances. The clusteroption tells Laravel how to handle those multiple defined connections.

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

If clusteris set to false, Laravel will create individual \Predis\Clientinstances for each connection. Each connection can be accessed individually, and will not have any relation to another connection.

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

If clusteris set to true, Laravel will create an aggregate \Predis\Clientinstance using all the defined connections. With no other configuration, this is kind of a "fake" cluster. It uses client-side sharding to distribute the keyspace and may require external monitoring and maintenance to ensure a proper key load balance.

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

The issue you're running into, however, is that Azure implements (presumably) a real server-side Redis cluster, which handles automatic sharding of the keyspace. In this instance, the nodes know about each other and talk to each other, and may go up and down. This is where MOVEDand ASKresponses come from.

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

The Predislibrary can automatically handle these responses, but only when you tell it that it needs to. In this case, you need to tell the Predisclient that it needs to handle clustering, and this is done by Laravel through the optionsarray on the redisconfiguration.

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

On the redisconfiguration, the optionskey should be a sibling of your connections (i.e. default), not a child. Additionally, the options should be specified as key => valuepairs.

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

So, your configuration should look like:

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

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

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

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

The clusterkey under the redisconfig will tell Laravel to create an aggregate Predis\Clientinstance that may handle multiple nodes, and the clusterkey under the optionsarray will tell that instance that it needs to handle server-side clustering, not client-side clustering.

cluster下键redis配置会告诉Laravel来创建聚合Predis\Client可以处理多个节点的实例,而cluster下键options阵列会告诉实例它需要处理服务器端集群,而不是客户端集群。

Auth

认证

The original connection parameters (including authentication) are not shared with connections to new nodes discovered via -MOVEDand -ASKresponses. So, any errors you previously got from -MOVEDresponses will now just convert to NOAUTHerrors. However, the server-side 'cluster'configuration allows for a 'parameters'sibling which defines a list of parameters to use with newly discovered nodes. This is where you can put your auth parameters to use with new nodes.

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

I believe this will look something like:

我相信这看起来像:

'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)],
    ],
],


Fair warning, this is all information I just got from research and code diving. While I have used Redis with Laravel, I have not used server side clustering (yet), so this still may not work.

公平警告,这是我刚刚从研究和代码潜水中获得的所有信息。虽然我已经在 Laravel 中使用了 Redis,但我还没有使用过服务器端集群(还没有),所以这仍然可能不起作用。

Some useful pieces of information I came across while looking into this:

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

Predis issue discussing connecting to a redis-cluster:
https://github.com/nrk/predis/issues/259#issuecomment-117339028

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

It looks like you did not configure Predis to use redis-cluster but instead you are using it with the plain old client-side sharding logic (which is also the default behaviour). You should configure the client setting the option cluster with the value redis to let the client know it must play along with redis-cluster. Quick example:

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

Doing so will make it possible for the client to automatically handle -MOVED or -ASK responses coming from Redis nodes.

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

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

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

MS article discussing clustering on redis cache:
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 缓存集群的 MS 文章:https:
//docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-premium-clustering#how-do-i-connect-to-my-启用集群时缓存

You can connect to your cache using the same endpoints, ports, and keys that you use when connecting to a cache that does not have clustering enabled. Redis manages the clustering on the backend so you don't have to manage it from your client.

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

Laravel code for creating Predis\Clientinstances:
https://github.com/laravel/framework/blob/v5.3.28/src/Illuminate/Redis/Database.php#L25-L66

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

回答by ramesh.mimit

For AWS elasticcache redis cluster the above configuration did not work, however below are working for me. Also mentioned in the documentation: https://laravel.com/docs/5.4/redis#configuration

对于 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,
            ],
        ],
    ],
],

回答by CenterOrbit

Related: Laravel + Redis Cache via SSL?

相关:Laravel + Redis 缓存通过 SSL?

To which I've answered here: https://stackoverflow.com/a/48876398/663058

我在这里回答过:https: //stackoverflow.com/a/48876398/663058

Relevant details below:

相关详情如下:

If you have clustering andTLS then you'll need a the following config (tested with AWS Elasticache):

如果您有集群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
        ]
    ]

Explaining the above:

解释以上内容:

  • 'client' => 'predis': This specifies the PHP Library Redis driver to use (predis).
  • 'cluster' => 'redis': This tells Predis to assume server-side clustering. Which just means "follow redirects" (e.g. -MOVEDresponses). When running with a cluster, a node will respond with a -MOVEDto the node that you must ask for a specific key.
    • If you don't have this enabled with Redis Clusters, Laravel will throw a -MOVEDexception 1/ntimes, nbeing the number of nodes in Redis cluster (it'll get lucky and ask the right node every once in awhile)
  • 'clusters' => [...]: Specifies a list of nodes, but setting just a 'default' and pointing it to the AWS 'Configuration endpoint'will let it find any/all other nodes dynamically (recommended for Elasticache, because you don't know when nodes are comin' or goin').
  • 'options': For Laravel, can be specified at the top-level, cluster-level, and node option. (they get combined in Illuminate before being passed off to Predis)
  • 'parameters': These 'override' the default connection settings/assumptions that Predis uses for new connections. Since we set them explicitly for the 'default' connection, these aren't used. But for a cluster setup, they are critical. A 'master' node may send back a redirect (-MOVED) and unless the parameters are set for passwordand schemeit'll assume defaults, and that new connection to the new node will fail.
  • 'client' => 'predis':这指定要使用的 PHP 库 Redis 驱动程序 (predis)。
  • 'cluster' => 'redis':这告诉 Predis 假设服务器端集群。这只是意味着“跟随重定向”(例如-MOVED响应)。与集群一起运行时,节点将响应-MOVED您必须请求特定密钥的节点。
    • 如果您没有在 Redis Clusters 中启用此功能,Laravel 将抛出-MOVED1/ n次异常,n是 Redis 集群中的节点数(它会很幸运并每隔一段时间询问正确的节点)
  • 'clusters' => [...]:指定节点列表,但仅设置一个“默认”并将其指向AWS 的“配置端点”将使其动态查找任何/所有其他节点(推荐用于 Elasticache,因为您不知道节点何时到来)或去')。
  • 'options':对于Laravel,可以在top-level、cluster-level、node选项中指定。(在传递给 Predis 之前,它们在 Illuminate 中组合在一起)
  • 'parameters':这些“覆盖” Predis 用于新连接的默认连接设置/假设。由于我们为“默认”连接明确设置了它们,因此不使用它们。但对于集群设置,它们至关重要。“主”节点可能会发回重定向 ( -MOVED) 并且除非设置了参数password并且scheme它将采用默认值,否则到新节点的新连接将失败。

回答by Pinak Saha

Please refer to [ https://laravel.com/docs/5.5/redis].

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

Make sure you have the proper library

确保你有合适的库

composer require predis/predis

In config/database.php as well as config/queue.php [ if your queue is also using clustered reddis]

在 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,
            ],
        ],
    ],

]

回答by abbood

this worked for me:

这对我有用:

'redis' => [
    'client' => 'predis',
    'cluster' => true,
    'options' => [
        'cluster' => 'redis',
        'parameters' => [
            'host' => env('REDIS_DEFAULT_HOST', '127.0.01'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_DEFAULT_PORT', 6379),
            'database' => 0,
            ],
        ],
    'clusters' => [
         'default' => [
            'host' => env('REDIS_DEFAULT_HOST', '127.0.01'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_DEFAULT_PORT', 6379),
            'database' => 0,
        ],
        'jobs' => [
            'host' => env('REDIS_JOBS_HOST', '127.0.01'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_JOBS_PORT', 6379),
            'database' => 0,
        ],
        'content' => [
            'host' => env('REDIS_CONTENT_HOST', '127.0.01'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_CONTENT_PORT', 6379),
            'database' => 0,
        ],
        'options' => [
            'cluster' => 'redis'
        ],
    ]
]

to see how I got there, see my answer here

查看我是如何到达那里的,请在此处查看我的答案