一个 node.js 应用既服务于 rest-api 又处理 websockets 是个好主意吗?
Is a node.js app that both servs a rest-api and handles web sockets a good idea?
免责声明:我是 node.js 的新手,如果这是一个奇怪的问题,我很抱歉 :)
我有一个 node.js 使用 express.js 来服务 REST-API。 REST-API 提供的数据由 node.js 应用程序从 nosql 数据库中获取。所有客户端仅使用 HTTP-GET。但是有一个例外:数据是从主数据库(另一台服务器上的关系数据库)中放置和删除的。
此设置的想法当然是让 'node.js/nosql database' 服务器成为 public 前端,从而保护主数据库免受繁忙流量的影响。
许多不同的客户端应用程序可能会使用 REST-API,但主要由具有较长生命周期(通常为 0.5 到 2 小时)的客户端应用程序使用。我不想让这个应用程序不断轮询 REST-API 以获取可能的新数据,而是使用 websockets 以便仅在有任何新数据时将数据发送到客户端。我将为此使用 node.js 应用程序,可能还会使用 socket.io,这样如果客户端不支持 websockets,它可以回退到 api-轮询。每次 master 数据库在 nosql 数据库中 PUT 或 DELETE 对象时,都应该向客户端发送新数据。
问题是我应该为 API 和 websockets 使用一个 node.js 还是为 API 和一个为 websockets 使用一个。
需要考虑的事项:
- 性能:应用程序将托管在一个服务器集群上,前面有一个负载平衡器和一个 HTTP 加速器。一个应用程序处理所有事情会比两个具有不同任务的应用程序表现更好吗?
- 应用程序之间的流量:如果我选择两个应用程序解决方案,则从主数据库接收 PUT 和 DELETE 的 api 应用程序每次接收新数据时都必须通知 websocket 应用程序(或者主数据库必须通知)两个应用程序)。翻倍的流量可能是性能问题吗?
- 代码简洁:我相信两个应用程序会产生更清晰和更好的代码,但话又说回来,这两个应用程序肯定会有一些共同的代码,这将导致它有两个副本。
至于负载有多大很难说,但可能的峰值可能涉及:
50000个客户
每个收听最多 5 个不同的频道
每 5 秒从主机发送一次新数据
新数据应发送给大约 25% 的客户端(对于某些数据,它应该发送给所有客户端,而其他数据可能低于 1% 的客户端)
更新:
谢谢你们的回答。更多的思想食物在这里。我决定拥有两个 node.js 应用程序,一个用于 REST-API ,另一个用于网络套接字。原因是我相信扩展它们会更容易。首先,整个系统将托管在三台物理服务器上,每台服务器上的 REST-API 一个 node.js 应用程序应该足够了,但对于 websocket 应用程序,可能需要它的多个实例在每台物理服务器上。
您必须考虑的第一件事是如何扩展服务器并管理它们的状态。使用 REST API 这在很大程度上是直接的,因为它们大部分是无状态的,并且每个负载均衡器都知道如何代理 http 请求。因此,REST APIs 可以水平扩展,将少量状态留给持久层(数据库)处理。对于 websockets,通常是另一回事。您需要研究要使用的负载均衡器(如果是云部署,通常取决于云提供商)。然后弄清楚负载均衡器需要什么类型的 websocket 支持或配置。然后根据您的应用程序,您需要弄清楚如何管理集群中的 websocket 连接状态。考虑不同的用例,例如如果一台服务器上的 websocket 事件改变了数据的状态,您是否需要将此更改传播给不同连接上的不同用户?如果答案是肯定的,那么您可能需要像 Redis 这样的东西来管理您的 ws 连接并在服务器之间传达更改。
至于性能,归根结底它仍然只是 HTTP 连接,所以我怀疑分离服务器功能会有很大的不同。但是,我认为只要您有另一个 'core' 模块来隔离两台服务器通用的代码,两台服务器就可以大大提高代码的整洁度。
我个人会一起做,这是因为您可以在 REST 和 WS 之间共享模型和大部分代码。
归根结底,Yuri 在他的回答中所说的是正确的,但是以任何方式负载平衡 WS 并没有太多工作,现在每个人都这样做。我采用的方法是为所有内容提供 REST,然后创建一些 WS "endpoints" 用于订阅实时数据服务器-客户端。
据我了解,您的客户端只会从服务器获得通知和更新,所以我肯定会选择 WS。你订阅了一些事件,然后当有新结果时你会得到新的结果。继续询问 HTTP 调用不是最好的方法。
我们有这个需求,基本上围绕这个想法构建了一个小框架http://devalien.github.io/Axolot/
基本上你可以理解我们在控制器中的方法(这只是一个例子,在我们真实世界的应用程序中我们有订阅,所以我们可以在有新数据或完成程序时通知)。在操作中有其余端点,在套接字中有 websockets 端点。
module.exports = {
model: 'user', // We are attaching the user to the model, so CRUD operations are there (good for dev purposes)
path: '/user', // Tthis is the end point
actions: {
'get /': [
function (req, res) {
var query = {};
Model.user.find(query).then(function(user) { // Find from the User Model declared above
res.send(user);
}).catch(function (err){
res.send(400, err);
});
}],
},
sockets: {
getSingle: function(userId, cb) { // This one is callable from socket.io using "user:getSingle
Model.user.findOne(userId).then(function(user) {
cb(user)
}).catch(function (err){
cb({error: err})
});
}
}
};
这是个很好的问题。
如果您正在查看遗留系统,并且已经定义了 REST 接口,那么添加 WebSockets 并没有太多优势。可能指向 WebSockets 的事情是:
- 服务器到客户端或客户端到客户端的需求实时数据
- 需要使用经典的双向协议与服务器组件集成(例如,您想在 javascript 中编写 FTP 或 sendmail 客户端)。
如果您要开始一个新项目,我会尝试在项目之间进行严格划分:
使用 HTTP(这是它的设计目的)提供静态内容(图像、js、css)和
使用 WebSockets 提供动态内容(实时数据)(负载平衡,基于 subscription/messaging,启用自动重新连接以处理网络故障)。
所以,我们为什么要硬分开呢?让我们考虑一下基于 HTTP 的 REST 协议的优点。
REST 语义使用 HTTP 协议是一项具有一定优势的发明
- 无状态交互:none 客户端上下文将在请求之间存储在服务器端。
- 可缓存:客户端可以缓存响应。
- 分层系统:中介不可检测
- 轻松测试:使用 curl 测试基于 HTTP 的协议很容易
另一方面...
在 WebSockets 之上使用消息传递协议(例如 AMQP,JMS/STOMP)并不排除任何这些优势。
WebSockets 可以透明地进行负载平衡,可以缓存消息和状态,可以定义高效的有状态或无状态交互。
基本的反应式分析风格可以定义哪些事件触发客户端和服务器之间的哪些消息。
主要的附加优势是:
WebSocket 旨在成为长期持久连接,可用于通过单个连接实现多种不同的消息传递目的
WebSocket 连接允许完全双向通信,允许根据网络特性在任一方向发送数据。
可以使用连接卸载来使用中介共享对公共主题的订阅。这意味着只需很少的核心消息代理连接,您就可以大规模高效地为数百万连接的用户提供服务。
监控和测试可以通过 send/recieve 消息的管理界面实现(所有消息代理都提供)。
这一切的代价就是WebSocket掉线后需要重连时需要处理重新建立状态。许多协议设计者构建了“同步”消息的概念,以提供从服务器到客户端的上下文。
无论哪种方式,无论您使用 REST 还是 WebSockets,您的模型对象 可能 相同,但这可能意味着您仍然在请求-响应方面考虑得太多,而不是publish/subscribe.
免责声明:我是 node.js 的新手,如果这是一个奇怪的问题,我很抱歉 :)
我有一个 node.js 使用 express.js 来服务 REST-API。 REST-API 提供的数据由 node.js 应用程序从 nosql 数据库中获取。所有客户端仅使用 HTTP-GET。但是有一个例外:数据是从主数据库(另一台服务器上的关系数据库)中放置和删除的。 此设置的想法当然是让 'node.js/nosql database' 服务器成为 public 前端,从而保护主数据库免受繁忙流量的影响。
许多不同的客户端应用程序可能会使用 REST-API,但主要由具有较长生命周期(通常为 0.5 到 2 小时)的客户端应用程序使用。我不想让这个应用程序不断轮询 REST-API 以获取可能的新数据,而是使用 websockets 以便仅在有任何新数据时将数据发送到客户端。我将为此使用 node.js 应用程序,可能还会使用 socket.io,这样如果客户端不支持 websockets,它可以回退到 api-轮询。每次 master 数据库在 nosql 数据库中 PUT 或 DELETE 对象时,都应该向客户端发送新数据。
问题是我应该为 API 和 websockets 使用一个 node.js 还是为 API 和一个为 websockets 使用一个。
需要考虑的事项: - 性能:应用程序将托管在一个服务器集群上,前面有一个负载平衡器和一个 HTTP 加速器。一个应用程序处理所有事情会比两个具有不同任务的应用程序表现更好吗? - 应用程序之间的流量:如果我选择两个应用程序解决方案,则从主数据库接收 PUT 和 DELETE 的 api 应用程序每次接收新数据时都必须通知 websocket 应用程序(或者主数据库必须通知)两个应用程序)。翻倍的流量可能是性能问题吗? - 代码简洁:我相信两个应用程序会产生更清晰和更好的代码,但话又说回来,这两个应用程序肯定会有一些共同的代码,这将导致它有两个副本。
至于负载有多大很难说,但可能的峰值可能涉及: 50000个客户 每个收听最多 5 个不同的频道 每 5 秒从主机发送一次新数据 新数据应发送给大约 25% 的客户端(对于某些数据,它应该发送给所有客户端,而其他数据可能低于 1% 的客户端)
更新: 谢谢你们的回答。更多的思想食物在这里。我决定拥有两个 node.js 应用程序,一个用于 REST-API ,另一个用于网络套接字。原因是我相信扩展它们会更容易。首先,整个系统将托管在三台物理服务器上,每台服务器上的 REST-API 一个 node.js 应用程序应该足够了,但对于 websocket 应用程序,可能需要它的多个实例在每台物理服务器上。
您必须考虑的第一件事是如何扩展服务器并管理它们的状态。使用 REST API 这在很大程度上是直接的,因为它们大部分是无状态的,并且每个负载均衡器都知道如何代理 http 请求。因此,REST APIs 可以水平扩展,将少量状态留给持久层(数据库)处理。对于 websockets,通常是另一回事。您需要研究要使用的负载均衡器(如果是云部署,通常取决于云提供商)。然后弄清楚负载均衡器需要什么类型的 websocket 支持或配置。然后根据您的应用程序,您需要弄清楚如何管理集群中的 websocket 连接状态。考虑不同的用例,例如如果一台服务器上的 websocket 事件改变了数据的状态,您是否需要将此更改传播给不同连接上的不同用户?如果答案是肯定的,那么您可能需要像 Redis 这样的东西来管理您的 ws 连接并在服务器之间传达更改。
至于性能,归根结底它仍然只是 HTTP 连接,所以我怀疑分离服务器功能会有很大的不同。但是,我认为只要您有另一个 'core' 模块来隔离两台服务器通用的代码,两台服务器就可以大大提高代码的整洁度。
我个人会一起做,这是因为您可以在 REST 和 WS 之间共享模型和大部分代码。
归根结底,Yuri 在他的回答中所说的是正确的,但是以任何方式负载平衡 WS 并没有太多工作,现在每个人都这样做。我采用的方法是为所有内容提供 REST,然后创建一些 WS "endpoints" 用于订阅实时数据服务器-客户端。
据我了解,您的客户端只会从服务器获得通知和更新,所以我肯定会选择 WS。你订阅了一些事件,然后当有新结果时你会得到新的结果。继续询问 HTTP 调用不是最好的方法。
我们有这个需求,基本上围绕这个想法构建了一个小框架http://devalien.github.io/Axolot/
基本上你可以理解我们在控制器中的方法(这只是一个例子,在我们真实世界的应用程序中我们有订阅,所以我们可以在有新数据或完成程序时通知)。在操作中有其余端点,在套接字中有 websockets 端点。
module.exports = {
model: 'user', // We are attaching the user to the model, so CRUD operations are there (good for dev purposes)
path: '/user', // Tthis is the end point
actions: {
'get /': [
function (req, res) {
var query = {};
Model.user.find(query).then(function(user) { // Find from the User Model declared above
res.send(user);
}).catch(function (err){
res.send(400, err);
});
}],
},
sockets: {
getSingle: function(userId, cb) { // This one is callable from socket.io using "user:getSingle
Model.user.findOne(userId).then(function(user) {
cb(user)
}).catch(function (err){
cb({error: err})
});
}
}
};
这是个很好的问题。
如果您正在查看遗留系统,并且已经定义了 REST 接口,那么添加 WebSockets 并没有太多优势。可能指向 WebSockets 的事情是:
- 服务器到客户端或客户端到客户端的需求实时数据
- 需要使用经典的双向协议与服务器组件集成(例如,您想在 javascript 中编写 FTP 或 sendmail 客户端)。
如果您要开始一个新项目,我会尝试在项目之间进行严格划分:
使用 HTTP(这是它的设计目的)提供静态内容(图像、js、css)和
使用 WebSockets 提供动态内容(实时数据)(负载平衡,基于 subscription/messaging,启用自动重新连接以处理网络故障)。
所以,我们为什么要硬分开呢?让我们考虑一下基于 HTTP 的 REST 协议的优点。
REST 语义使用 HTTP 协议是一项具有一定优势的发明
- 无状态交互:none 客户端上下文将在请求之间存储在服务器端。
- 可缓存:客户端可以缓存响应。
- 分层系统:中介不可检测
- 轻松测试:使用 curl 测试基于 HTTP 的协议很容易
另一方面...
在 WebSockets 之上使用消息传递协议(例如 AMQP,JMS/STOMP)并不排除任何这些优势。
WebSockets 可以透明地进行负载平衡,可以缓存消息和状态,可以定义高效的有状态或无状态交互。
基本的反应式分析风格可以定义哪些事件触发客户端和服务器之间的哪些消息。
主要的附加优势是:
WebSocket 旨在成为长期持久连接,可用于通过单个连接实现多种不同的消息传递目的
WebSocket 连接允许完全双向通信,允许根据网络特性在任一方向发送数据。
可以使用连接卸载来使用中介共享对公共主题的订阅。这意味着只需很少的核心消息代理连接,您就可以大规模高效地为数百万连接的用户提供服务。
监控和测试可以通过 send/recieve 消息的管理界面实现(所有消息代理都提供)。
这一切的代价就是WebSocket掉线后需要重连时需要处理重新建立状态。许多协议设计者构建了“同步”消息的概念,以提供从服务器到客户端的上下文。
无论哪种方式,无论您使用 REST 还是 WebSockets,您的模型对象 可能 相同,但这可能意味着您仍然在请求-响应方面考虑得太多,而不是publish/subscribe.