Rails 4 + Websocket-rails + Passenger + Nginx + Балансировщик нагрузки
Я добавил некоторые функции в пару наших веб-приложений, которым нужны websocket-rails. В разработке все работает нормально, но я не уверен, как развернуть все это в нашей производственной среде, поскольку это немного сложнее.
Производственная установка:
- 1 сервер используется в качестве балансировщика нагрузки (Nginx).
- 2 сервера, используемые в качестве веб-серверов, где наши приложения rails работают с использованием Nginx и Passenger (оба сервера идентичны).
- Несколько других серверов, используемых серверами приложений, но я считаю, что они не имеют отношения к этому вопросу.
- Все сайты работают по HTTPS.
Конфигурации балансировщика нагрузки
Вот пример для одного из сайтов, остальные имеют похожие конфиги:
upstream example {
ip_hash;
server xx.xx.xx.xx:443;
server xx.xx.xx.xx:443;
}
server {
listen 80;
listen 443 ssl;
ssl on;
ssl_certificate /etc/nginx/ssl/example.chained.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
server_name example.com;
rewrite ^(.*) https://www.example.com$1 permanent;
}
server {
listen 80;
listen 443 ssl;
ssl on;
ssl_certificate /etc/nginx/ssl/example.chained.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
server_name www.example.com;
if ($ssl_protocol = "") {
rewrite ^ https://$server_name$request_uri? permanent;
}
client_max_body_size 2000M;
location /css { root /home/myuser/maintenance; }
location /js { root /home/myuser/maintenance; }
location /img { root /home/myuser/maintenance; }
location /fonts { root /home/myuser/maintenance; }
error_page 502 503 @maintenance;
location @maintenance {
root /home/myuser;
if ($uri !~ ^/maintenance/) {
rewrite ^(.*)$ /maintenance/example.html break;
}
}
location / {
proxy_pass https://example;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Конфиги веб-сервера
Опять же, вот пример для одного из сайтов, остальные имеют похожие конфиги:
server {
server_name example.com;
rewrite ^(.*) https://www.example.com$1 permanent;
}
server {
listen 80;
listen 443 ssl;
ssl on;
ssl_certificate /etc/nginx/ssl/example.chained.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
root /var/www/example/public;
server_name www.example.com;
if ($ssl_protocol = "") {
rewrite ^ https://$server_name$request_uri? permanent;
}
client_max_body_size 2000M;
passenger_enabled on;
rails_env production;
passenger_env_var SECRET_KEY_BASE "SOME_SECRET";
}
Что я собрал до сих пор:
- Мне нужно включить пассажирские сессии
- Мне нужно создать
location
на сайтеserver
раздел, где сервер websocket слушает. - Мне нужно переопределить одновременные запросы пассажиров на местоположение веб-розетки без ограничений.
Мои вопросы:
- Нужно ли включать сеансы закрепления пассажиров также в конфигах балансировщика нагрузки? Я предполагаю, что это только для веб-серверов.
- Как бы
location
раздел для сервера websocket выглядит? - Нужно ли создавать веб-сокет
location
раздел также о балансировке нагрузки? - Достаточно ли проводить липкие сессии, чтобы синхронизировать различные приложения и серверы?
- У меня на каждом сервере запущены различные приложения, и все они должны получать одинаковые уведомления (сообщения сокетов), поэтому все они должны подключаться к одному и тому же серверу веб-сокетов (я полагаю). Теперь, когда websocket-rails является частью их гемсетов, не будет ли каждое приложение пытаться создать свой собственный сервер websocket? Если так, как я могу предотвратить это и заставить их порождать только одного, если ни один еще не запущен?
Как вы можете заметить, я довольно озадачен тем, как websocket-rails работает с пассажирским и nginx в производстве, поэтому даже если у вас нет ответов на все вопросы, любой вклад очень важен!
ОБНОВИТЬ
Я пробовал следующее на балансировщике нагрузки:
upstream websocket {
server xx.xx.xx.xx:443;
server xx.xx.xx.xx:443;
}
location /websocket {
proxy_pass https://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#also tried with this:
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "upgrade";
}
и на серверах приложений:
location /websocket {
proxy_pass https://www.example.com/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#also tried with this:
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "upgrade";
}
На стороне клиента я подключаюсь к URL WebSocketRails('www.example.com/websocket');
и я получаю следующую ошибку:
WebSocket connection to 'wss://www.example.com/websocket' failed: Error during WebSocket handshake: Unexpected response code: 404
Есть идеи?
1 ответ
Я не думаю, что вам понадобятся пассажирские липкие сессии на балансировщике нагрузки
В этом блоге рассматриваются соответствующие настройки WebSocket для NGINX. Конфигурация WebSocket необходима на балансировщике нагрузки, а также на веб-сервере, если вы хотите передать заголовки Upgrade и Connection в приложение rails.