SSE 连接期间无法禁用缓冲

SSE 连接期间无法禁用缓冲

我正在尝试从Apache2NGINX并遇到问题上交所连接。其他一切都运行良好,常规 GET 或 POST 请求均成功通过。请注意,相同的设置在 Apache2 WEB 服务器上运行良好。

但是 SSE 与 NGINX 服务器的连接存在两个关键问题:

  1. NGINX 会保留响应,直到缓冲区已满
  2. 如果 SSE 正在进行,NGINX 将阻止对服务器的任何其他请求。

使用 Apache2 时我曾经遇到过问题 #1,但通过以下配置可以轻松解决:

OutputBufferSize 0

问题 #2 确实阻碍了我使用 NGINX。为什么 SSE 进行时服务器会阻止其他连接?如何解决此问题?

restconf应用程序是一个 HTTP/REST 瘦客户端应用程序,由 WEB 服务器中的 FastCGI 模块调用,为指定的用户或 SSE 流启动单个请求会话。

client <-> WEB server <-> restconf <-> subsystem netconf server

我发现无论我的配置设置如何,NGINX 都会继续缓冲我的 SEE 输出。我尝试使用以下方法:

  • 环境fastcgi_buffering 关闭在站点配置位置;
  • 环境fastcgi_request_buffering 关闭在站点配置位置;
  • 将标头设置为X-Accel-Buffering:无在我的 restconf 应用程序和客户端请求中。

什么都没用。奇怪的是缓冲设置根本不起作用。无论配置如何,缓冲区的大小都保持不变:

  • fastcgi_buffer_size 是4k;
  • fastcgi_buffers 4 4k;
  • fastcgi_busy_buffers_大小:8k;

当我更改上述设置时,实际程序运行中没有任何变化。整个事件流等待在 NGINX 中发送,无论是应用程序完成/终止后还是缓冲区已满(如果缓冲区的大小始终相同,则上述设置不会改变其大小)

    nginx -V

nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020 (running with OpenSSL 1.1.1g  21 Apr 2020)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-5J5hor/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC'
--prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf
--http-log-path=/var/log/nginx/access.log
--error-log-path=/var/log/nginx/error.log
--lock-path=/var/lock/nginx.lock
--pid-path=/run/nginx.pid
--modules-path=/usr/lib/nginx/modules
--http-client-body-temp-path=/var/lib/nginx/body
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi
--http-proxy-temp-path=/var/lib/nginx/proxy
--http-scgi-temp-path=/var/lib/nginx/scgi
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi
--with-debug
--with-compat
--with-pcre-jit
--with-http_ssl_module
--with-http_stub_status_module
--with-http_realip_module
--with-http_auth_request_module
--with-http_v2_module
--with-http_dav_module
--with-http_slice_module
--with-threads
--with-http_addition_module
--with-http_gunzip_module
--with-http_gzip_static_module
--with-http_image_filter_module=dynamic
--with-http_sub_module
--with-http_xslt_module=dynamic
--with-stream=dynamic
--with-stream_ssl_module
--with-mail=dynamic
--with-mail_ssl_module

NGINX 服务器配置:

server {
    listen 80;
    listen [::]:80;

    root /var/www/yang-api;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name localhost;

    # need to install fcgiwrap to use RESTCONF
    # set SCRIPT_FILENAME to the location of the restconf program
    location /restconf {
    
        fastcgi_param  SCRIPT_NAME restconf;
        fastcgi_param  SCRIPT_FILENAME /var/www/yang-api/restconf;
        fastcgi_pass unix:/var/run/fcgiwrap.socket;

        include /etc/nginx/fastcgi_params;
   
        allow all;

    #   HAS EFFECT
        ## This is the maximum time limit for request handling.
        ## If a FastCGI request does not complete within this timeout
        ## seconds, it will be subject to termination.
        ## Set to big number if SSE used
        fastcgi_read_timeout 120s;

    #   NO EFFECT
        fastcgi_buffering off;
        fastcgi_request_buffering off;
    }
}

答案1

这里的问题是 fcgiwrap 进程,它一直保留缓冲区,直到应用程序终止或缓冲区已满。我通过在 /location 中添加以下几行解决了这个问题:

### When set (e.g., to ""), disables output fastcgiwrap buffering.
### MUST be set if SEE used
fastcgi_param NO_BUFFERING "";

### When buffering is disabled, the response is passed to a
### client synchronously, immediately as it is received.
### Nginx will not try to read the whole response from the
### FastCGI server.
### MUST be set if SEE used
fastcgi_buffering off;

第二个问题也是由于 fcgiwrap 造成的。正如这里讨论的那样https://stackoverflow.com/a/66099376/5555750

我必须破解 /etc/init.d/fcgiwrap 并更改 DAEMON_OPTS 变量并强制脚本停止,然后在输入时使用新参数重新启动服务:

sudo /etc/init.d/fcgiwrap 重新加载

这将重新加载 fcgiwrap,以便它可以同时处理多个请求。

相关内容