记一次部署 SSE 消息推送到 Cloudflare 遇到的问题

270 天前
 pzhyy

前言

情况是这样的,在开发 MagicBee 时,需要支持实时消息通知和任务分发功能。

在做了一番技术方案的对比之后,决定使用 SSE (Server Send Events) 来实现。

历经一个星期加班加点地开发之后,在本地测试一切都很完美,忍不住想来一波自夸:我真是个天才!😄

终于到了部署上线的环节,跟往常一样,这个项目依然采用单机服务,然后使用 Cloudflare DNS 解析,再通过它的边缘网络分发到世界各地。

为了安全,我决定先上到预发布环境测一测,再发布,以确保万无一失。

拷贝了一份 Nginx 的配置,改改,-t 测试通过,然后重启 Nginx 使配置生效。

最后,在 Cloudflare 的配置面板,将域名解析指向自己的服务器 IP 。

这样,后端的部署就完成了。

遇到的问题

我迫不及待地打开 MagicBee 插件,心里有点慌,又有点期待...

打开控制台,切换到 Network 面板,映入眼帘的是一秒闪一下的 401 错误,心想 🤔 完了。

愣住 3 秒,突然回过来神来的我,这是访问受限,嗷 ~~ 嗐,我还没登录呀!

于是,不慌不忙地打开登录页,噼里啪啦地输入账号&密码,回车。

回到 Network 面板,F5 刷新一下,没有错误了,暗自欣喜,继续观察中...

在 1.1min 后,SSE 连接断开了,可能是网络波动,更何况还有重试机制兜底,不慌,继续观察...

在下一个 1.1min 后,连接又断开了,看来这不是一个意外!

首先想到的是 Nginx 的配置不对,赶紧检查了下配置。

发现 proxy_read_timeout 1m; 设置为 1 分钟,肯定是它在搞鬼,于是改为 8h ,一天断开 3 次连接,还可以接受吧!

继续观察,在 1.7min 后,又有序的断开连接了。

啊 ~~ 😵 这次又是什么原因呢???

疯狂检索后,试了一遍又一遍,各种解决方案,可惜对我都不管用!

比如,更改 Nginx 配置:

proxy_http_version 1.1;
proxy_set_header Connection '';
chunked_transfer_encoding off;

proxy_buffering off;
proxy_cache off;

在源(上游)服务的响应头添加:

X-Accel-Buffering: no

简直要疯了,为了确定这是 Cloudflare 导致的问题,我不得不在本地装了个 Nginx ,用同样的配置测试却没问题。

好,既然知道问题出在哪里,那就有解决的方法!

又一波疯狂地检索后,得知 Cloudflare 对 SSE 支持并不好,但能很好的支持 WebSocket 。

啊 ~~ 这?难道要我更换技术方案?

想想那漫漫重构路,我头大了!😥

解决方案

就在即将放弃 SSE 方案之际,决定再好好翻阅 Cloudflare 官方文档,终于功夫不负有心人,发现了这么一个描述。

意思是 Cloudflare 已成功连接到源服务器,但在 100 秒内没有响应,所以就发生超时了。

100 秒?换算起来不就是 1.666... 分钟,四舍五入恰好就是 1.7 分钟嘛?这与我遇到的问题十分吻合啊!

继续往下看,对于这种耗时任务,Cloudflare 也提供了几种解决方案:

这些都不是我想要的解决方案,仔细想想,是不是在 100 秒内有响应就好了?

于是,我赶紧改造消息推送的代码,启动一个时钟来每隔 30 秒发送一个 keepalive 的空消息

部署上去后,继续观察,嗯 ~ 这一次,稳了!

连接在 1.5 小时后才断开,还是由于电脑休眠了的原因,不过这已经足够了。

只要能达到小时级别,再加上重连机制,这是可接受的结果。

总结

这是一次部署 SSE 消息推送到 Cloudflare 的经历,中途遇到很多很多问题,做了很多测试,再一一排除。

每一次都到了濒临崩溃,更改技术方案的局面,好在最终克服了重重困难,得偿所愿。

如果你的应用场景与我相似,请求链路如下:

Client -> Cloudflare -> Nginx -> Server
  1. 请在 Server 设置响应头 X-Accel-Buffering: no 来关闭 Nginx 响应缓存
  2. 每隔 30 秒做一次响应来避免 Cloudflare 100 秒未响应的超时错误

好啦!今天就分享到这里,有任何问题,欢迎在评论区交流。

1190 次点击
所在节点    程序员
4 条回复
GTim
270 天前
所以,看到最后,你没搞心跳就是了
xieqiqiang00
270 天前
cloudflare 免费的压根不支持 sse 吧?踩过坑
pzhyy
270 天前
@GTim 跳了,每 30s 跳一下,要不然 Cloudflare 就以为链接死了 🤣

@xieqiqiang00 支持!只是之前没搞过,这一次踩坑,记录一下
RangerWolf
270 天前
感觉很干货,很多我没见过的东西!感谢楼主分享

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/965988

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX