![Linux 上的低级磁盘 I/O](https://linux22.com/image/37482/Linux%20%E4%B8%8A%E7%9A%84%E4%BD%8E%E7%BA%A7%E7%A3%81%E7%9B%98%20I%2FO.png)
用户级程序可以在 SSD 上执行页级或块级 I/O 吗?
我查看了磁盘设备,但不确定它们是否提供此功能,因为它们仅在分区具有文件系统时才起作用。
更新#1
我想为 SSD 编写一个高性能键值存储,因此我需要某种方法来进行低级访问(包括读取、写入和擦除)。
我知道我的方法必须是内核级的,但在此之前我想在用户空间中测试它(避免学习内核级编程的复杂性)。
答案1
您可以通过以下方式在任何类型的存储上执行低级磁盘 I/O块设备,类似于Linux 下的/dev/sda
(对于整个磁盘)或/dev/sda1
(对于分区)。这完全绕过了文件系统。
如果您实现自己的键值存储,我绝对保证您将得到的结果将比专业人员编写的文件系统和数据库慢得多且错误更多。一个高效的存储机制需要考虑缓存、并发写入、断电恢复能力等,这是非常难的!
答案2
我不认为用户程序可以完成该级别的 I/O 优化(更不用说这样做所需的优化机制)。因此,我的方法是通过实现类似队列之类的东西来优化应用程序中的流程,一旦超过既定的数据阈值,该队列将其内容刷新到所需的输出。伪代码可能如下所示:
MAX_OBJS=100
M[100]=new M[100]
function saveObj(obj) {
if (M.size > MAX_OBJS-1) {
outputStream.appendArrayToBinary(M)
M = new M[100]
}
M.add(obj)
}
while (true) {
saveObj( new Obj )
}
正如你所看到的,它会有一个缓冲100 个对象。一旦第 101 个物体被尝试已保存,它将另外 100 个对象写入磁盘并清除缓冲区,为另外 100 个对象留出空间。当然,您可以实现更复杂的技术,例如在另一个线程上执行写入并锁定数组,以便在将对象写入磁盘并清除缓冲区之前不会添加其他对象。或类似的东西。
答案3
我已经指出在您的另一个问题中,为什么您必须放弃内核级方法。
在进行此类努力之前,应澄清以下几点:
“高性能”并不是一刀切的属性。
优化应该针对特定情况进行,并且只有在发现主要瓶颈时才进行。
您应该问自己以下问题:
- 我是否评估过当前主流的键值存储系统实现?如果没有,为什么不呢?
- 如果我这样做了,为什么它们不适合我的用例?我是否进行了广泛的基准测试和测试?我是否找到了主要瓶颈?我可以在当前最先进的实现中修复它吗?如果没有,为什么我认为我可以在自己的实现中修复它?
- 我的具体性能要求是什么?我是否定义了“绩效”并找到了衡量它的方法?存储操作期间的高性能?检索操作期间的高性能?由于客户端连接数量大,高负载下高性能?
一旦你清楚地了解了什么确切地你想要实现的目标,一旦你拒绝了当前最先进的软件,只有那时你才应该开始探索潜在的实施策略。
内核是你最不想碰的地方。特别是如果您之前没有内核开发经验。大多数内核子系统都经过高技能工程师经过多年测试和开发的流程进行了高度优化。
我的建议是考虑通过预分叉、智能缓存和延迟写入的组合进行优化。熟悉流行的缓存算法、负载平衡方法并了解现代文件系统(例如预读,制定政策,LRU)-也许这些与您的问题没有直接关系,但它有助于了解人们如何解决类似领域的性能问题。当然,这并不意味着建议在您的应用程序中重新实现这些功能,因为文件系统本身已经更好地实现了这些功能 - 在大多数情况下,这会损害应用程序的性能而不是增强它。