首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用MongoDB + NodeJS避免竞争条件和饥饿

使用MongoDB + NodeJS避免竞争条件和饥饿
EN

Stack Overflow用户
提问于 2018-02-12 02:50:22
回答 1查看 571关注 0票数 0

我有一个代理管理池,负责存储、检查和检索代理,以便它们可以与web请求一起使用。

代码语言:javascript
复制
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;
    }
}

值得注意的是,我的findsave版本是NodeJS的MongoDB驱动程序的包装器。

同样值得注意的是,Utils.sleep()是一个使用setTimeout执行异步休眠的promise。

现在,我了解到由于NodeJS是单线程的,所以不会出现竞争条件。但是,当使用多个隔离对象快速查询数据库时,情况并非如此。

假设我有5个对象ProxyPool实例,它们都在短时间内调用getNextAvailableProxy(),它们都将从数据库中获取相同的代理,因为一个实例在另一个实例保存InUse标志之前就已经启动了查询,这使得n-instances of ProxyPool都在检索save exact代理。

我如何才能以异步方式绕过这个问题?

EN

回答 1

Stack Overflow用户

发布于 2018-02-12 04:24:17

老实说,很难根据你的帖子来判断为什么这是一个问题。虽然冲突可能会发生,但在我看来,它应该是足够罕见的,不会有什么影响,除非代理的使用是一个真正的长时间运行的操作(因此给定的代理被占用了很多)。

也就是说,我也不会在每个请求上都查找代理。相反,我可能会让每个worker在启动时或按时间间隔(可能每小时一次或其他时间)获取一个代理池,然后在内部管理(在内存中)可用的代理。

然后,您的算法可以非常灵活地计算出为给定工作线程分配哪些代理,并且不太可能发生冲突,因为每个节点实例都是单线程的,它不会两次分配相同的代理。

风险在于,您可能会遇到某个给定的工作线程已用完代理的地方。这也是您需要处理的事情,但由于您(理论上)将以某种方式使您的工作负载均衡,因此如果您到达该位置,您可能无论如何都会耗尽代理,并且将不得不很快发出Too Busy响应。

最后,当您在数据库中查找可用代理的列表时,您应该使用findAndModify()或类似的工具一次性获取和更新文档,这样,当您从数据库中取出一个代理时,您会告诉数据库它不可用,而不是首先等待web服务器上的处理。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48735138

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档