Node.js 实时通知-数据库轮询-最佳实践
我向我的用户提供实时通知。 我正在讨论两个选项,但在轮询DB时无法决定哪种方式是最好的 (通知使用WebSocket传输。) 选项1(当前): 我持有所有已登录用户的列表。 每隔1000毫秒,我会检查数据库中是否有新的通知,如果有,我会通过WS向相应的用户发送消息 优点: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
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秒钟是一个很长的时间等待李>
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次,这对于这个任务来说是非常昂贵的李>
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毫秒运行一次。这不过分吗?排队机制是为这种类型的操作设计的。