Node.js 实时通知-数据库轮询-最佳实践

Node.js 实时通知-数据库轮询-最佳实践,node.js,mongodb,notifications,database,Node.js,Mongodb,Notifications,Database,我向我的用户提供实时通知。 我正在讨论两个选项,但在轮询DB时无法决定哪种方式是最好的 (通知使用WebSocket传输。) 选项1(当前): 我持有所有已登录用户的列表。 每隔1000毫秒,我会检查数据库中是否有新的通知,如果有,我会通过WS向相应的用户发送消息 优点: hooks = { notifications : { add: function () { count() //and other actions

我向我的用户提供实时通知。

我正在讨论两个选项,但在轮询DB时无法决定哪种方式是最好的

(通知使用WebSocket传输。)

选项1(当前):

我持有所有已登录用户的列表。 每隔1000毫秒,我会检查数据库中是否有新的通知,如果有,我会通过WS向相应的用户发送消息

优点:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}
  • 这项任务在资源上并不昂贵
缺点:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}
  • 在关闭时间,每1分钟只有一个新通知,我会无缘无故地轮询DB 60次
  • 从某种意义上说,它不是实时的,因为更新新通知需要整整1秒的时间。如果它是一个聊天服务,1秒钟是一个很长的时间等待
选项2:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}
创建一个钩子,每当保存(或删除)一个新通知时,db都会被轮询

优点:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}
  • 没有新通知时,不会轮询数据库
  • 实际实时响应
缺点:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}
  • 在高峰时段,当每秒可能生成多达10个新通知时,db将经常被轮询,这可能会阻碍其对站点其他元素的响应时间
  • 如果用户在生成通知时未登录,则通知更新将丢失(因为我仅轮询已登录用户的数据库),除非每当用户登录以检索其脱机时的通知时,我也执行计数。所以现在,我不仅在触发通知钩子时轮询DB,而且在每次用户登录时轮询DB。如果我每秒生成通知,每秒登录10次,那么我将每秒轮询我的DB 20次,这对于这个任务来说是非常昂贵的
您会选择哪个选项?1, 2? 或者两者都没有?为什么?

以下是我当前使用的代码(选项1):

var activeSockets = [] //whenever a user logs in or out, the array gets updated to only contain the logged-in users in any given moment

var count = function () {
    process.nextTick(function () {
        var ids = Object.keys(activeSockets) //the ids of all the logged in users
        //every user document has a field called newNotification that updates whenever a new notification is available. 0=no new notifications, >0=there are new notifications
        User.find({_id:{$in:ids}}).select({newNotifications:1}).lean().exec(function (err,users) {
            for(var i=0;i<users.length;i++) {
                var ws = activeSockets[String(users[i]._id)]
                if(ws!=undefined) {
                    if (ws.readyState === ws.OPEN) {
                        //send the ws message only if it wasn't sent before. 
                        if(ws.notifCount!=users[i].newNotifications) {
                            ws.send(JSON.stringify({notifications:users[i].newNotifications}));
                            activeSockets[String(users[i]._id)].notifCount = users[i].newNotifications
                        }

                    }
                    else {
                        //if the user logged out while I was polling, remove them from the active users array
                        delete activeSockets[String(users[i]._id)]
                    }
                }
            }
            setTimeout(function () {
                count()
            },1000)
        })
    })

}
var activeSockets = [] //whenever a user logs in or out, the array gets updated to only contain the logged-in users in any given moment

var count = function () {
    process.nextTick(function () {
        var ids = Object.keys(activeSockets) //the ids of all the logged in users
        //every user document has a field called newNotification that updates whenever a new notification is available. 0=no new notifications, >0=there are new notifications
        User.find({_id:{$in:ids}}).select({newNotifications:1}).lean().exec(function (err,users) {
            for(var i=0;i<users.length;i++) {
                var ws = activeSockets[String(users[i]._id)]
                if(ws!=undefined) {
                    if (ws.readyState === ws.OPEN) {
                        //send the ws message only if it wasn't sent before. 
                        if(ws.notifCount!=users[i].newNotifications) {
                            ws.send(JSON.stringify({notifications:users[i].newNotifications}));
                            activeSockets[String(users[i]._id)].notifCount = users[i].newNotifications
                        }

                    }
                    else {
                        //if the user logged out while I was polling, remove them from the active users array
                        delete activeSockets[String(users[i]._id)]
                    }
                }
            }
        //setTimeout was removed
        })
    })

}

那么,您会选择哪个选项?1, 2? 或者两者都没有?为什么?

我会选择选项2并将通知传递到消息队列(这应该很便宜)。然后,一个单独的进程将实际执行通知用户的工作(更昂贵)。我明白了,消息队列最多每1000毫秒执行一次,除非是空的?这可能是个好主意。让我想想这个!您在消息队列上放置了一个侦听器,它会在可用时读取消息并进行处理。但是,如果队列每20毫秒更新一次,它也会每20毫秒运行一次。这不过分吗?排队机制是为这种类型的操作设计的。