网络不稳?别急着疯狂重试
你有没有遇到过这种情况:手机连Wi-Fi,信号一弱,立马弹出“正在重连”,然后一秒后又弹,再等一秒又来……还没等连上,自己先被提示烦死了。其实在系统软件里,这种“着急”的重连方式很常见,但并不聪明。
真正的高手,懂得“缓一缓再试”。这就是我们今天要说的——指数退避重连机制实现。
什么是指数退避?
简单说,就是每次重连失败后,等待的时间不是固定的,而是成倍增长。比如第一次失败等1秒,第二次等2秒,第三次等4秒,第四次等8秒……以此类推。这样既能保证最终能连上,又不会在短时间内把服务器砸懵。
想象一下,电梯坏了,一群人围在门口猛按按钮,结果系统更卡。如果大家轮流等1秒、2秒、4秒再按,压力小了,恢复还更快。
为什么要用它?
直接暴力重试,短时间内发起大量请求,轻则浪费资源,重则触发服务限流,甚至把对方打挂。尤其是在微服务架构下,一个服务连不上,几十个实例一起疯试,很容易形成“雪崩”。
指数退避的核心思想是:越着急,越要冷静。给系统留出恢复时间,也给自己留条后路。
代码怎么写?
下面是一个简单的 JavaScript 实现示例:
function retryWithBackoff(fn, maxRetries = 5) {
let attempt = 0;
const execute = () => {
return fn().then(
(result) => Promise.resolve(result),
(error) => {
attempt++;
if (attempt >= maxRetries) {
return Promise.reject(error);
}
const delay = Math.pow(2, attempt) * 1000; // 指数退避,单位毫秒
console.log(`第 ${attempt} 次重试,等待 ${delay}ms`);
return new Promise((resolve) => setTimeout(resolve, delay)).then(execute);
}
);
};
return execute();
}这段代码封装了一个函数 fn,最多重试5次,每次等待时间翻倍。你可以把它用在 API 请求、数据库连接、WebSocket 重连等各种场景。
可以再优化吗?
当然。实际项目中,我们常加入“随机抖动”(jitter),避免多个客户端在同一时间点集体重试。比如在计算延迟时加一点随机值:
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;这样,原本整齐划一的重试洪流,就变成错落有致的小雨点,对系统更友好。
另外,设置最大重试间隔也很重要。比如退到64秒就够了,没必要一路翻到上千秒。合理设置上限,防止等待太久。
真实场景中的应用
比如你在开发一个 IoT 设备管理平台,设备分布在各地,网络环境复杂。一旦断线,直接每秒重连,设备没回来,服务器先扛不住了。加上指数退避后,设备在网络恢复时能平稳接入,运维告警也少了大半。
再比如前端调用后端接口,网络抖动导致超时。不用用户手动刷新,页面自动在1秒、2秒、4秒后尝试,体验顺滑很多。
这玩意儿不炫技,但关键时刻特别顶用。