情况是这样的,在开发 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 也提供了几种解决方案:
proxy_read_timeout
到 6000 秒这些都不是我想要的解决方案,仔细想想,是不是在 100 秒内有响应就好了?
于是,我赶紧改造消息推送的代码,启动一个时钟来每隔 30 秒发送一个 keepalive 的空消息。
部署上去后,继续观察,嗯 ~ 这一次,稳了!
连接在 1.5 小时后才断开,还是由于电脑休眠了的原因,不过这已经足够了。
只要能达到小时级别,再加上重连机制,这是可接受的结果。
这是一次部署 SSE 消息推送到 Cloudflare 的经历,中途遇到很多很多问题,做了很多测试,再一一排除。
每一次都到了濒临崩溃,更改技术方案的局面,好在最终克服了重重困难,得偿所愿。
如果你的应用场景与我相似,请求链路如下:
Client -> Cloudflare -> Nginx -> Server
X-Accel-Buffering: no
来关闭 Nginx 响应缓存好啦!今天就分享到这里,有任何问题,欢迎在评论区交流。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.