Node.js 使用异步i/o编写数据库
我最近遇到了一个低级库,它可以让NodeJ发挥异步的魔力。这让我思考。我想澄清以下几点:Node.js 使用异步i/o编写数据库,node.js,database,libuv,Node.js,Database,Libuv,我最近遇到了一个低级库,它可以让NodeJ发挥异步的魔力。这让我思考。我想澄清以下几点: Nodejs具有异步i/o调用。然而,如果我调用一个(远程)数据库的API,对db的实际读/写将是同步的,但节点不必等待。是否有可能使数据库本身以异步方式写入磁盘?是否有使用libuv进行实际异步i/o的数据库 Javascript以单线程著称。我知道nodejs运行时不需要这样-如果我有4个cpu核,我可以启动4个实例。但是,如果我使用libuv用一种支持线程的语言编写另一个web框架,它不具备异步I/o
你混淆了两个概念。在对服务执行查询时,您可以异步等待(通过epoll/kpoll/libuv…)这一事实并不意味着您的查询在另一端是非阻塞的,反之亦然。这也并不意味着,在事件循环中,事情“感觉”是异步的,而实际上是异步的 让我们回到什么是事件循环,以及nodeJS是如何发挥其魔力的。我觉得这是一个好的开始 事件循环的可见部分是代码编写方式的变化——从大部分同步到大部分异步。不可见的部分是,这个异步代码被尽可能多地抛出到事件循环中,在后台检查要做的事情—IO、计时器等。这不是一个新想法,它的工作(提供并发性)做得非常好 libuv的文档实际上对此非常有描述性。是对他们所做设计选择的描述,从中得出以下流程图: 请注意,他们没有声明他们已经实现了真正的异步——因为他们没有。底层系统调用保持同步。只是感觉不是这样。这是关键 关于数据库上的磁盘I/O,我不久前在海牙做过一次演讲,坦率地说,大多数关键I/O都是阻塞。例如,您不能说“嘿,我要更新磁盘快照,同时只追加txlog!”——因为如果其中一个失败,您就有一个严重的回滚问题,可能还有未知状态 关于问题2,我会给出代码示例,但我不确定您熟悉哪些语言。底线是,当某物越过线程边界时,它就变成了地狱。一个非常简单的例子是这样的-假设您的事件循环有两个计时器,如下所示:
- 定时器1每0.5s触发一次,增加给定的状态变量
a
- 定时器2,每当有人提供用户输入时触发,将状态变量除以2
THREAD 1 | THREAD 2
<- A=1 |
Local:A=1+1=2 | <- A=1
| Local: A=1*2=2
A=2 -> | A=2 ->
螺纹1 |螺纹2
线程2在线程1计算的中途开始运行,检索到错误的状态变量值(因为线程1尚未更新变量),并将其乘以2。你应该有3个,但事实上你最终只有2个
为了防止这种情况,有很多方法和工具。现在大多数处理器架构都有原子指令(例如),开发人员如果知道在哪里需要它们,就可以利用这些指令。在这些工具之上,您可以有一整套工具—互斥锁、读/写锁、信号量等等。。。以降低或消除这些问题的成本,并在您知道需要它们的地方时
不用说,概括这一点绝非易事。感谢您抽出时间键入描述性答案。“大多数重要的I/O都是阻塞的”-因此,如果我有一种并发处理的方法并确保事务处理正常,那么数据库读/写就不需要阻塞,对吗?是的,我知道在文件系统级别,一切都会阻塞。我只是好奇,如果我编写一个单线程的db,但使用一个事件循环,会发生什么。这意味着我可以“执行”一个非常耗时的
SELECT
,而不必等待响应,然后执行一个INSERT
,前提是我有正确的锁。@lonesword“blocking”是一个大字。很难提供一个通用的答案,因为即使在linux上纯读/写操作的世界中,人们也可以访问select
/pselect
,以查看多个文件描述符。然而,对于大多数RDBMS解决方案,读/写并不是阻塞的。现在我真希望有人能录下我的演讲,我深入探讨了很多数据库解决方案的所有事务机制。“然而,对于大多数RDBMS解决方案,读/写都没有阻塞”-这对我来说是新闻。如果你能抽出时间在博客上发表演讲,我很乐意阅读。谢谢您的时间。@lonesword他们在查询级别没有阻塞。它们在I/O级别阻塞很短的时间(通常写入AOL)。这就是我一直试图提出的观点——“阻塞”这个词太笼统了。如何阻止?在什么级别?影响谁?例如,在MySQL的情况下