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 раздел для сервера 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 ответ

  1. Я не думаю, что вам понадобятся пассажирские липкие сессии на балансировщике нагрузки

  2. В этом блоге рассматриваются соответствующие настройки WebSocket для NGINX. Конфигурация WebSocket необходима на балансировщике нагрузки, а также на веб-сервере, если вы хотите передать заголовки Upgrade и Connection в приложение rails.

Другие вопросы по тегам