[译] Node.js 高性能和可扩展应用程序的最佳实践 [第 2/3 部分]

第 2 章 —— 如何使您的 Node.js 应用程序安全扩展

上篇文章中,咱们学会了如何无需忧虑代码,而水平扩展 Node.js 应用程序。本章中,咱们将讨论扩展时必须注意的事项,以便在扩展流程时防止错误发生。前端

从 DB 中分离应用程序实例

本章首先要讲的不是代码,而是你的基础架构node

若是你但愿应用程序可以多主机扩展,则必须部署数据库到一些独立的主机,以即可以根据须要自由复制主机。android

在同一台机器上部署应用程序和数据库可能很便宜而且用于开发目的,但绝对不建议用于生产环境,其中应用程序和数据库必须可以独立扩展。这一样适用于像 Redis 这样的内存数据库。ios

无状态

若是您生成应用程序的多个实例,每一个进程都有本身的内存空间。这意味着即便您在一台机器上运行,当您在全局变量中存储某些值,或者更常见的是在内存中存储会话时,若是负载均衡服务器在下一个请求期间将您重定向到另外一个进程,您将没法在那里找到它。git

这适用于会话数据和内部值,如任何类型的应用程序配置。github

对于可在运行时更改的设置或配置,一种解决方案是将它们存储在外部数据库(磁盘或内存中)上,以使全部进程均可以访问它们。web

使用 JWT 进行无状态身份验证

身份验证是开发无状态应用程序时要考虑的首要问题之一。若是将会话存储在内存中,它们将做用于该单个进程。redis

为了使工做正常,您应该将网络负载均衡服务器配置为始终将同一用户重定向到同一台计算机,并将重定向到同一用户的本地用户始终重定向到同一进程(粘性会话)。数据库

解决此问题的一个简单方法是将会话的存储策略设置为持久性,例如将它们存储在 DB 中而不是 RAM 中。可是,若是您的应用程序检查每一个请求的会话数据,则每次 API 的调用都会有磁盘 I/O 操做,从性能的角度来看,这绝对不是好事。后端

更好,更快的解决方案(若是您的身份验证框架支持它)是将会话存储在像 Redis 这样的内存数据库中。Redis 实例一般位于应用程序实例外部,例如 DB 实例,但在内存中工做会更快。不管如何,在 RAM 中存储会话会使您在并发会话数增长时须要更多内存。

若是您想采用更有效的无状态身份验证方法,能够查看 JSON Web 令牌

JWT 背后的想法很简单:当用户登陆时,服务器生成一个令牌,该令牌本质上是包含有效负载的 JSON 对象的 base64 编码,加上签名得到的散列,该负载具备服务器拥有的密钥。有效负载能够包含用于对用户进行身份验证和受权的数据,例如 userID 及其关联的 ACL 角色。令牌被发送回客户端并由其用于验证每一个 API 请求。

当服务器处理传入请求时,它会获取令牌的有效负载并使用其密钥从新签名。若是两个签名匹配,则能够认为有效载荷有效且不被改变,还能够识别用户。

重要的是要记住 JWT 不提供任何形式的加密。有效负载仅在 base64 中编码,并以明文形式发送,所以若是您须要隐藏内容,则必须使用 SSL。

jwt.io 用的如下模式恢复了身份验证过程:

在认证过程当中,服务器不须要访问存储在某处的会话数据,所以每一个请求均可以由很是有效的方式由不一样的进程或机器处理。RAM 中没有保存数据,也不须要执行存储 I/O 操做,所以在扩展时这种方法很是有用。

存储在 S3 上

使用多服务器时,没法将用户生成的数据直接保存在文件系统上,由于这些文件只能由该服务器本地的进程访问。解决方案是将全部内容存储在外部服务上,可能存储在像 Amazon S3 这样的专用服务上,并在数据库中仅保存指向该资源的绝对 URL。

而后,每一个进程/机器均可以以相同的方式访问该资源。

使用 Node.js 的官方 AWS sdk 很是简单,您能够轻松地将服务集成到应用程序中。S3 很是便宜而且针对此目的进行了优化,在您的应用程序不是多进程的状况下也是一个不错的选择。

正确配置 WebSockets

若是您的应用程序使用 WebSockets 进行客户端之间或客户端与服务器之间的实时交互,则须要连接后端实例,以便在链接到不一样节点的客户端之间正确传播广播或消息。

Socket.io 库为此提供了一个特殊的数据库链接工具,称为 socket.io-redis,它容许您使用 Redis pub-sub 功能连接服务器实例。

为了使用多节点 socket.io 环境,您还须要配置协议为 “websockets”,由于长轮询须要粘性会话才能工做。

下一步

在这篇简短的文章中,咱们已经看到了一些关于如何扩展 Node.js 应用程序须要注意的事情,这对于单节点环境也能够被视为良好的实践。

在本系列的下一篇文章(也是最后一篇文章)中,咱们介绍一些 Nodejs 的进阶操做。你能够在这里找到它。


若是这篇文章对你有用,请给我点赞吧!

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索