掘金是不懂技术吗,为什么一直用轮询调接口?

11,145 阅读5分钟

以掘金为例:为什么选择轮询?

不知道大家有没有留意,掘金平台的通知模块一直使用轮询请求API,自上线至今,尽管UI和功能更新了好多版,这一块仍然使用轮询接口来获取最新数据,而不是更先进的 WebSocket 或 MQTT。 这种典型的轮询机制在众多互联网产品中仍然广泛存在。为什么看似"简单粗暴"的轮询接口仍被大量采用?实时通信技术又该如何选型?

image.png

首先,我可以肯定的回答,肯定不是掘金平台的技术水平差。那为什么没有使用诸如Web Socket技术呢?首先我们根据业务场景分析一下,只谈技术不谈场景都是耍流氓

为什么使用轮询?

  1. 兼容性好: 轮询是 HTTP 协议的基础操作,几乎所有浏览器和服务器都支持,而 WebSocket 需要额外的服务器支持。

  2. 开发成本低: 轮询的实现很简单,只需要加个定时发送请求,离开页面关闭请求即可。而 WebSocket 需要实现建立、连接、断开、重连。设置还需要优化连接数,支持高并发。真要把socket搞好,工作量也不少

  3. 低并发,长时间轮询,服务器扛得住: 首先,这个轮询是大约30S一次,时间太长也没意义,1分钟我觉得都OK。其次,相比较上拉刷新、下拉加载、查看等业务,这个轮询的使用频率是比较低的,谁没事天天挂着个网页呀。就算真的有这种情况,那每日时长肯定高的很,估计运营平台都笑开花了。就算真的扛不住,升级这个功能,分分钟的事情

  4. 祖传代码,用着没问题,不用动,能用就行

优化方案

WebSocket

image.png

很多人第一时间会想到使用WebSocket,其实更WebSocket适合实时性要求高的场景, 如聊天室、弹幕、股票报价等。用WebSocket去做这种消息通知(不需要实时通知,就算通知不到,用户自己去刷新,对用户也业务也没有影响),有点杀鸡用牛刀的感觉,大材小用了。

WebSocket需要注意: 优化架构(如水平扩展、消息队列)以突破连接数限制

Server-Sent Events(SSE)

image.png

SSE 是单向通道,只能服务器向浏览器发送

SSE是使用流信息向浏览器推送信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。

SSE实现起来很简单,也有很多优点,我们放在后面去讲

但是需要注意的是:SSE方案有2个必须考虑的问题

SSE不支持IE/Edge早期版本

http 1.X时,SSE会受到打开连接数的限制。以chrome为例,是6个

各方案对比

处理这种实时数据的业务,常见的解决方式是:轮询、WebSocket、 MQTT。下面简单说下不同技术的优缺点

1. 轮询(Polling) 轮询是指客户端定期向服务器发送请求的操作

setInterval(() => {
  fetch('/api/notifications')
   .then()
   .then()
}, 1000 * 30)

优点:

  • 简单易实现,所有 HTTP 服务器都支持
  • 无需额外的协议支持,维护成本低

缺点:

  • 数据延迟高,数据只能按固定时间间隔获取
  • 大量无效请求,浪费带宽和服务器资源

适用场景: 低并发、对实时性要求不高的场景,如错误列表,站内信等

2. WebSocket

WebSocket是一种全双工通信协议,客户端和服务器可以在连接建立后随时发送数据。

const ws = new WebSocket('wss://example.com/notifications');
ws.onmessage = (event) => {
  console.log(event.data);
};

优点:

  • 实时性强,数据变更可即时推送
  • 相比轮询减少了无效请求,减少服务器负担

缺点:

  • 需要额外的服务器支持(如 WebSocket 服务器)
  • 连接数管理复杂,可能需要负载均衡

适用场景: 即时聊天、股票交易、在线协作等需要高实时性的场景

3. Server-Sent Events SSE 是单向通道,只能服务器向浏览器发送。

const sse = new EventSource("/api");

sse.addEventListener("notice", (e) => {
  console.log(e.data);
});

优点:

  1. SSE 属于轻量级,使用简单
  2. 默认支持断线重连
  3. 连接开销少,比WebSocket节省的2/3的成本

缺点:

  1. SSE不支持IE/Edge早期版本
  2. http 1.X时,SSE会受到打开连接数的限制

适用场景:需要单向更新的场景,如未读消息,版本升级等

4. MQTT(Message Queuing Telemetry Transport)

MQTT 是一种轻量级的发布/订阅协议,通常用于物联网(IoT)。

client = mqtt.Client()
client.connect("broker.example.com", 8001)
client.subscribe("sensors/#")

优点:

  • 低功耗,适用于低带宽设备
  • 服务器端可以进行消息存储和转发,保证数据可靠性

缺点:

  • 需要专门的 MQTT 服务器
  • 适用于 IoT 设备,浏览器支持较差,移动端需要SDK

适用场景: 物联网设备、智能家居、传感器数据收集

一句话总结:

对于大多数 Web 应用,轮询仍然是最常见的选择,因为它的实现简单,兼容性好。但如果应用对实时性要求高,比如聊天、直播、推送通知等,WebSocket 是更好的选择。而 MQTT 则更适合 IoT 场景。

现代架构演进方案

  1. 混合架构:主通道用WebSocket,兼容回退轮询
  2. 协议升级策略
location /notifications {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

3. 边缘计算优化:在边缘侧处理心跳、计算等需求

总结

没有最好的协议,只有最合适的方案。在掘金这类技术社区中,采用轮询可能是出于历史架构演进成本、用户实际需求强度(非严格实时)等多维度权衡的结果。而我们在技术选型也应该建立在对业务场景、用户规模、团队能力的综合评估

最后一句话: 所有的方案都要在压力测试扛得住的情况下论证,如果扛不住,果断想办法。