nginx Rails - ActionCable偶尔无法订阅

lc8prwob  于 2023-05-16  发布在  Nginx
关注(0)|答案(1)|浏览(111)

我正在为一个现有的大型Rails应用程序添加WebSocket支持。我从一个简单的测试开始,只是为了确保它可以处理我们的生产负载-我们需要支持数千个活动连接,例如通知或聊天通道,每个活动连接对应于站点上的每个活动用户。
我已经部署了代码,它只是在页面加载时创建一个新的“PerfTestChannel”订阅:

App.cable.subscriptions.create('PerfTestChannel', ...)

它只为当前用户流:

class PerfTestChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

在低流量下,它似乎工作得很好。它创建订阅并确认它:

然而,在较高的流量下,它会偶尔无法订阅该频道,并且spam subscribe每秒无限期地重试两次:

我不知道为什么会失败,以及如何修复它。这很奇怪,因为如图所示,ping消息仍在成功传输,因此电缆连接显然是打开的。它只是不会订阅PerfTestChannel
我们使用的是标准的Redis适配器设置。在测试中,我们有大约200个开放连接:

irb(main):016:0> Redis.new.pubsub("channels", "action_cable/*").count
=> 211

我们在生产日志中看到一些与Web套接字相关的错误:

第一个错误似乎不相关,因为(如上所述)很明显WebSocket升级是成功的,因为ping正在顺利进行。
第二个错误似乎是相关的。它是从源头的这一点来的:https://github.com/rails/rails/blob/main/actioncable/lib/action_cable/connection/base.rb#L94
不过,我不知道WebSocket是如何关闭的,因为ping的事情。所以,这也可能是一个红鲱鱼错误?
我们正在通过nginx-ingress使用负载平衡,它声称除了将超时提高到1小时之外,不需要任何特殊的websockets配置,我们已经这样做了,但无济于事。

kjthegm6

kjthegm61#

我想你可以试着做两个改变
1.增加Redis连接的数量。您可以通过在config/cable.yml文件中设置pool_size选项来完成此操作,如下所示:

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  pool_size: 50

1.检查您的nginx-ingress配置。检查proxy_read_timeoutproxy_send_timeout值是否设置为足够高的值(例如1小时),并且proxy_http_version值设置为1.1。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
spec:
  rules:
    - host: mydomain.com
      http:
        paths:
          - path: /websocket
            backend:
              serviceName: my-service
              servicePort: 80

相关问题