>必须写入大量单个文件,通常为10000
>文件必须是人类可读的,即格式化的I / O.
>定期向每个文件添加一个新行.通常每50秒.
>新数据几乎可以立即访问,因此不能选择大型手动写入缓冲区
>我们使用的是Lustre文件系统,它似乎针对相反的情况进行了优化:顺序写入少量大文件.
制定要求的不是我,所以不幸的是,讨论它们没有意义.我只想找到具有上述先决条件的最佳解决方案.
我想出了一个小例子来测试一些实现.这是迄今为止我能做的最好的事情:
!===============================================================! ! program to test some I/O implementations for many small files ! !===============================================================! PROGRAM iotest use types use omp_lib implicit none INTEGER(I4B), PARAMETER :: steps = 1000 INTEGER(I4B), PARAMETER :: monitors = 1000 INTEGER(I4B), PARAMETER :: cachesize = 10 INTEGER(I8B) :: counti, countf, count_rate, counti_global, countf_global REAL(DP) :: telapsed, telapsed_global REAL(DP), DIMENSION(:,:), ALLOCATABLE :: density, pressure, vel_x, vel_y, vel_z INTEGER(I4B) :: n, t, unitnumber, c, i, thread CHARACTER(LEN=100) :: dummy_char, number REAL(DP), DIMENSION(:,:,:), ALLOCATABLE :: writecache_real call system_clock(counti_global,count_rate) ! allocate cache allocate(writecache_real(5,cachesize,monitors)) writecache_real = 0.0_dp ! fill values allocate(density(steps,monitors), pressure(steps,monitors), vel_x(steps,monitors), vel_y(steps,monitors), vel_z(steps,monitors)) do n=1, monitors do t=1, steps call random_number(density(t,n)) call random_number(pressure(t,n)) call random_number(vel_x(t,n)) call random_number(vel_y(t,n)) call random_number(vel_z(t,n)) end do end do ! create files do n=1, monitors write(number,'(I0.8)') n dummy_char = 'monitor_' // trim(adjustl(number)) // '.dat' open(unit=20, file=trim(adjustl(dummy_char)), status='replace', action='write') close(20) end do call system_clock(counti) ! write data c = 0 do t=1, steps c = c + 1 do n=1, monitors writecache_real(1,c,n) = density(t,n) writecache_real(2,c,n) = pressure(t,n) writecache_real(3,c,n) = vel_x(t,n) writecache_real(4,c,n) = vel_y(t,n) writecache_real(5,c,n) = vel_z(t,n) end do if(c .EQ. cachesize .OR. t .EQ. steps) then !$OMP PARALLEL DEFAULT(SHARED) PRIVATE(n,number,dummy_char,unitnumber, thread) thread = OMP_get_thread_num() unitnumber = thread + 20 !$OMP DO do n=1, monitors write(number,'(I0.8)') n dummy_char = 'monitor_' // trim(adjustl(number)) // '.dat' open(unit=unitnumber, file=trim(adjustl(dummy_char)), status='old', action='write', position='append', buffered='yes') write(unitnumber,'(5ES25.15)') writecache_real(:,1:c,n) close(unitnumber) end do !$OMP END DO !$OMP END PARALLEL c = 0 end if end do call system_clock(countf) call system_clock(countf_global) telapsed=real(countf-counti,kind=dp)/real(count_rate,kind=dp) telapsed_global=real(countf_global-counti_global,kind=dp)/real(count_rate,kind=dp) write(*,*) write(*,'(A,F15.6,A)') ' elapsed wall time for I/O: ', telapsed, ' seconds' write(*,'(A,F15.6,A)') ' global elapsed wall time: ', telapsed_global, ' seconds' write(*,*) END PROGRAM iotest
主要功能包括:OpenMP并行化和手动写入缓冲区.
以下是Luster文件系统中有16个线程的一些时序:
> cachesize = 5:I / O经过的挂起时间:991.627404秒
> cachesize = 10:I / O的耗用时间:415.456265秒
> cachesize = 20:I / O的耗用时间:93.842964秒
> cachesize = 50:I / O的经过时间:79.859099秒
> cachesize = 100:I / O经过的挂起时间:23.937832秒
> cachesize = 1000:I / O经过的挂起时间:10.472421秒
有关已停用HDD写入缓存的本地工作站HDD上的结果参考,16个线程:
> cachesize = 1:I / O的已用壁时间:5.543722秒
> cachesize = 2:I / O经过的挂起时间:2.791811秒
> cachesize = 3:I / O经过的挂起时间:1.752962秒
> cachesize = 4:I / O经过的挂起时间:1.630385秒
> cachesize = 5:I / O经过的挂起时间:1.174099秒
> cachesize = 10:I / O经过的挂起时间:0.700624秒
> cachesize = 20:I / O的经过时间:0.433936秒
> cachesize = 50:I / O的经过时间:0.425782秒
> cachesize = 100:I / O的经过时间:0.227552秒
正如您所看到的,与普通硬盘相比,Lustre文件系统的实现速度仍然令人尴尬,我需要巨大的缓冲区大小才能将I / O开销降低到可容忍的程度.这意味着产量落后于先前制定的要求.
另一种有希望的方法是在连续写入之间使单元保持打开不幸的是,同时打开的单元数量通常限制为1024-4096,没有root权限.因此,这不是一个选项,因为文件数量可能超过此限制.
如何在满足要求的同时进一步降低I / O开销?
编辑1
通过与Gilles的讨论,我了解到即使使用普通用户权限也可以调整光泽文件系统.所以我尝试按照建议将条带计数设置为1(这已经是默认设置)并将条带大小减小到支持的最小值64k(默认值为1M).但是,这并没有改善我的测试用例的I / O性能.如果有人对更合适的文件系统设置有其他提示,请告诉我.
http://cdn.opensfs.org/wp-contenthttp://img.558idc.com/uploadfile/2018/04/Leers-Lustre-Data_on_MDT_An_Early_Look_DDN.pdf
lfs setstripe -E 1M -L mdt -E -1 fubar fill存储MDT目录fubar中所有文件的第一兆字节