【问题标题】:Optimize async queries nodeJs优化异步查询 nodeJs
【发布时间】:2021-03-21 17:12:36
【问题描述】:

我正在开发一个拥有超过 25k 用户的项目,每次为 Oppurtinity module 创建任何记录时,它都会执行此函数,该函数会在 mongodb 中插入每个用户的通知详细信息, 问题是它耗尽了 cpu 并且不让任何其他 API 产生结果,直到这个异步结束它需要时间,同时服务器不加载任何其他数据/它给出延迟响应。

  1. 节点-v10.15.3
  2. MongoDB shell 版本v4.0.17
  3. 服务器=Windows=Memory-8GB
  4. CPU 2.70GHz speed

我想知道,这里有什么问题,是不是代码,如果是我该如何优化呢?

async.eachSeries(users, (eachuser, next) => {
     db.notifications.find({user_id:eachuser._id},function(errr,opp_noti){
        if(opp_noti.length != 0){
          db.notifications.update( { user_id:eachuser._id},{$push:{oppurtunity:oppurtunity_id}},function(errr,result){
            })
        }else{
        db.notifications.insert({user_id:eachuser._id,oppurtunity:[oppurtunity_id]},function(errr,result){
         })
        }
       })
    next();
})

【问题讨论】:

    标签: node.js mongodb optimization async-await


    【解决方案1】:

    您的示例代码和您的问题存在一些问题。我不得不假设您正在使用这些库:AsyncMongoDB。请尝试更好地组织您的问题。

    如果我假设正确,那么您没有仔细遵循文档,因为您没有正确实现 async.eachSeries 函数 - eachSeries 期望 async 函数作为第二个参数。

    我已经根据这两个库的文档重写了您的代码。我以前从未使用过它们,但我有理由相信它是正确的。

    async.eachSeries(users, async (user) => {
        const user_id = user._id;
        const cursor = db.notifications.find({ user_id });
        const count = await cursor.count();
        if (count > 0) {
            return db.notifications.update({ user_id },
                {
                    $push: { oppurtunity: oppurtunity_id } // where is oppurtunity_id defined?
                }
            )
        } else {
            return db.notifications.insert({
                user_id,
                oppurtunity: [oppurtunity_id]
            })
        }
    })
    

    您可能已经意识到这一点,但async.eachSeries 将通过串联运行请求来限制请求。尽管出于各种原因这可能是必要的,但它会减慢进程并且不会利用 Node 的非阻塞特性。 async.each 将并行运行它们,这在理论上是最快的,但在 25K 记录时它可能会导致问题。所以我建议你采取中间立场,考虑使用async.eachOfLimit,设置并行限制并查看它的执行情况。

    您还可以通过不为每个用户查询数据库来进一步分解问题并大幅提高性能。尝试在一个查询中获取所有需要提前更新的用户。

    类似下面的内容将在一个查询中返回 notifications 集合中的所有 ID(可能不止一个,但仍然比 n 好得多)。

    const user_ids = db.notifications.find({}, { _id:1 }).map(item => item._id)
    

    一旦有了 ID,您就可以创建两个工作负载,一个运行所有 db.notifications.update 查询,另一个运行所有 db.notifications.insert 查询。

    【讨论】:

    • 我正在处理这个问题,并将更新为我唤醒的内容,非常感谢 :D
    • 我有一个疑问,我的服务器配置是否可以处理 30k 用户流量、数据处理等等? @理查德邓恩
    • 30k users 没有任何意义。您需要掌握每秒处理的请求数,尤其是在/当有高峰时间时。然后你需要考虑这些请求中的大多数在做什么(它是一个长时间运行的任务吗?它是否消耗大量内存?)。如果您的服务器与大多数其他 API 服务器一样,那么它实际上只是数据库的包装器。如果是这样,数据库将是您的第一个瓶颈。想一想如何提高Mongo效率,网上有很多文章。对于通知之类的事情,您应该考虑在 Mongo 旁边使用 Redis 等内存存储。
    猜你喜欢
    • 2018-09-30
    • 1970-01-01
    • 2020-06-19
    • 2011-08-14
    • 2014-03-28
    • 2021-10-11
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多