中心思想:分为同步频率不等的两个层次,一个近乎实时(分钟甚至秒级别)定时同步,一个长时间(小时级甚至天级)定时同步。通过实时同步与数据库的交互,执行长时间定时同步中的同步任务。
为什么想到这个策略?最近在看 api 网关架构相关知识,想到网关中可能有一部分配置信息需要定时同步,同时在系统运行时可能需要即时更新什么配置。由于我们的 node.js 进程是无中心的多进程,因此想到了下面的混合策略来提供一方面可以低系统消耗即时更新配置,另一方面又可以长期同步配置的功能。
首先,长时间定时同步容易理解,类似下面的:
// 每五个小时同步一次信息
setInterval(() => {
longIntervalSyncFunc();
}, HOUR * 5);
这种同步策略是常用的同步策略,既能及时同步数据,又不会对系统造成太大的负载。
有时候我们可能需要很快的同步数据,那么,可能会写成下面的形式:
// 每五秒同步一次信息
setInterval(() => {
shortIntervalSyncFunc();
}, SECOND * 5);
这样写可以很快的同步数据,但是如果我们的数据变化得没有那么快,那么很多次的同步操作都是无效操作,对系统性能造成了不少损耗。可以使用增量数据更新来减轻这个问题。
如果需要既能及时同步又能不显著增加系统负担,可以采用一种混合策略。
// 每五秒同步一次信息
setInterval(async () => {
// 首先从 db 中查询需要执行的同步函数
let rel = await db.get('syncFuncNeedCall');
if (rel.someSyncFunc && rel.synced.indexOf(curProcess) < 0) {
// 如果其中有这个函数,并且还没有开始执行同步,就执行
await someSyncFunc(); // 执行同步任务
await db.update('syncFuncNeedCall'); // 更新数据库中本进程执行同步任务的信息,以及是否所有进程都已经执行过此同步任务
}
}, SECOND * 5);
需要及时同步时,只需要更新一下数据库中的数据,数秒内所有的进程就会开始执行同步任务。
每个进程执行完此同步任务之后,就在数据库中标记本进程已经执行。所有进程都执行完毕之后,就可以标记本任务已执行,所有进程都不再执行此任务。
----------------------------> end