【问题标题】:A better way of calculating top-32 file sizes for DFS folder staging size为 DFS 文件夹暂存大小计算前 32 个文件大小的更好方法
【发布时间】:2016-11-07 14:57:11
【问题描述】:

设置 DFS 副本时的一项常见任务是确定已复制文件夹中最大 32 个文件的大小 - 根据当前最佳实践,这些文件的总和应该是暂存区域的最小大小。

在 Technet 博客中给出了查找和计算此前 32 个文件大小的方法:https://blogs.technet.microsoft.com/askds/2011/07/13/how-to-determine-the-minimum-staging-area-dfsr-needs-for-a-replicated-folder/

它依赖于使用Get-ChildItem 查找路径中的所有文件及其大小,按大小排序,丢弃除最大的 32 个之外的所有文件,然后计算总和。

当您的路径中的文件数量有限时,这很好,但在索引包含数十万(如果不是数百万)文件的文件夹时存在严重缺陷。该进程在执行时会将所有内容转储到内存中 - 在我的示例中,它消耗超过 2GB 的虚拟内存 - 并且需要很长时间,即使单个文件非常小。内存一直分配到 PS 实例关闭。

PS C:\> measure-command { (get-childitem F:\Folder\with\966693\items -recurse | 
sort-object length -descending | select-object -first 32 | 
measure-object -property length -sum).sum }
Days              : 0
Hours             : 0
Minutes           : 6
Seconds           : 6
Milliseconds      : 641
Ticks             : 3666410633
TotalDays         : 0.00424353082523148
TotalHours        : 0.101844739805556
TotalMinutes      : 6.11068438833333
TotalSeconds      : 366.6410633
TotalMilliseconds : 366641.0633

【问题讨论】:

    标签: powershell microsoft-distributed-file-system


    【解决方案1】:

    如果您可以大大加快 Get-ChildItem 的速度,我会感到惊讶,除非您可以避免为每个文件构建 [IO.FileInfo] 对象(可能是 .Net DirectorySearcher?)。

    但是您可以通过不保留所有结果来减少内存需求,只保留正在进行的最大 N,在本示例中为 100,但调整以测试内存/性能,例如

    $BufferSize = 100
    $FileSizes = New-Object System.Collections.ArrayList
    
    Get-ChildItem 'd:\downloads' -Force -Recurse -File | ForEach {
    
        $null = $FileSizes.Add($_.Length)
        if ($FileSizes.Count -gt $BufferSize)
        {
            $FileSizes.Sort()
            $FileSizes.RemoveRange(0, ($BufferSize-32))
        }
    }
    ($FileSizes[0..31] | measure-object -Sum).Sum/1GB
    

    为 gci 添加了-Force 参数,以防一些最大的文件被隐藏。

    【讨论】:

    • 谢谢,通过丢弃不再需要的结果,这看起来更有效率。至于我的结果,它们在测试文件夹树中的 100K+ 文件时非常一致。我想解决这个问题,因为每次我在 120 万个项目文件集上尝试原始进程时,基本上都会在服务器上发生内存泄漏。这些特定文件集的一个特点是它们中的大部分由大小
    【解决方案2】:

    稍作调整 - 实例化 System.Collections.ArrayList 以存储文件长度列表 - 在同一目录上执行查询的时间几乎减半。当您向其中添加新项目时,您是 not constantly creating/destroying a standard fixed-sized array

    此示例的 Powershell 进程的内存使用量仍低于 900MB。如果我想重用 PS 控制台,我也喜欢将变量设置为 $null。

    measure command { $total = New-Object System.Collections.ArrayList; 
    gci F:\Folder\with\966693\items -file -r | 
    ForEach { $total.Add($_.length)>$null } ; 
    (($total | sort -descending | select -first 32 |measure-object -sum).sum/1GB) }
    Days              : 0
    Hours             : 0
    Minutes           : 3
    Seconds           : 34
    Milliseconds      : 215
    Ticks             : 2142159038
    TotalDays         : 0.00247935073842593
    TotalHours        : 0.0595044177222222
    TotalMinutes      : 3.57026506333333
    TotalSeconds      : 214.2159038
    TotalMilliseconds : 214215.9038
    

    更整洁的多行版本:

    $total = New-Object System.Collections.ArrayList
    gci F:\Folder\with\966693\items  -file -r | ForEach { $total.Add($_.length)>$null } 
    ($total | sort -descending | select -first 32 | measure-object -sum).sum/1GB
    

    【讨论】:

      猜你喜欢
      • 2011-08-17
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 2011-01-12
      • 2023-04-08
      • 1970-01-01
      相关资源
      最近更新 更多