Rails 4 + Websocket-rails + Passenger + Nginx + 负载均衡器

Posted

技术标签:

【中文标题】Rails 4 + Websocket-rails + Passenger + Nginx + 负载均衡器【英文标题】:Rails 4 + Websocket-rails + Passenger + Nginx + Load balancer 【发布时间】:2017-01-15 18:18:21 【问题描述】:

我已经为我们的几个需要 websocket-rails 的网络应用程序添加了一些功能。在开发中一切正常,但我不确定如何在我们的生产环境中部署所有这些,因为它有点复杂。

生产设置:

1 个服务器用作负载平衡器 (nginx)。 2 台服务器用作 Web 服务器,我们的 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";

到目前为止我收集到的内容:

我需要启用passenger sticky sessions 我需要在网站的server 部分创建一个location,Websocket 服务器正在侦听该部分。 我需要override the concurrent requests 的乘客才能将 websocket 位置设置为无限制。

我的问题:

我是否还必须在负载平衡器的配置中启用乘客粘性会话?我猜这仅适用于网络服务器。 websocket 服务器的location 部分是什么样的? 我是否还必须在负载平衡器上创建 websocket location 部分? 拥有粘性会话就足以使各种应用程序和服务器保持同步? 我在每台服务器上运行了各种应用程序,它们都应该接收相同的通知(套接字消息),因此它们都应该连接到同一个 websocket 服务器(我猜)。现在 websocket-rails 是他们 gemsets 的一部分,每个应用程序不会尝试生成自己的 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】:

    我认为您不需要负载平衡器上的乘客粘性会话

    blog 涵盖了 NGINX 的相关 WebSocket 配置。您需要负载均衡器上的 WebSocket 配置,如果您想将 Upgrade 和 Connection 标头传递给 rails 应用程序,还需要 Web 服务器上的配置。

【讨论】:

感谢您的输入,请查看我的更新以了解我到目前为止的内容。 我能看到的所有相关信息都在访问日志中:负载均衡器上的"GET /websocket HTTP/1.1" 404 731 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36" 哦,我在应用服务器上也看到了同样的情况 您的 NGINX 配置似乎是正确的。我的猜测是乘客侧配置错误。乘客日志中是否有任何错误? 好吧,我找不到任何乘客日志,但查看应用服务器上 rails 应用程序的production.log,我没有发现任何问题,甚至没有 404

以上是关于Rails 4 + Websocket-rails + Passenger + Nginx + 负载均衡器的主要内容,如果未能解决你的问题,请参考以下文章

websocket-rails,websocket握手错误

gem“websocket-rails”及其可扩展性

从 rails runner 内部触发/订阅 websocket-rails 事件

websocket-rails 在生产中没有连接

Websocket-Rails 和 IE 8

无法在生产服务器上为 websocket-rails 启动独立服务器