问题描述
我了解到 Node.js 是单线程和非阻塞的。在这里我看到了一个很好的解释How,in general,does Node.js handle 10,000 concurrent requests? 但第一个答案说
看似神秘的事情是上述两种方法如何设法“并行”运行工作负载?答案是数据库是线程化的。所以我们的单线程应用实际上是在利用另一个进程的多线程行为:数据库。
(1) 这让我很困惑。以一个简单的快递应用为例,当我
var monk = require('monk');
var db = monk('localhost:27017/databaseName');
router.get('/QueryVideo',function(req,res) {
var collection = db.get('videos');
collection.find({},function(err,videos){
if (err) throw err;
res.render('index',{ videos: videos })
});
});
当我的路由器通过简单的 MongoDB 查询响应多个请求时。这些查询是否由不同的线程处理?我知道节点中只有一个线程来路由客户端请求。
(2) 我的第二个问题是,这样的单线程节点应用如何保证安全?我对安全性不太了解,但看起来多请求应该是隔离的(至少是不同的内存空间?)即使多线程应用程序无法确保安全性,因为它们仍然共享很多东西。我知道这可能不是一个合理的问题,但在今天的云服务中,隔离似乎是一个重要的话题。我迷失在无服务器、wasm 和使用 Node.js 环境的基于 wasm 的无服务器等主题中。
感谢您的帮助!!
解决方法
(1) 大局是这样的; nodejs 有两种类型的线程:事件(单个)和工作线程(池)。只要你不阻塞事件循环,在 nodejs 将阻塞的 I/O 调用放置到工作线程之后; nodejs 继续为下一个请求提供服务。工作人员会将完成的 I/O 放回事件循环以进行下一步操作。
简而言之,主线程:“在需要等待时执行其他操作,等待结束后返回并继续,并且一次执行此操作”。
而且这种反应机制与运行在另一个进程(即数据库)中的线程无关。数据库可以部署其他类型的线程管理方案。
(2) 您问题中的“内存空间”在同一个进程空间中。一个线程属于一个进程(即 Express 应用 A),永远不会在其他进程(即 Fastify 应用 B)空间中运行。
,既然你问了我的答案,我想我可以帮忙澄清一下。
1
对于处理触发多个并行 MongoDB 查询的多个并行客户端请求的特定情况:
这些查询是否由不同的线程处理?
在 node.js 上,由于 MongoDB 通过网络堆栈 (tcp/ip) 连接,所有并行请求都在单个线程中处理。 魔法是一种系统 API,它允许您的程序并行等待。 Node.js 使用 libuv 来根据编译时的操作系统选择要使用的 API。但是哪个 API 并不重要。知道所有现代操作系统都具有允许您并行等待多个套接字的 API(而不是通常在多个线程/进程中等待单个套接字)就足够了。这些 API 统称为异步 I/O API。
关于 MongoDB.. 我对 MongoDB 了解不多。 Mongo 可以在多线程中实现,也可以像 node.js 一样是单线程的。磁盘 I/O 本身由操作系统并行处理而不使用线程,而是使用 I/O 通道(例如,PCI lanes)和 DMA 通道。基本上,线程/进程和异步 I/O 通常由操作系统(至少在 Linux 和 Mac 上)使用相同的底层系统实现:操作系统事件。操作系统事件只是处理中断的函数。无论如何,这与关于数据库的讨论相去甚远。
我知道 MySQL 和 Postgresql 都是多线程来处理 SQL 查询循环的解析(SQL 中的查询处理基本上是遍历行并过滤结果的操作 - 这需要 I/O 和 CPU,这就是为什么它们多线程)
如果您仍然好奇计算机如何在没有 CPU 执行单个指令的情况下执行操作(例如等待 I/O),您可以查看我对以下相关问题的回答:
Is there any other way to implement a "listening" function without an infinite while loop?
What is the mechanism that allows the scheduler to switch which threads are executing?
2
被解释的语言确保了安全性,并确保解释器没有任何堆栈溢出或下溢错误。在大多数情况下,这适用于所有现代 javascript 引擎。通过程序输入注入代码和执行外部代码的主要机制是通过缓冲区溢出或下溢。能够执行外部代码然后允许您访问内存。如果你不能执行能够访问内存的外部代码,那是没有意义的。
在某些编程语言文化中,还有第二种注入外来代码的机制:code eval(我在看你的 PHP!)。无论您的程序的内存模型如何,使用字符串替换以任何语言构建数据库查询都会使您面临 sql 代码 eval 攻击(通常称为 sql 注入)。 Javascript 本身有一个 eval()
函数。为了防止这种 javascript 程序员简单地考虑 eval
邪恶。基本上,对 eval
的保护取决于良好的编程实践,并且 Node.js 是开源的,任何人都可以查看代码并报告可能发生代码评估攻击的任何情况。从历史上看,Node.js 在这方面做得非常好 - 因此,您对代码评估安全性的主要保证是 Node 的声誉。