我有一个代理管理池,负责存储、检查和检索代理,以便它们可以与web请求一起使用。
async getNextAvailableProxy() {
while(true) {
var sleepTime = global.Settings.ProxyPool.ProxySleepTimeMS;
var availableProxies = await this.data.find(PROXY_COLLECTION, {
$query: {
Enabled: true,
InUse: false,
LastUsed: { $lte: new Date(new Date() - sleepTime) }
},
$orderby: { ResponseTime: 1 }
});
if (availableProxies.length <= 0) {
var nextAvailable = await this.data.findOne(PROXY_COLLECTION, {
$query: { Enabled: true, InUse: false },
$orderby: { LastUsed: -1 }
});
if (!nextAvailable) {
await Utils.sleep(100);
console.log('No proxies available, sleeping');
continue;
}
sleepTime = sleepTime - (new Date() - nextAvailable.LastUsed)
if (sleepTime > 0)
await Utils.sleep(sleepTime);
continue;
}
var selectedProxy = availableProxies[0];
selectedProxy.InUse = true;
await this.data.save(PROXY_COLLECTION, selectedProxy);
return selectedProxy;
}
}值得注意的是,我的find和save版本是NodeJS的MongoDB驱动程序的包装器。
同样值得注意的是,Utils.sleep()是一个使用setTimeout执行异步休眠的promise。
现在,我了解到由于NodeJS是单线程的,所以不会出现竞争条件。但是,当使用多个隔离对象快速查询数据库时,情况并非如此。
假设我有5个对象ProxyPool实例,它们都在短时间内调用getNextAvailableProxy(),它们都将从数据库中获取相同的代理,因为一个实例在另一个实例保存InUse标志之前就已经启动了查询,这使得n-instances of ProxyPool都在检索save exact代理。
我如何才能以异步方式绕过这个问题?
发布于 2018-02-12 04:24:17
老实说,很难根据你的帖子来判断为什么这是一个问题。虽然冲突可能会发生,但在我看来,它应该是足够罕见的,不会有什么影响,除非代理的使用是一个真正的长时间运行的操作(因此给定的代理被占用了很多)。
也就是说,我也不会在每个请求上都查找代理。相反,我可能会让每个worker在启动时或按时间间隔(可能每小时一次或其他时间)获取一个代理池,然后在内部管理(在内存中)可用的代理。
然后,您的算法可以非常灵活地计算出为给定工作线程分配哪些代理,并且不太可能发生冲突,因为每个节点实例都是单线程的,它不会两次分配相同的代理。
风险在于,您可能会遇到某个给定的工作线程已用完代理的地方。这也是您需要处理的事情,但由于您(理论上)将以某种方式使您的工作负载均衡,因此如果您到达该位置,您可能无论如何都会耗尽代理,并且将不得不很快发出Too Busy响应。
最后,当您在数据库中查找可用代理的列表时,您应该使用findAndModify()或类似的工具一次性获取和更新文档,这样,当您从数据库中取出一个代理时,您会告诉数据库它不可用,而不是首先等待web服务器上的处理。
https://stackoverflow.com/questions/48735138
复制相似问题