Laravel + Redis缓存通过SSL连接?

14

我正在尝试使用Predis 1.1和SSL连接Redis,使用的信息在https://github.com/nrk/predis中,示例中使用了以下配置:

// Named array of connection parameters:
$client = new Predis\Client([
  'scheme' => 'tls',
  'ssl'    => ['cafile' => 'private.pem', 'verify_peer' => true],
]);

我的Laravel配置如下:

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

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

很不幸,我遇到了以下错误:

ConnectionException in AbstractConnection.php line 155:
Error while reading line from the server. [tcp://MY_REDIS_SERVER_URL:6380]

欢迎提出建议 :)


请发布您的.env文件。错误出在您的.env中 MY_REDIS_SERVER_URL 的部分。 - Paras
MY_REDIS_SERVER_URL 简单来说就是 Redis 服务器的 URL。我可以通过端口 6379 访问它,但无法通过 6380 访问。两个端口都应该可访问(这是 Azure Redis Cache,默认情况下打开了 6380 端口)。 - Lech Migdal
你找到解决方案了吗? - codiaf
很遗憾,还没有,有什么建议吗? :) - Lech Migdal
同样的问题,我就是无法使用SSL使其工作。 - codiaf
4个回答

34

我成功了!

你需要将'scheme''options'移动到'default'

我的配置文件已经生效:

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

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

    'options' => [
        'parameters' => ['password' => env('REDIS_PASSWORD', null)],
    ],
],

注意:我还从“选项”中删除了“集群”选项,但我不认为这会是解决此问题的关键。

在我的最终配置中,我将其更改为:'scheme' => env('REDIS_SCHEME', 'tcp'),然后在env文件中定义REDIS_SCHEME=tls

已经使用启用了TLS的AWS Elasticache进行测试。

编辑:上述配置仅适用于单节点redis。如果您同时启用了集群和TLS,则需要完全不同的配置。

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

解释如下:

  • 'client' => 'predis': 这指定了要使用的 PHP Library Redis 驱动程序(predis)。
  • 'cluster' => 'redis': 这告诉 Predis 假定服务器端群集,这意味着“遵循重定向”(例如-MOVED响应)。在运行群集时,节点将对必须请求特定键的节点发出-MOVED响应。
  • 如果没有启用 Redis 群集,则 Laravel 将抛出-MOVED异常1/n次,其中n是 Redis 群集中节点的数量(它偶尔会幸运地问正确的节点)
  • 'clusters' => [...]:指定节点列表,但仅设置“默认值”并将其指向AWS“配置端点”将使它动态查找任何/所有其他节点(推荐用于 Elasticache,因为您不知道何时节点将到来或离开)。
  • 'options':对于 Laravel,可以在顶级、群集级和节点选项处指定(在传递给 Predis 之前,在 Illuminate 中合并)。
  • 'parameters':这些“覆盖” Predis 为新连接使用的默认连接设置/假设。由于我们明确为“默认”连接设置了它们,因此不会使用它们。但对于集群设置,它们非常关键。“主”节点可能会发送重定向(-MOVED),除非为passwordscheme设置参数,否则它将假定默认值,并且与新节点的新连接将失败。

1
非常好的分析!如果我说错了,请有人纠正我。在查看Laravel 5.5源代码之后,顶层的'cluster' => env('REDIS_CLUSTER', false)不起任何作用。要使用集群,您只需拥有一个顶级clusters数组,并且像@CenterOrbit提到的那样,**删除顶级default**连接配置。如果Laravel找到一个名为您的连接名称(默认情况下为“default”)的顶级密钥,则不会在clusters配置中查找连接。 https://github.com/laravel/framework/blob/5.5/src/Illuminate/Redis/RedisManager.php#L72 - Brandon
此外,@CenterOrbit提到的每个集群的“选项”需要您将关联的“选项”值混合到非关联节点数组中,例如:'redis' => [ 'clusters' => [ 'default' => [ 'options' => [ 'cluster' => 'redis' ], [ 'scheme' => env('REDIS_SCHEME', 'tcp'), /* ... */ ], ], ], ] - Brandon
这是一个更好格式化的Gist,其中包含更多与我的先前评论相关的信息。 - Brandon

4

感谢CenterOrbit!!

我可以确认第一种解决方案允许Laravel通过TLS连接到Redis服务器。在AWS ElastiCache上测试了Redis 3.2.6,配置为单节点和单分片。

我也可以确认第二种解决方案允许Laravel通过TLS连接到Redis集群。在AWS ElastiCache上测试了Redis 3.2.6,配置为“启用集群模式”,1个分片,每个分片1个副本。

当我第一次尝试实现集群解决方案时,我收到了以下错误:

Error: Unsupported operand types

当我将 "default" 设置移到 "clusters" 数组中时,我错过了额外的数组括号。

错误的

'clusters' => [
  'default' => [
    'scheme' ...
  ]
]

正确

'clusters' => [
  'default' => [
    [
      'scheme' ...
    ]
  ]
]

我希望这篇文章能为他人节省一些疑难排查的时间。


0

CenterOrbit提供的解决方案对我有用,因为我正在使用AWS,所以我必须在我的.env文件中添加tls://

Laravel


0

tls://username:password@URL:PORT?database=0 试一下,它会起作用的


1
目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接