【发布时间】:2021-03-28 05:43:50
【问题描述】:
在我的应用程序中,它将一个大文件 (650GB) 写入 SSD。其中包含大量约 1k 条消息。消息不是固定长度的。因此,我根据几个消息过滤条件的需要维护一个内存索引。索引包含文件的位置。
在一种情况下,一个索引中几乎所有对应的消息都以大约 63,000 字节的距离写入磁盘。这意味着当读取一条消息 (~1k) 时,应用程序必须在文件中寻找另一个 ~63,000 条消息以读取下一条消息。当 OS 磁盘缓存被删除时(sync; echo 1 > /proc/sys/vm/drop_caches;),应用程序每秒只能读取大约 12,000 条消息。那是 12MB/秒。那是实际行为吗?请指教。 我准备了一个小应用程序来模拟。
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <iostream>
#include <unistd.h>
using namespace std;
uint64_t gethrtime_us()
{
timeval tv;
gettimeofday(&tv, NULL);
uint64_t t = tv.tv_sec;
t = t * 1000 * 1000 + tv.tv_usec;
return t;
}
int main(int argc, const char** argv)
{
uint64_t gap = atol(argv[1]);
uint64_t messages = atol(argv[2]);
int32_t fd = open("/mnt/OC/data", O_RDONLY);// data.txt is 650GB binary data
if (fd < 0)
{
cout << "Open Error" << endl;
return 1;
}
uint64_t startTime = gethrtime_us();
uint64_t totalReadSize = 0;
for (uint64_t i = 0 ; i < messages ; i++)
{
char message[1024];
if (read(fd, message, 1024) != 1024)
{
cout << "Read Error @" << i << endl;
break;
}
if (lseek(fd, gap, SEEK_CUR) == -1)
{
cout << "Seek Error @" << i << endl;
break;
}
}
uint64_t endTime = gethrtime_us();
cout << "Time taken " << (endTime - startTime) << " micro seconds" << endl;
return 0;
}
测试结果如下。
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # g++ -std=c++11 -O3 Main.cpp;
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 0 100000
Time taken 172105 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 1000 100000
Time taken 318472 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 2000 100000
Time taken 446191 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 3000 100000
Time taken 561590 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 4000 100000
Time taken 702702 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 5000 100000
Time taken 874044 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 6000 100000
Time taken 1105384 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 7000 100000
Time taken 1698921 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 8000 100000
Time taken 1165863 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 9000 100000
Time taken 7445158 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 10000 100000
Time taken 8033516 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 15000 100000
Time taken 8950091 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 20000 100000
Time taken 9135020 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 30000 100000
Time taken 9180888 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 40000 100000
Time taken 9123635 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 50000 100000
Time taken 9181108 micro seconds
root@comp|centos7|3.10.0-957.5.1.el7:0:bin # sync; echo 1 > /proc/sys/vm/drop_caches; ./a.out 60000 100000
Time taken 9141465 micro seconds
在最后一种情况下,每 9 秒有 100000 条消息。 (100000 * 1k) / 9 = 11111kb/s
我很担心为什么 SDD 制造商声称 ~2.3 GB/s 的顺序读取速率获得了 OC 磁盘缓存的好处,而在这种情况下他们只能做到 12MB/s。 请指教。
【问题讨论】:
-
小型随机写入的典型写入速度低于 200 MB/s。以下是一些信息:https://www.thessdreview.com/ssd-guides/beginners-guide/the-ssd-manufacturers-bluff/2/ 查看前 4K 数字,而不是 QD32 或线程 4K。
-
对于小的随机 I/O,MBPS 没有意义。测量 IOPS。由于您正在通过文件系统,因此 I/O 比程序中明确的 I/O 多。使用 iostat 之类的工具进行测量。
-
这些是“内存索引”字节偏移还是消息索引偏移?
-
我认为制造商声称 ~2.3 GB/s 顺序读取速率,然后在“随机且非常非顺序读取”中没有提供 ~2,3 GB/s 没有任何问题” 情况。
-
如果可以的话,我还建议尝试异步 IO。使用阻塞 IO(例如
read()),SSD 可能将一半的时间用于等待下一个读取请求,而 CPU 将另一半时间用于等待前一个读取完成。对于顺序读取,这可以通过在请求数据之前检测模式和预取数据来“隐藏”(在操作系统和 SSD 中)。
标签: c++ c performance file-read solid-state-drive