NodeJS + SocketIO大型套接字事件管理

时间:2014-12-09 04:41:56

标签: javascript node.js mongodb mongoose socket.io

我有一百万恐龙用户全部登录。

恐龙希望看到其他恐龙何时实时更新其个人资料,因此他们会迷上NodeJS / Mongoose模型: dinosaur.schema.post('save', function (doc) { socket.emit('dinosaur:save', doc); });
其中socket是连接恐龙的插座。

恐龙也将从其他几个方面看到实时更新。也许是新闻,评论等等。

所以,我的问题是,是否存在一些事件,这些事件的发生会变大并影响性能?

在客户端,我会有类似socket.on('dinosaur:save', function(){})的东西......我在不需要时会摧毁听众。但是,如果我正在倾听每一个dinosaur:save,我理论上可以处理每秒一百万次保存(比如每个恐龙在同一秒内更新了他们的个人资料)。对于大型数据集来说,似乎有更好的方法。

我想还有其他一些我可能想要观看的事件,我只是想知道是否有一些推荐的方法用于这种套接字管理。

编辑:要清楚,我知道房间,但如果我有一个滚动列表,列出我所在地区附近所有的恐龙,我可能只想勾住接收所有{{{ 1}}事件。所以我还不确定。

2 个答案:

答案 0 :(得分:1)

通知一百万个任何东西是很多数据包,如果你要通知的事情发生了很多,那就是很多,而且尝试在屏幕上显示的内容甚至更多。

通常要考虑的第一件事是:

  1. 这些通知实际上必须是实时的吗?您是否可以在每个通知期间将每个用户60秒或更长时间的通知批量分组到一个数据包中?

  2. 每个用户是否真的必须看到每个其他用户的每一次更改。您知道任何用户界面都无法呈现其他一百万用户的状态。所以,我认为每个用户都不必知道每个其他用户的状态。也许如果有1-50个其他用户,但如果有一百万用户则不行。

  3. 您可以通过算法确定给定用户可能感兴趣的用户状态,并仅向他们广播。例如,您是否可以仅在地理位置靠近其他用户的位置更新它们?

  4. 您是否有用户界面,用户可以告诉您要跟踪哪些其他用户,以便您只更新这些用户?或者也许是他们告诉你的一些用户组合以及他们对他们有意义的用户。关键是你无论如何都不能看到一百万用户,所以你必须发明一个显示比这更少的UI。

  5. 如果客户端尚未拥有该状态,您可以随时拥有可根据需要获取其他用户状态的UI,因此您无需为每个客户端中的所有百万用户保留状态(因为它无论如何都不可能一次全部显示)。如果用户浏览以查看他们尚未拥有的内容,您只需通过套接字或ajax调用从服务器获取它。

  6. 哦,就你所说的规模而言,你可能需要将用户的连接分散在多个服务器中,这样你就必须处理这种复杂性。

答案 1 :(得分:1)

如果将来有人遇到此问题,请查看问题和我目前的解决方案。

我们想要实时更新。如果您在某人的个人资料页面上,并且更新它,请显示。如果您正在查看用户个人资料的某些广告结果集,并且其中任何一个用户更新了他们的个人资料,请显示该结果。如果您在另一个页面上,并且某些计数器更改了您附近的用户,请显示该信息。但是,我们不会同时在所有这些页面上,所以在客户端我甚至不想知道其他更改,如果我不在那些其他页面。这个问题可能会导致我收到所有的通知,这可能会导致带宽问题,以及一大堆不必要的套接字使用。

所以,我解决问题的方法是使用rooms。我在命名空间上使用房间,因为命名空间通常用于访问相同套接字资源的两个相互不相交的应用程序。房间也适合这个应用程序。

我已经为每个用户个人资料页面创建了一个动态的动态房间。当访问者打开个人资料页面时,客户端调用socket.emit("joinRoom", modelName + ":" + modelObj._id);并在服务器上处理socket.on('joinRoom', function(room) { socket.join(room); });。如果还没有房间,这会自动创建房间。并将用户添加到其中。 modelName可以是我们想要的任何东西。它只是我如何拆分房间的命名惯例。你可以给房间打电话。但重要的部分是最后的._id。使用Mongoose,没有两个DB对象可以具有相同的._id,因此这可以保证独特的房间。

当此个人资料页面的所有者更新他们的信息时,我们会在服务器上调用: io.sockets.in('Dinosaur:' + doc._id).emit("Dinosaur:" + doc._id + ":updated", doc);并使用 socket.on(modelName + ":" + modelObj._id + ":updated" , function(msg){ // do something })

在客户端接收该信息

Viola,我们只向感兴趣的客户发送了这些必要的信息。

- (另一个问题) -
使用这种方法,我们还可以提供与多个用户相关的数据。如果我们有一个用户配置文件的配对结果列表,对于每个配置文件,我们可以将当前用户添加到所有这些配置结果配置文件的房间中。 (所以他们在属于_id X,_id Y,_id Z等的房间里。 然后,当前用户将在多个房间中,所有这些都反映了这些用户的即时更新,因此反映了整个照顾结果列表,无论它是什么列表(可能是"恐龙附近")。 /> 另一种解决方法,特别是如果列表更加静态,就是让套接字每隔X秒重新传递一次结果集,使用相同的套接字,并且只需要相同的初始空间。