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

查看 28|回复 0
作者: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 。
啊 ~~ 这?难道要我更换技术方案?
  • 使用传统的轮询?
  • 还是长连接?
  • 还是 WebSocket 呢?
  • 还是不用 Cloudflare 了?

    想想那漫漫重构路,我头大了!😥
    解决方案
    就在即将放弃 SSE 方案之际,决定再好好翻阅 Cloudflare 官方文档,终于功夫不负有心人,发现了这么一个描述。

    意思是 Cloudflare 已成功连接到源服务器,但在 100 秒内没有响应,所以就发生超时了。
    100 秒?换算起来不就是 1.666... 分钟,四舍五入恰好就是 1.7 分钟嘛?这与我遇到的问题十分吻合啊!
    继续往下看,对于这种耗时任务,Cloudflare 也提供了几种解决方案:
  • 使用短轮询来避免发生这个错误
  • 企业用户可以设置 proxy_read_timeout 到 6000 秒
  • 关闭 Cloudflare 的边缘网络分发,请求直接打到源服务器上

    这些都不是我想要的解决方案,仔细想想,是不是在 100 秒内有响应就好了?
    于是,我赶紧改造消息推送的代码,启动一个时钟来每隔 30 秒发送一个 keepalive 的空消息
    部署上去后,继续观察,嗯 ~ 这一次,稳了!
    连接在 1.5 小时后才断开,还是由于电脑休眠了的原因,不过这已经足够了。
    只要能达到小时级别,再加上重连机制,这是可接受的结果。
    总结
    这是一次部署 SSE 消息推送到 Cloudflare 的经历,中途遇到很多很多问题,做了很多测试,再一一排除。
    每一次都到了濒临崩溃,更改技术方案的局面,好在最终克服了重重困难,得偿所愿。
    如果你的应用场景与我相似,请求链路如下:
    Client -> Cloudflare -> Nginx -> Server
    [ol]
  • 请在 Server 设置响应头 X-Accel-Buffering: no 来关闭 Nginx 响应缓存
  • 每隔 30 秒做一次响应来避免 Cloudflare 100 秒未响应的超时错误
    [/ol]
    好啦!今天就分享到这里,有任何问题,欢迎在评论区交流。
  • 您需要登录后才可以回帖 登录 | 立即注册

    返回顶部