随机偏移二进制原始磁盘写入,没有任何缓存

Randomized-offset binary raw disk writes with no caching whatsoever

对于我的应用程序,我试图确定数据备份系统是否遗漏了任何写入。我通过将递增整数计数器写入 1GB 虚拟磁盘来执行此操作,并确保没有遗漏任何写入我可以查看还原的快照并查看是否存在任何间隙(即如果我看到 1、2、3、0 , 0, 6, 7 我知道备份没有正确写入 4 和 5)。这一切都在 CentOS 7 VM 上进行,其中大部分 Python 2.7 脚本用于 writes/reads(速度不是一个大问题)

我的问题的很大一部分是缓存:因为我模拟随机 I/O,写操作经常从缓存中刷新并乱序写入磁盘。这使得每个测试都显示为误报,因为看起来快照时某些数据丢失了。再一次,我根本不关心效率,所以我不介意写入速度非常慢。读取可以使用缓存,这不是问题,但无论哪种方式都无关紧要

以下是我尝试禁用缓存所做的事情:

  1. 使用 sudo hdparm -W 0 /dev/sdb 禁用磁盘写缓存,其中 /dev/sdb
  2. 写入没有文件系统的原始磁盘,因此没有文件系统缓存
  3. 在 Python 脚本中将 with open 上的缓冲标志设置为 0(无 Python 写入缓存)

确保我的写入按顺序放在磁盘上基本上是一项不可能完成的任务吗?我只需要在写#(n+1) 之前写#(n),在#(n+2) 之前写#(n+1),等等。

这是我用来写入磁盘的 Python 脚本(SIZE 和 PRIME 根据磁盘大小和随机种子而变化):

from struct import pack, unpack
import sys
SIZE,PRIME = [x],[x]
# random I/O traversal iterator
def rand_index_generator(a,b):
    ctr=0
    while True:
        yield (ctr%b)
        ctr+=a

with open('/dev/sdb', 'rb+', buffering=0) as f:
    index_gen = rand_index_generator(PRIME, SIZE)
    # random traversal using iterator above, write counter to file
    for counter in xrange(1, SIZE-16):
        f.seek(index_gen.next()*4)
        f.write(pack('>I', counter))

然后为了验证我以相同的顺序遍历并观察未写入数据的间隙。这是在将 VM 恢复到快照之后。我知道所有的遍历和写入工作都有效,因为验证将顺利进行,在恢复之前不会遗漏任何写入,但我认为一些“写入的”数据死在 RAM 中并且不会写入磁盘

将采纳任何建议来保证我需要的此应用程序的写入顺序

找到了这个问题的答案。我误解了写入原始磁盘的效果,它并没有消除 OS 缓存,因为我仍在调用 OS 来写入我的原始磁盘。糟糕

要绕过 OS 缓存,您应该使用 os.open 并传递 os.O_DIRECTos.O_SYNC 标志以确保写入以正确的顺序发生(more info on those flags) and are not stuck in volatile memory. I used mmap and os file descriptors but you could also use the normal filehandles like this

页面大小因您的操作系统而异。 Linux 是 4096

代码的顶部保持不变,但这里是写循环:

PAGESIZE = 4096
filedesc = os.open('/dev/sdb', os.O_DIRECT|os.O_SYNC|os.O_RDWR)
for counter in xrange(1, SIZE-16):
    write_loc = index_gen.next()*4
    page_dist = (write_loc%PAGESIZE)
    offset = write_loc - page_dist
    bytemap = mmap.mmap(filedesc, PAGESIZE, offset=offset)
    bytemap[page_dist:(page_dist+4)] = pack('>I', counter)
    bytemap.flush()
    bytemap.close()