Вопрос или проблема
Моя проблема возникла при использовании Redis на Kubernetes, но, похоже, это не проблема самого Redis, а проблема с сетью/инфраструктурой.
Мой сценарий:
- У меня есть сервис Redis с одним подом Redis, обслуживающим его.
- Я подключаю клиент Redis к сервису.
- Я удаляю под Redis.
- Подключение клиента завершается.
- Клиент Redis пытается переподключиться.
- В это время Redis Replica Set поднимает новый под Redis, и сервис Redis начинает отвечать на запросы/создавать новые подключения.
- Однако мой существующий клиент Redis зависает на подключении (первая попытка переподключения), и так остается до истечения времени ожидания (примерно через 130 секунд).
- На второй попытке переподключения он подключается сразу.
Проблема, похоже, не возникает в моей среде разработки (локальные контейнеры Docker), потому что время ожидания появляется через секунду или две.
Также у клиента, которого я использую, нет опции настройки таймаута сокета.
- Является ли это нормальным поведением сервиса – зависание соединения до истечения времени ожидания, если нет подов для обработки запросов? Если бы он сразу отвечал ошибкой, такой проблемы бы не возникло.
- Есть ли способ настроить это время ожидания на приемлемое значение где-то (на уровне сервиса, в какой-то сетевой конфигурации и т.д.)? Скажем, 5 секунд было бы нормально.
Сервис – это абстракция в Kubernetes, которая определяет логический набор подов и политику доступа к ним. Технически, сервис – это тип ресурса Kubernetes, который настраивает прокси для перенаправления запросов к набору подов.
В вашем случае клиент Redis подключается напрямую к вашему поду Redis, используя некоторые правила брандмауэра, настроенные в сервисе. Поэтому, если сервис не трогали, проблемы с подключением могут возникнуть только на стороне пода или клиента. Поэтому вам нужно искать настройки конфигурации для них.
Ответ или решение
Проблема, которую вы описываете, связана с ожиданием таймаута TCP-клиентов при подключении к Kubernetes-сервису, когда нет доступных Pod’ов, способных обработать запросы. Давайте разберемся, что конкретно происходит на уровне инфраструктуры Kubernetes и какие механизмы здесь задействованы.
Теория
Сервис в Kubernetes — это абстракция, которая представляет собой сетевой доступ к набору Pod’ов. Сервис использует прокси, позволяющий направлять запросы к этим Pod’ам. Однако, если ни один Pod не доступен, то прокси, соответственно, не может установить соединение с конечной точкой. В вашем случае Redis-сервис связан с одним Redis Pod. Когда этот Pod удаляется, между клиентом и хостом возникает разрыв соединения.
В отсутствие доступных Pod’ов, поведение сервиса будет зависеть от конфигурации сетевой инфраструктуры и прокси. Часто такие соединения либо дожидаются восстановления Pod, либо занимают больше времени на получение ответа об ошибке, что объясняет долгое ожидание таймаута.
Пример
Рассмотрим ваш сценарий:
- Redis-сервис связан с единственным Pod.
- Клиент успешно подключается к Pod через сервис.
- Под удаляется, вызывая обрыв соединения.
- Клиент пытается переподключиться, но все доступные соединительные целевые точки временно недоступны, так как произошла регенерация Redis Pod посредством Replica Set.
- Пусть Redis-сервис становится вновь готов обрабатывать запросы сразу после появления нового Pod. Однако, первый повторный запрос клиента "зависает", так как маршрутизация на сетевом уровне не может найти доступный Pod, пока Redis Pod не станет снова доступным.
Применение
Конфигурация Services и таймаутов
-
Быстрое завершение подключения: Kubernetes-сервис, в идеале, должен быстро завершать соединение при отсутствии доступных Pod’ов. На уровне Cluster, вы можете исследовать возможность установки настроек, которые бы принуждали сервис быстро завершать соединение, если нет доступных Pod’ов. Например, использование сторонных сетевых плагинов может оказаться решением, если стандартные инструменты K8S ограничены.
-
Конфигурация таймаута на уровне клиента: Если клиент не имеет возможности конфигурировать socket timeout, подумайте о создании промежуточного слоя или использования библиотек, которые обрабатывают время ожидания. Некоторые клиенты могут поддерживать обертки или прокси, которые позволяют указывать таймауты на уровне приложения.
-
Инфраструктурные оптимизации: Поскольку Redis Replica Set управляет созданием новых Pod, проверьте, что эти процессы выполняются максимально быстро. Возможным является конфигурация autoscaling или использование проактивных механизмов мониторинга, которые реагируют на снижение количества доступных Pod’ов.
-
Мониторинг и логирование: Установите подробное логирование и мониторинг на уровне сети и приложения. Это поможет в диагностике и понимании причин временных задержек в соединениях.
-
LoadBalancer и внешние сервисы: Если у вас используется LoadBalancer, то настройка backoff межподключений или использование внешних сетевых сервисов для проверки доступности может помочь в улучшении времени реакции на недоступность Pod’ов.
-
Параллельные подключения: Подумайте над реализацией механизма параллельных подключений, который будет использовать несколько маршрутов для подключения к разным сервисам.
Подытоживая, стоит обратить внимание на различные уровни инфраструктуры и настройки, от сетевых плагинов до настроек конкретных клиентов, чтобы оптимизировать сценарии разрыва и восстановления соединений в Kubernetes. Внедрение вышеуказанных методов позволит улучшить устойчивость к временным потерям соединения и уменьшить время ожидания таймаутов.