Laravel + Redis Cache через SSL?

Я пытаюсь подключиться к Redis с помощью predis 1.1 и SSL, используя информацию 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',
            'ssl'    => ['verify_peer' => false],
        ],
    ],

Поскольку у меня нет ключа, используемого для SSL, я отключил одноранговую проверку (согласно http://php.net/manual/en/context.ssl.php).

К сожалению, я получаю следующую ошибку:

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

Предложения приветствуются :)


person Lech Migdal    schedule 20.01.2017    source источник
comment
Пожалуйста, опубликуйте свой файл .env. Ошибка заключается в том, что в вашем .env указано MY_REDIS_SERVER_URL.   -  person Paras    schedule 20.01.2017
comment
MY_REDIS_SERVER_URL — это просто URL-адрес сервера Redis. Я могу связаться с ним через порт 6379, но не через 6380. Оба должны быть доступны (это Azure Redis Cache, по умолчанию 6380 открыт).   -  person Lech Migdal    schedule 21.01.2017
comment
Вы нашли решение для этого?   -  person codiaf    schedule 10.03.2017
comment
К сожалению, пока нет, есть предложения? :)   -  person Lech Migdal    schedule 11.03.2017
comment
То же самое здесь, я просто не могу заставить его работать с SSL   -  person codiaf    schedule 13.03.2017


Ответы (2)


Я смог заставить его работать!

Вам нужно переместить «схему» с '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)],
        'ssl'    => ['verify_peer' => false],
    ],
],

Примечание. Я также удалил параметр 'cluster' из 'options', но я не подозреваю, что это решает эту проблему.

В моей окончательной конфигурации я изменил его на: 'scheme' => env('REDIS_SCHEME', 'tcp'),, а затем вместо этого определил REDIS_SCHEME=tls в моем файле env.

Протестировано с AWS ElastiCache с включенным TLS.

Изменить: приведенная выше конфигурация работает только с 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
            ],
            'ssl'    => ['verify_peer' => false], // Since we dont have TLS cert to verify
        ]
    ]

Объясняя вышесказанное:

  • 'client' => 'predis': указывает используемый драйвер Redis библиотеки PHP (predis).
  • 'cluster' => 'redis': This tells Predis to assume server-side clustering. Which just means "follow redirects" (e.g. -MOVED responses). When running with a cluster, a node will respond with a -MOVED to the node that you must ask for a specific key.
    • If you don't have this enabled with Redis Clusters, Laravel will throw a -MOVED exception 1/n times, n being the number of nodes in Redis cluster (it'll get lucky and ask the right node every once in awhile)
  • 'clusters' => [...]: указывает список узлов, но устанавливает только «по умолчанию» и указывает на Конечная точка конфигурации AWS позволит ему динамически находить любые/все остальные узлы (рекомендуется для Elasticache, поскольку вы не знаете, когда узлы приходят или уходят).
  • 'options': для Laravel можно указать на верхнем уровне, на уровне кластера и в опции узла. (они объединяются в Illuminate, а затем передаются Предису)
  • 'parameters': Они «переопределяют» настройки/допущения подключения по умолчанию, которые Predis использует для новых подключений. Поскольку мы устанавливаем их явно для соединения «по умолчанию», они не используются. Но для установки кластера они критичны. «Главный» узел может отправить обратно перенаправление (-MOVED), и если параметры для password и scheme не установлены, он примет значения по умолчанию, и это новое соединение с новым узлом не удастся.
person CenterOrbit    schedule 20.02.2018
comment
Отличный разбор! Кто-нибудь поправьте меня, если я ошибаюсь, но после просмотра исходного кода Laravel 5.5 верхний уровень 'cluster' => env('REDIS_CLUSTER', false), ничего не делает. Чтобы использовать кластеризацию, вам просто нужно иметь массив верхнего уровня clusters и, как упоминает @CenterOrbit, удалить конфигурацию соединения верхнего уровня default. Если Laravel найдет ключ верхнего уровня с именем вашего соединения (по умолчанию default), он не будет искать соединение в конфигурации clusters. github.com/laravel/framework/blob/ 5.5/src/Illuminate/Redis/ - person Brandon; 29.08.2018
comment
Также для каждого кластера options, о котором упоминает @CenterOrbit, требуется, чтобы вы неинтуитивно смешивали ассоциативное значение options с вашим неассоциативным массивом узлов, например: 'redis' => [ 'clusters' => [ 'default' => [ 'options' => [ 'cluster' => 'redis' ], [ 'scheme' => env('REDIS_SCHEME', 'tcp'), /* ... */ ], ], ], ] - person Brandon; 29.08.2018
comment
суть с улучшенным форматированием и дополнительной информацией, связанной с мой предыдущий комментарий. - person Brandon; 29.08.2018

Спасибо CenterOrbit!!

Я могу подтвердить, что первое решение позволяет Laravel подключаться к серверу Redis через TLS. Протестировано с Redis 3.2.6 на AWS ElastiCache с TLS, настроенным как один узел и один сегмент.

Я также могу подтвердить, что второе решение позволяет Laravel подключаться к кластеру Redis через TLS. Протестировано с Redis 3.2.6 на AWS ElastiCache с TLS, настроенным с включенным режимом кластера, 1 сегмент, 1 реплика на сегмент.

Я получил следующую ошибку, когда впервые попытался реализовать кластерное решение:

Error: Unsupported operand types

Я пропустил дополнительный набор скобок массива, когда переместил настройки «по умолчанию» в массив «кластеры».

НЕВЕРНО

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

ПРАВИЛЬНО

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

Я надеюсь, что это сэкономит кому-то еще немного времени на устранение неполадок.

person Jason Klein    schedule 14.05.2018