问题起因:
在开发我的网站谷流仓AI - guliucang.com的AI聊天助手功能模块,采用了跟chatGPT官网一样的stream流传输格式。在建立起连接并且还未断的期间,后端服务器可以主动推送消息给前端,在页面上能看到的效果就是AI回复的消息是一个字一个字打印出来的,而在浏览器的控制面板可以看到接口的response Content-Type是text/event-stream。
我在本地调试的时候,一切都正常,前端看到字是一个一个打印出来的。但是发布到云服务器之后,发现实际效果是AI发回来消息的时候,直接显示一大段文字,然后卡顿2秒,然后又是直接显示一大段文字。整个过程看起来就很卡顿。下面来回顾一下这个问题的排查流程。
问题排查 & 解决办法
首先,理清整个链路,如下图
- 本地启动前端项目,连接本地服务,页面展示效果正常。连接云端服务器, 页面就出现了类似卡顿的现象。这样就排除了前端渲染的问题,同时也排除了节点1的问题
- 打开浏览器控制台,查看该接口的获取到event stream的时间节点,发现接收到的数据是一批一批的,比如在第一秒的几百毫秒内瞬间收到了几十个响应,然后过了2秒,又在几百毫秒内收到几十个响应,但是在本地的时候,接受到的stream时持续不断的,不可能中断2秒,然后又瞬间发送。推测是java应用发送响应到nginx之后,被nginx缓存起来了,缓存到一定数据量之后,再统一发送到浏览器客户端。
在经过大量面向百度后,怀疑是proxy_buffer的问题,于是在nginx针对该接口添加了如下配置
# http模块添加tcp_nodelay尝试让nginx直接将数据发送至客户端
tcp_nodelay on;
# server下的location模块针对该接口设置禁用缓存
proxy_buffering off;
proxy_cache off;
proxy_buffer_size 0;
proxy_http_version 1.1;
事实证明这些配置完全没起作用.
然后还是去stackoverflow, 找到了一个解决方法,就是在接口返回的header上添加X-Accel-buffering:no
return ResponseEntity.ok()
.header("X-Accel-Buffering", "no")
.body(stringFlux);
再次尝试,发现已经是和本地一样的展示效果了。至此,问题排查结束,就是nginx的加速缓存导致的。