对接AI大模型之nginx代理配置SSE接口
一、背景在对接AI大模型的时候采用流式输出可以较好地缓解用户等待的焦虑但是接口极其容易超时。前端这时候会一直报错Expected content-type to be text/event-stream, Actual: text/html而后端的错误显示是客户端断开了连接。这里摘录其中的一段错误信息如果你也遇到该错误希望本文可以帮助到你。Caused by: java.io.IOException: Broken pipe at java.base/sun.nio.ch.SocketDispatcher.writev0(Native Method)~[na:na]at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:66)~[na:na]at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:227)~[na:na]at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:158)~[na:na]at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:574)~[na:na]at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:162)~[xnio-nio-3.8.16.Final.jar!/:3.8.16.Final]at io.undertow.conduits.IdleTimeoutConduit.write(IdleTimeoutConduit.java:130)~[undertow-core-2.3.18.Final.jar!/:2.3.18.Final]二、架构图不通过内网域名访问后端服务三、排查过程1、机房B的nginx配置第一个被怀疑的对象是机房B的nginx超时时长因为sse接口总是60秒即超时。机房A的nginx,我看全局的配置nginx.conf已把连接超时调整为600秒。vi /etc/nginx/nginx.conf而接口每到了60秒的时候就断开了。这一点从机房B的nginx可以看到。所以我们尝试改大机房B的nginx的超时ingress的配置见下apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/proxy-connect-timeout:600nginx.ingress.kubernetes.io/proxy-read-timeout:600nginx.ingress.kubernetes.io/proxy-send-timeout:600它无需重启热加载配置生效。2、机房A的nginx既然机房B的nginx超时不能解决问题试着从源头来排查。首先在机房A通过IP地址访问不通过内网域名访问机房B的后端服务。尝试后无果。在机房A无论通过内网域名还是IP地址测试后端服务的接口都不会出现60秒即超时的异常。curl-w\n 耗时统计 \nDNS解析: %{time_namelookup}s\nTCP连接: %{time_connect}s\nSSL握手: %{time_appconnect}s\n首字节: %{time_starttransfer}s\n总耗时: %{time_total}s\nHTTP状态: %{http_code}\n\-XPOST\-HAccept:text/event-stream\-HContent-Type:application/json\-d...略\http://内网域名/api/v1/pub/.../chat/messages\-o/dev/null\-s你可以通过curl进行测试这一点很关键可以排查非机房B的问题。既然是机房A的问题那就转换下思路。因为机房B的后端服务原本是kong代理对外提供服务正常的不同的是机房A现在是使用nginx代理。3、nginx配置试着单独配置sse接口的反向代理见下location ~ ^/ai(/api/v1/pub/.../chat/messages)${proxy_pass http://10.xxx.xxx.196:7209$1;proxy_http_version1.1;proxy_set_header Connection;# sse 关闭缓存proxy_buffering off;proxy_cache off;chunked_transfer_encoding on;proxy_connect_timeout 600s;proxy_send_timeout 600s;proxy_read_timeout 600s;send_timeout 30s;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;}其他接口则走默认location /ai/{# 注意host末尾要加斜杆,否则访问后端接口的地址会被追加/aiproxy_pass http://10.xxx.xxx.196:7209/;}当然proxy_pass 也可以配置内网域名。经测试前端访问sse接口终于不会60秒即断开了。三、测试验证同样通过curl工具对外网接口进行测试。curl-w\n 耗时统计 \nDNS解析: %{time_namelookup}s\nTCP连接: %{time_connect}s\nSSL握手: %{time_appconnect}s\n首字节: %{time_starttransfer}s\n总耗时: %{time_total}s\nHTTP状态: %{http_code}\n\-XPOST\-HAccept:text/event-stream\-HContent-Type:application/json\-d...略\http://外网域名/api/v1/pub/.../chat/messages\-o/dev/null\-s 耗时统计 DNS解析: 0.012sTCP连接: 0.024sSSL握手: 0.185s首字节: 17.739s总耗时: 72.965sHTTP状态: 200