I/O 完成端口可以帮助数据库而不是文件写入吗?

Posted

技术标签:

【中文标题】I/O 完成端口可以帮助数据库而不是文件写入吗?【英文标题】:Can I/O completion port help with database instead of File writes? 【发布时间】:2010-08-15 03:25:05 【问题描述】:

我正在阅读 IOCP,据我所知,异步写入仅适用于写入文件的上下文。我所说的“文件”不仅仅是磁盘文件,而是 Windows 上的“文件”类型的输出设备。

我计划以某种方式使用 IOCP 来实现一个服务器,该服务器从客户端获取消息,然后将这些消息异步写入数据库(mysql 或 SQLite)。但是,据我了解,IOCP 中的异步写入涉及将要写入的数据传递给设备驱动程序——而且“设备驱动程序”的提及似乎排除了在数据库上使用 IOCP 和异步写入的可能性,因为有从应用程序编写者的角度来看,不涉及写入数据库的“设备驱动程序”。

那么,IOCP 真的可以帮助实现写入数据库的服务器吗?我有一种唠叨的感觉,我误会了什么。

如果在这种情况下 IOCP 无法提供帮助,对于在 Windows 上实现对数据库进行异步写入的服务器,我应该考虑什么建议?

【问题讨论】:

【参考方案1】:

通常,数据库会给您一个 API,您可以使用它来写入数据。这通常隐藏了它所做的所有复杂事情。有时,该 API 可能是通用的并且可以与许多数据库一起使用,例如 OLE-DB 和 ODBC,有时 API 可能是特定于数据库的。

您使用的数据库不太可能公开一个足够低级别以使用 IOCP 的 API,尽管它可能在内部使用 IOCP。

您可能想问的是,我可以使用异步写入来写入我的数据库吗,也就是说,您能否在不阻塞执行“触发”的线程的情况下触发数据库写入。

虽然当您的服务器的其余部分使用 IOCP 与其自己的日志文件和套接字读/写通信时,IOCP“友好”数据库 API 会很好,但您可以获得的最好的方法是使用线程池来允许您发出数据库 API 需要的阻塞调用,而不会阻塞服务器所做的其余工作。我倾向于将其称为“业务逻辑线程池”,它与我用于所有非阻塞 I/O 的 IOCP 线程池是分开的。

我写了一些关于构建服务器的文章,这些文章使用这种设计来写入数据库,可以在here 找到文章的代码和链接。

【讨论】:

【参考方案2】:

Io 完成端口是一种通用机制,可通过多种方式使用以实现可扩展性。

在“最佳”情况下,Io 完成端口与重叠 Io 使用的操作系统句柄相关联。但这实际上根本不是必需的:Io 完成端口机制足够通用,可以提供可扩展性,即使使用的所有 API 都是阻塞的和/或不公开所需的句柄。

在一个非常简单的模型中,可以使用CreateIoCompletionPort - 调用PostQueuedCompletionStatus 来创建用户定义的“工作”。创建一个所有在GetQueuedCompletionStatus 上循环的工作线程池 - 并在处理排队作业时简单地在工作线程内调用您的阻塞 Io 例程。每当一个工作线程阻塞在任何内核函数上时,Io Completion Port 机制将看到并发计数较低,并释放另一个工作线程。

显然,使用这种方式,活动工作线程的数量可能会超过并发计数,但是,假设作业是对称的,当线程返回到它的 `GetQueuedCompletionStatus' 调用时,它应该会很快自行解决。

【讨论】:

【参考方案3】:

当您写入文件并且不想在发生任何事情时阻塞时,它们可以在任何地方提供帮助。很难想象一个数据库想要这样,除了可能在编写完整性并不重要的文本日志文件时。

【讨论】:

【参考方案4】:

IOCP 在实现数据库时可以提供很大帮助。

IOCP 结合 FILE_FLAG_NO_BUFFERING 和 FILE_FLAG_WRITE_THROUGH 以及正确对齐的块让数据库引擎控制缓存行为,避免不必要的重复缓存和块副本,以正确的顺序获取写入,控制哪些写入可以同时进行,等等

当然需要实现数据库才能使用这些功能,使用 SQLite 和 Mysql 可以获得其他功能。

有关这如何帮助实现数据库的更多详细信息,请参阅 Gray 和 Reuter 的“事务处理:概念和技术”。

【讨论】:

以上是关于I/O 完成端口可以帮助数据库而不是文件写入吗?的主要内容,如果未能解决你的问题,请参考以下文章

将多个文件关联到同一个 io 完成端口,同时保持文件流顺序 c#

我的循环错了吗?我是不是滥用 ReadFile() 和 I/O 完成端口?

boost.asio 和文件 i/o 有啥关系?

编写程序以处理导致 Linux 上丢失写入的 I/O 错误

如果 I/O 完成端口数据包可能以不同的顺序出列,为啥 I/O 完成端口数据包会按 FIFO 顺序排队?

I/O