Эффективное устранение распространенных ошибок подключения к Redis
Боретесь с проблемами подключения к Redis? Это практическое руководство содержит четкие шаги для диагностики и устранения распространенных ошибок, таких как 'Connection Refused', 'Timeouts' и 'Authentication Failures'. Узнайте, как проверить статус сервера, сетевые конфигурации, брандмауэры и показатели производительности Redis. Включает практические примеры для `redis-cli` и клиентских библиотек, чтобы быстро восстановить ваши подключения к Redis.
Эффективное устранение распространенных ошибок подключения к Redis
Ошибки подключения к Redis обычно становятся понятными, если разделить их на три вопроса: может ли клиент достичь хоста и порта, принимает ли Redis подключение, и разрешено ли клиенту выполнять команды после подключения?
Делайте это по порядку. Прыгать сразу в код приложения — пустая трата времени, когда Redis остановлен. Перестраивать правило брандмауэра — пустая трата времени, когда пароль неверен. Небольшой повторяемый контрольный список быстрее приведет вас к реальной неисправности.
Сначала протестируйте из того же места, что и приложение
Тестирование с вашего ноутбука полезно, но оно не доказывает, что под Kubernetes, VM, контейнер или CI-раннер может достичь Redis. Начните внутри той же сетевой локации, что и неисправное приложение.
redis-cli -h redis.example.internal -p 6379 PING
Ожидаемый вывод:
PONG
Если Redis требует TLS, используйте параметры TLS, которые ожидает ваше развертывание:
redis-cli --tls -h redis.example.internal -p 6380 PING
Если Redis требует аутентификации:
redis-cli -u redis://app-user:[email protected]:6379 PING
Будьте осторожны с паролями в истории оболочки. Для продакшена используйте временные учетные данные или переменные окружения, когда это возможно.
Connection refused
ECONNREFUSED, Connection refused или Could not connect to Redis обычно означает, что TCP-соединение достигло целевого хоста, но ничто не приняло его на этом порту. Наиболее распространенные причины просты:
- Redis не запущен.
- Клиент использует неверный хост или порт.
- Redis привязан только к localhost.
- Маппинг контейнера или сервиса указывает на неверный порт.
- Брандмауэр активно отклоняет соединение.
На хосте Redis проверьте процесс и слушатель:
redis-cli PING
ps aux | grep '[r]edis-server'
ss -ltnp | grep redis
Вы хотите увидеть Redis, слушающий на ожидаемом адресе и порту, обычно 127.0.0.1:6379, 0.0.0.0:6379 или адрес частного интерфейса.
Проверьте redis.conf или действующую конфигурацию:
redis-cli CONFIG GET bind
redis-cli CONFIG GET port
redis-cli CONFIG GET protected-mode
Если bind установлен в 127.0.0.1, удаленные клиенты не могут подключиться напрямую. Это часто намеренно. Не меняйте его на 0.0.0.0 в качестве быстрого исправления, если Redis не защищен аутентификацией, ACL, правилами брандмауэра и частными сетями. Redis, открытый в публичный интернет, — это серьезный инцидент безопасности, который ждет своего часа.
В Docker помните о разнице между портом контейнера и портом хоста:
docker ps
docker port <redis-container>
Внутри сети Docker Compose приложения обычно подключаются к имени сервиса и внутреннему порту:
redis://redis:6379
С хоста они могут подключаться к опубликованному порту, такому как localhost:6379 или localhost:6381, в зависимости от маппинга.
Connection timeout
Таймаут означает, что клиент ждал и не завершил операцию вовремя. В отличие от отклоненных соединений, таймауты часто указывают на проблему с путем или перегруженный сервер.
Проверьте TCP-путь:
nc -vz redis.example.internal 6379
ping -c 5 redis.example.internal
ping не идеален, потому что ICMP может быть заблокирован, пока TCP работает, но он может выявить очевидные ошибки DNS или маршрутизации. nc ближе к тому, что нужно клиенту Redis.
Если TCP подключается, но команды Redis истекают по таймауту, проверьте, не занят ли Redis:
redis-cli INFO clients
redis-cli INFO stats
redis-cli INFO memory
redis-cli SLOWLOG GET 10
redis-cli LATENCY DOCTOR
Ищите заблокированных клиентов, большое количество подключенных клиентов, память, близкую к maxmemory, своп на хосте, медленные команды и события задержки. Одна дорогостоящая команда, такая как KEYS *, большой HGETALL или длинный Lua-скрипт, может задержать несвязанных клиентов, поскольку выполнение команд Redis в основном однопоточное.
Также проверьте настройки таймаута клиента. Некоторые библиотеки используют короткие значения по умолчанию для таймаутов подключения или таймаутов команд. Увеличение таймаута может уменьшить количество ложных сбоев в медленной сети, но это не должно скрывать перегруженный экземпляр Redis. Если простой PING занимает секунды с хоста приложения, исправьте это, прежде чем настраивать повторные попытки.
Проблемы с разрешением имен и неверной конечной точкой
Не каждая ошибка подключения связана с Redis. DNS и обнаружение сервисов вызывают их множество.
С хоста приложения:
getent hosts redis.example.internal
nslookup redis.example.internal
В Kubernetes:
kubectl exec -it deploy/my-app -- sh
getent hosts redis.default.svc.cluster.local
nc -vz redis.default.svc.cluster.local 6379
Проверьте, использует ли приложение конечную точку реплики чтения, конечную точку Sentinel, конечную точку кластера или прямую конечную точку узла. Клиентам Redis Cluster нужны библиотеки, учитывающие кластер, потому что ключи могут принадлежать разным слотам, и команды могут получать перенаправления. Клиент, не учитывающий кластер, может успешно подключиться, а затем выдать ошибки MOVED или ASK, как только отправит реальные команды.
Ошибки аутентификации
Сбои аутентификации проявляются как:
NOAUTH Authentication requiredWRONGPASS invalid username-password pairNOPERM this user has no permissions- Исключения аутентификации, специфичные для клиентской библиотеки
Для Redis 6 и новее распространены пользователи ACL. Строка подключения может потребовать как имя пользователя, так и пароль:
redis://app-user:[email protected]:6379/0
С пользователем по умолчанию некоторые клиенты используют только пароль:
redis://:[email protected]:6379/0
Проверьте активную конфигурацию пользователя, если у вас есть доступ администратора:
redis-cli ACL LIST
redis-cli ACL GETUSER app-user
NOAUTH означает, что клиент не прошел аутентификацию перед выполнением команды. WRONGPASS означает, что аутентификация была предпринята, но отклонена. NOPERM означает, что аутентификация прошла успешно, но у пользователя нет разрешения на команду, шаблон ключа или канал Pub/Sub.
Когда секреты меняются, убедитесь, что каждый запущенный процесс действительно получил новое значение. В контейнерных платформах обновление объекта секрета не всегда перезапускает существующие поды или процессы. Частая реальная ошибка — половина приложения использует новый пароль, а половина все еще использует старый.
Несоответствие TLS
Ошибки TLS могут выглядеть как сбросы соединения, таймауты или нечитаемые ошибки протокола.
Проверьте порт. Управляемые сервисы часто используют разные порты для TLS и non-TLS Redis. Например, одна конечная точка может ожидать обычный протокол Redis, а другая — TLS с первого байта.
Протестируйте с помощью:
redis-cli --tls -h redis.example.internal -p 6380 PING
redis-cli -h redis.example.internal -p 6379 PING
Если ваша организация использует частные сертификаты, клиенту также может понадобиться файл CA:
redis-cli --tls --cacert /path/to/ca.pem -h redis.example.internal -p 6380 PING
В журналах приложений ошибки сертификата часто более понятны, чем исключение Redis верхнего уровня. Ищите сообщения о неизвестных центрах сертификации, просроченных сертификатах, несоответствии имени хоста или сбое рукопожатия.
Слишком много подключений
У Redis есть лимит maxclients. У операционной системы также есть лимиты файловых дескрипторов. Когда любой из них исчерпан, новые клиенты могут не подключаться, а существующие могут работать некорректно.
Проверьте:
redis-cli INFO clients
redis-cli CONFIG GET maxclients
ulimit -n
Полезные поля включают connected_clients, blocked_clients и rejected_connections из INFO stats.
Слишком много подключений обычно возникает из-за одного из следующих шаблонов:
- Создание нового клиента Redis для каждого веб-запроса.
- Незакрытие клиентов в краткосрочных заданиях.
- Слишком много рабочих процессов, каждый со своим большим пулом.
- Подписки Pub/Sub, заимствующие подключения из обычного пула команд.
- Штормы повторных попыток во время перезапуска Redis.
Исправьте форму приложения, прежде чем повышать лимиты. Используйте одного общего клиента или ограниченный пул на процесс. Добавьте задержку с джиттером при повторном подключении, чтобы каждый экземпляр не переподключался в одну и ту же миллисекунду после сбоя.
Защищенный режим и настройки привязки
Защищенный режим Redis предназначен для уменьшения ущерба от случайного раскрытия. Если Redis привязан широко и не имеет аутентификации, защищенный режим может отклонять удаленные подключения.
Проверьте:
redis-cli CONFIG GET protected-mode
redis-cli CONFIG GET bind
redis-cli CONFIG GET requirepass
Не отключайте защищенный режим только для того, чтобы удаленное подключение заработало. Более безопасный путь обычно — частная сеть плюс аутентификация и узкий адрес привязки. Если Redis должен принимать удаленных клиентов, поместите его в частную подсеть, ограничьте исходные IP-адреса, требуйте учетные данные и используйте TLS, где это уместно.
Практический порядок действий
Когда приложение не может подключиться, используйте эту последовательность:
- Из среды приложения выполните
redis-cli PINGк тому же хосту и порту. - Если отказано, проверьте процесс Redis, слушатель, привязку, порт и маппинг контейнера.
- Если таймаут, проверьте маршрутизацию, правила брандмауэра, загрузку сервера, медленные команды и настройки таймаута клиента.
- Если аутентификация не удалась, проверьте имя пользователя, пароль, разрешения ACL и развертывание секретов.
- Если не удаются только некоторые команды, проверьте разрешения команд/ключей ACL и перенаправления Redis Cluster.
- Если сбои происходят под нагрузкой, проверьте количество подключений, размер пула, повторные попытки и метрики ресурсов сервера.
Устранение неполадок подключения — это в основном сбор доказательств. Получите чистый результат CLI из того же места, что и приложение, затем сравните его с тем, что делает клиентская библиотека. Как только эти два пути расходятся, разрыв обычно виден: отсутствующий флаг TLS, старый пароль, неверное имя сервиса или пул, который создает гораздо больше подключений, чем Redis был рассчитан обрабатывать.
Чтение ошибок приложения без излишней реакции
Клиентские библиотеки оборачивают ошибки Redis в свой собственный язык. Сервис Node.js может показывать ECONNRESET, Python-воркер может показывать redis.exceptions.ConnectionError, а Java-сервис может сообщать о таймауте получения из пула. Все они могут описывать разные слои одной и той же проблемы.
Разделите их:
- Таймаут подключения: TCP-соединение не завершилось достаточно быстро.
- Таймаут чтения: соединение существует, но ответ на команду не пришел вовремя.
- Сброс соединения: соединение было закрыто Redis, прокси, сетью или пиром.
- Таймаут пула: приложение не смогло получить подключение к Redis из своего собственного пула.
- Ошибка аутентификации: Redis отклонил учетные данные или разрешения.
Таймаут пула легко ошибочно принять за сбой Redis. Иногда Redis в порядке, но приложение заняло все подключения пула и никогда их не вернуло. Неправильное использование Pub/Sub может вызвать это. Также длинные блокирующие команды, обработчики запросов, которые забывают закрывать клиентов, или пул, слишком маленький для параллелизма процесса.
Проверяйте обе стороны одновременно. В приложении проверьте метрики пула, если библиотека их предоставляет: активные подключения, бездействующие подключения, ожидающие, количество повторных попыток. В Redis проверьте:
redis-cli INFO clients
redis-cli CLIENT LIST | head
Если Redis показывает лишь горстку клиентов, а приложение говорит, что его пул исчерпан, проблема, вероятно, внутри процесса приложения. Если Redis показывает тысячи подключений от одного и того же развертывания, сервис может создавать клиентов слишком часто.
Повторные попытки заслуживают особого внимания. Цикл переподключения без задержки может превратить короткую перезагрузку Redis в шторм. Каждый экземпляр приложения пытается переподключиться немедленно, аутентификация и рукопожатия TLS взлетают, и Redis приходится восстанавливаться, находясь под шквалом клиентов. Используйте экспоненциальную задержку с джиттером. Также решите, какие команды безопасно повторять. Повторение идемпотентного кэш-GET отличается от повторения записи, которая могла уже быть успешной до разрыва соединения.
Для заметок об инцидентах фиксируйте точный текст ошибки и время. «Redis был недоступен» часто неверно. «С 14:03 до 14:06 UTC поды приложения видели таймауты чтения, в то время как CPU Redis был на одном ядре, а SLOWLOG показывал большие вызовы `HGETALL» — это уже действенно.