内容简介:本系列的头两篇文章中我们看到就像你可能知道的那样,尽管你使用的是异步编程,但是将所有这些操作都指派给同一个用于响应 API 调用的进程真的是一种效率很低的方式。
本系列的头两篇文章中我们看到 如何扩展一个 Node.js 应用 以及 在应用的代码部分应该考虑什么 才能使其在这个过程中运行如我们所愿。在这最后一篇文章中,我们将介绍一些其它实践,以进一步提高应用运行效率和性能。
Web 和 Worker 进程
就像你可能知道的那样, Node.js 在实际运行中是单线程的 ,因此一个进程实例在同一时间只能执行一个操作。在 Web 应用的运行生命周期中,会执行 很多不同类型的任务 :包括管理 API 调用,读/写数据库,与外部网络服务通信,以及不可避免地执行某些 CPU 密集型工作等。
尽管你使用的是异步编程,但是将所有这些操作都指派给同一个用于响应 API 调用的进程真的是一种效率很低的方式。
一种常见的模式是基于组成你应用不同类型进程之间的 责任分离 ,这种情况下进程通常被分为 web 进程和 worker 进程。
Web 进程主要的任务是管理 传入的网络调用 并尽快将它们分发出去。每当一个非阻塞任务需要被执行时,例如发送电子邮件/通知,写日志,执行一个触发操作,它们都不需要马上响应 API 调用返回结果,Web 进程会把这些操作委派给 worker 进程。
web 和 worker 进程之间的通信可以通过不同的方式实现。一种常见且有效的解决方案是优先级队列,就像我们将在下一段描述的 Kue 所实现的那样。
这种方式有一个很大的优点,无论在同一台还是不同机器上其都可以 分别独立扩展 web 和 worker 进程 。
例如,如果你的应用请求量很大,相较于 worker 进程你可以部署更多的 web 进程而几乎不会产生任何副作用。而如果请求量不是很大但是有很多的工作需要 worker 进程去处理,你可以据此重新分配相应的资源。
Kue
为了使 web 进程和 worker 进程可以相互通信,使用 队列 是一种灵活的方式,它可以使你不需要担心进程之间的通信。
Kue 是 Node.js 中常用的队列库,它基于 Redis 并且让你可以用完全一致的方式让运行在同一台或不同机器上的进程间相互通信。
任何类型的进程都可以创建一个工作并将之放入队列,然后被配置的相应 worker 进程就会从队列中提取并执行它。每个工作都提供了大量的可配置选项,如优先级,TTL,延迟等。
你创建的 worker 进程越多,执行这些作业的并行吞吐量也就越大。
Cron
应用程序通常需要 定期执行 一些任务。通常这种类型的操作,是通过操作系统级别的 cron 工作 进行管理,也就是会调用你应用程序之外的一个单独脚本。
当需要把你的应用部署到新的机器上时,这种方式会需要额外的配置工作,如果你想要自动化部署应用时,它会让人对其感到不舒服。
我们可以使用 NPM 上的 cron 模块 从而更轻松地实现同样的效果。它允许你在 Node.js 代码中定义 cron 工作,从而使其免于操作系统的配置。
根据上面所描述的 web/worker 进程模式,worker 进程可以通过定期调用一个函数把工作放到队列从而实现创建 cron。
使用队列可以使 cron 的实现更加清晰并且还可以利用 Kue 所提供的所有功能,如优先级,重试等。
当你的应用有多个 worker 进程时就会出现一个问题,因为同一时间所有 worker 进程的 cron 函数都会唤醒应用把多个同样重复的工作放入队列,从而导致同一个工作将会被执行多次。
为了解决这个问题,有必要 识别将要执行 cron 操作的单个 worker 进程 。
Leader 选举和 cron-cluster
这种类型的问题被称为 “ leader 选举 ”,NPM 为我们提供了这种特定情况下的处理方案,有一个叫做cron-cluster 的包。
它在维持和 cron 模块一致 API 的同时增强了模块,但是在启动过程中它需要有 redis 连接 ,用于和其它进程间通信和执行 leader 选举算法。
使用 redis 作为单一事实的来源, 所有进程最终都会同意谁将执行 cron ,并且只有一个工作副本会被放入队列中。在这之后,所有的 worker 进程都可以像往常一样选择是否执行这个工作。
缓存 API 调用
服务端缓存是提高你 API 调用 性能和反馈性 一种常用的方式,但这是一个非常广泛的主题,有很多可能的实现。
在像我们在这个系列所描述的分布式环境中,如果想要所有的节点在处理缓存时表现一致,最好的办法或许是使用 redis 来缓存需要的值。
缓存所需要考虑最困难的方面就是缓存失效。一种快捷实用的解决方案是只考虑缓存时间,这样缓存中的值就会在固定的 TTL 时间后刷新,这样做的缺点是我们不得不等到下一次缓存刷新才能看到响应中的更新。
如果你能有更多的时间,最好在应用级别实现失效,即当数据库中的值更改时手动刷新 redis 缓存中的相关记录。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- “DevOps”的人员可扩展性
- 喝口可乐聊聊可扩展性设计
- 大咖连载|可扩展性设计(二)
- 观点 | 以太坊可扩展性挑战:状态数据
- Kubernetes 1.15:可扩展性和持续改进
- Kubernetes 1.15 发布,可扩展性与持续性改进
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
测试驱动开发的艺术
Lasse Koskela / 李贝 / 人民邮电出版社 / 20101023 / 59.00元
在传统的软件开发中,开发人员对于代码是否正确心中无底,一切依赖于后期的测试环节。极限编程反其道而行之,主张采用测试驱动开发(TDD)的方法,即通过测试定义所要开发的功能的接口,然后实现功能的开发过程。TDD通过不断地测试推动代码的开发,既简化了代码,又保证了软件质量。 本书采用“手把手”的教学方式,通过大量实例来解释TDD,还专门用几章的篇幅来讲解如何为难于测试的技术编写单元测试。全书内容循......一起来看看 《测试驱动开发的艺术》 这本书的介绍吧!