欢迎光临散文网 会员登陆 & 注册

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

2023-08-16 21:11 作者:程序员潘岩  | 我要投稿

前言

情况是这样的,在开发 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 配置:

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

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

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

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

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

  • 使用传统的轮询?

  • 还是长连接?

  • 还是 WebSocket 呢?

  • 还是不用 Cloudflare 了?

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

解决方案

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

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

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

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

  • 使用短轮询来避免发生这个错误

  • 企业用户可以设置 proxy_read_timeout 到 6000 秒

  • 关闭 Cloudflare 的边缘网络分发,请求直接打到源服务器上

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

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

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

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

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

总结

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

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

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

  1. 请在 Server 设置响应头 X-Accel-Buffering: no 来关闭 Nginx 响应缓存

  2. 每隔 30 秒做一次响应来避免 Cloudflare 100 秒未响应的超时错误

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


记一次部署 SSE 消息推送到 Cloudflare 遇到的问题的评论 (共 条)

分享到微博请遵守国家法律