Я создал шлюз API для своего приложения, и он будет действовать как передний контроллер для других микросервисов. В моей производственной настройке я использую Nginx в качестве обратного прокси-сервера для своего шлюза.
Шлюз API работает на порту 8080.
Nginx настроен следующим образом:
шлюз-api.conf:
server {
listen 80;
server_name api.example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://localhost:30010/;
keepalive_timeout 500s;
}
keepalive_timeout 500s;
access_log /var/log/nginx/api.log;
error_log /var/log/nginx/api_error.log;
}
Настройка таймаута в nginx.conf:
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
Файл градиента Spring Cloud Gateway:
compile('org.springframework.cloud:spring-cloud-starter-gateway')
compile('org.springframework.cloud:spring-cloud-starter-openfeign')
compile("org.springframework.boot:spring-boot-starter-actuator")
compile('org.springframework.boot:spring-boot-starter-security')
springBootVersion=2.0.3.RELEASE
springDMPVersion=1.0.4.RELEASE
springPlatformBomVersion=Cairo-SR2
springCloudVersion=Finchley.RELEASE
Приложение шлюза:
@SpringBootApplication
@ComponentScan(basePackages = {"com.example"})
@EntityScan(basePackages = {"com.example"})
@EnableFeignClients(basePackages = "com.example")
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
Постановка задачи:
В одном из моих микросервисов выполнение одного REST API занимает более 3 минут.
Если я вызову этот API через nginx(api.example.com), он выдаст ошибку ровно через 1 минуту и выдаст HTTP-статус 504.
завиток:
curl --request GET \
--url http://api.example.com/hellomicroservice/api/take/moretime
ошибка:
504 Timeout while reading the response from Server
Журналов ошибок в nginx или шлюзе API нет.
Лог доступа из nginx:
203.129.213.102 - - [01/Apr/2019:08:14:33 +0000] "GET hellomicroservice/api/take/moretime HTTP/1.1" 499 0 "-" "PostmanRuntime/7.3.0"
Но когда я делаю вызов того же API непосредственно к шлюзу (на порту шлюза 8080), запрос обрабатывается успешно.
curl с портом шлюза:
curl --request GET \
--url http://api.example.com:8080/hellomicroservice/api/take/moretime
Редактировать:
Если я применяю настройки времени ожидания Nginx менее 60 секунд (например, 30 секунд), время ожидания запроса истекает через указанный интервал времени. Но если я установлю время ожидания Nginx более 60 секунд, скажем, 300 секунд, время ожидания запроса истекает через 60 секунд.
Нет журналов ошибок в nginx и шлюзе, добавлены журналы доступа
вы можете попробовать добавить proxy_read_timeout 300s; в блоке сервера server { proxy_read_timeout 300s;
@RadhaMohanMaheshwari Пробовал, не работает
вы можете попробовать заменить localhost: 8080 в настройках nginx на api.example.com: 8080?
В производственном развертывании мы используем AWS EKS, и мы не получаем эту проблему в производстве с теми же файлами конфигурации.




Кажется, что тайм-ауты запросов не являются для вас проблемой. Это тайм-аут соединения. Я думаю, нам нужно посмотреть на заголовок
Connection
Насколько я знаю, заголовок Connection определяет, что соединение должно быть постоянным или кто имеет право поддерживать/закрывать его. Если соединение было keep-alive , то соединение будет постоянным. Для поддерживающих соединений клиент время от времени отправляет TCP-пинг, чтобы убедиться, что сервер все еще активен и удерживает соединение. В соответствии с завиток это время по умолчанию составляет каждые 60 секунд.
Теперь nginx необходимо настроить для приема соединений и поддержания его активности некоторое время с помощью директивы keepalive_timeout. Если этого нет, то nginx не будет поддерживать связи живыми.
Это должно быть причиной того, что nginx пишет в логах 499. HTTP499 — это ошибка cutom в nginx, которая говорит о том, что клиент закрыл соединение. В вашем случае curl закрыл его. Почему curlзакрыл? потому что nginx не ответил на 60-секундный TCP-пинг, так как не включена поддержка активности.
Добавление keepalive_timeout к ~ 500 или более высокому значению, чем время ожидания приложения, должно решить вашу проблему.
Теперь, почему это работало с котом напрямую? Я думаю, что Spring позволяет живому тайм-ауту быть бесконечным или очень высоким значением. Обычно в tomcat также 60 секунд.
Надеюсь, это решит вашу проблему.
Настройка keepalive_timeout 500; не сработала, та же ошибка Когда я проверил заголовок ответа, я нашел заголовок соединения как Connection →close
Установите как keepalive_timeout 500s; Держите его в разделе сервера или в локации. Я думаю, что единица 's' должна быть там.
попробовал после ввода раздела сервера и местоположения с keepalive_timeout 500s;, но та же ошибка
Может быть, вам стоит попробовать вариант --no-keepalive в curl. Я предполагаю, что Nginx не соблюдает постоянное соединение. Вы также можете проверить то же самое с некоторыми другими клиентами, такими как http-client/Fiddler или любым другим, если на то пошло. Использование keep-alive полезно только в том случае, если вы выполняете несколько операций с одним и тем же соединением.
Connection просто сообщает исходному серверу, что делать с TCP-сокетом после завершения ответа, идея заключается в том, что клиент будет отправлять дальнейшие запросы по потоку. В данном случае это будет между curl/postman и nginx. Я думаю, что более вероятно, что nginx просто надоедает и убивает запрос, что странно, так как read_timeout составляет 5 минут.
Keepalive может быть не включен для восходящего потока из-за того, что в вашей конфигурации отсутствует ключ proxy_http_version.
Цитата: https://www.nginx.com/blog/tuning-nginx/#proxy_http_версия
To enable keepalive connections to upstream servers you must also include the following directives in the configuration:
proxy_http_version 1.1;
proxy_set_header Connection "";
Я бы также сохранил keepalive_timeout в конфигурации, как предложил Крис.
Возможно, у вас проблема с форматированием. Примеры конфигураций показывают, что блок «сервер» обычно заключен в блок «http { }», а ключ «keepalive_timeout» обычно является дочерним элементом блока http, а не блока сервера или местоположения. Вы можете проверить свои другие ключи, чтобы убедиться, что все они также находятся под правильным родителем. Кроме того, у вас есть несколько активных конфигураций nginx в каталоге конфигурации?
Попробуйте поместить свои настройки тайм-аута в /etc/nginx/conf.d/timeout.conf (если его там нет, создайте его). Установите ниже настройки,
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
Я предполагаю, что это одна из проблем, которые могут возникнуть из-за многих других вещей. Это решение сработало для меня (я также получал ошибки в /var/log/nginx/error.log:
2020/12/30 21:47:47 [error] 26765#26765: *13064 upstream timed out (110: Connection timed out) while connecting to upstream, client: XXX, server: example.com, request: "GET /eshop HTTP/1.0", upstream: "http://[::1]:8080/error_50x.html", host: "example.com"
Как ни странно, этого не происходило на моем ноутбуке, а только на моем сервере. Итак, я проверил IP-адреса, и оказалось, что это может быть из-за отсутствия адреса :: 1. Когда я добавил его к сетевому устройству вот, я не смог воспроизвести тайм-ауты.
sudo ip a add ::1/128 dev lo
Далее: (это мое понимание, я не уверен в этом на 100%:) Кроме того, поскольку накладные расходы на сохранение соединения с службой Java локального хоста кажутся выше, чем просто разрыв этого соединения и повторное соединение при выполнении другого запроса, рекомендуется использовать следующие настройки для прокси (в .conf вашего сайта nginx):
proxy_http_version 1.1;
proxy_set_header Connection "";
какой журнал ошибок на шлюзе API и журнал ошибок nginx, когда вы
curlчерез обратный прокси?