Share via


Blob kapsayıcısının toplam faturalama boyutunu hesaplama

Bu betik, faturalama maliyetlerini tahmin etmek amacıyla Azure Blob depolamadaki bir kapsayıcının boyutunu hesaplar. Betik, kapsayıcıdaki blobların boyutunun toplamını alır.

Önemli

Bu makalede sağlanan örnek betik, blob anlık görüntüleri için faturalama boyutunu doğru hesaplamayabilir.

Bu örnek için Azure PowerShell gerekir. Sürümü bulmak için Get-Module -ListAvailable Az komutunu çalıştırın. Yüklemeniz veya yükseltmeniz gerekirse, bkz. Azure PowerShell Modülü yükleme.

Azure'a bağlanmak için Bağlan-AzAccount cmdlet'ini çalıştırın.

Azure aboneliğiniz yoksa başlamadan önce birücretsiz Azure hesabı oluşturun.

Dekont

Bu PowerShell betiği, faturalama amacıyla bir kapsayıcının boyutunu hesaplar. Kapsayıcı boyutunu başka amaçlarla hesaplıyorsanız, tahmin sağlayan daha basit bir betik için bkz . Blob depolama kapsayıcısının toplam boyutunu hesaplama.

Blob kapsayıcısının boyutunu belirleme

Blob kapsayıcısının toplam boyutu, kapsayıcının boyutunu ve kapsayıcı altındaki tüm blobların boyutunu içerir.

Aşağıdaki bölümlerde blob kapsayıcıları ve bloblar için depolama kapasitesinin nasıl hesaplandığı açıklanmaktadır. Aşağıdaki bölümde Len(X), dizedeki karakter sayısı anlamına gelir.

Blob kapsayıcıları

Aşağıdaki hesaplamada blob kapsayıcısı başına tüketilen depolama miktarının nasıl tahmin edilir açıklanmaktadır:

48 bytes + Len(ContainerName) * 2 bytes +
For-Each Metadata[3 bytes + Len(MetadataName) + Len(Value)] +
For-Each Signed Identifier[512 bytes]

Döküm aşağıdadır:

  • Her kapsayıcı için 48 bayt ek yük Son Değiştirme Zamanı, İzinler, Genel Ayarlar ve bazı sistem meta verilerini içerir.

  • Kapsayıcı adı Unicode olarak depolanır, bu nedenle karakter sayısını alın ve iki ile çarpın.

  • Depolanan her blob kapsayıcısı meta veri bloğu için adın uzunluğunu (ASCII) ve dize değerinin uzunluğunu depolarız.

  • İmzalı Tanımlayıcı başına 512 bayt, imzalı tanımlayıcı adı, başlangıç zamanı, süre sonu süresi ve izinleri içerir.

Bloblar

Aşağıdaki hesaplamalar, blob başına tüketilen depolama miktarının nasıl tahmin yapılacağını gösterir.

  • Blok blobu (temel blob veya anlık görüntü):

    124 bytes + Len(BlobName) * 2 bytes +
    For-Each Metadata[3 bytes + Len(MetadataName) + Len(Value)] +
    8 bytes + number of committed and uncommitted blocks * Block ID Size in bytes +
    SizeInBytes(data in unique committed data blocks stored) +
    SizeInBytes(data in uncommitted data blocks)
    
  • Sayfa blobu (temel blob veya anlık görüntü):

    124 bytes + Len(BlobName) * 2 bytes +
    For-Each Metadata[3 bytes + Len(MetadataName) + Len(Value)] +
    number of nonconsecutive page ranges with data * 12 bytes +
    SizeInBytes(data in unique pages stored)
    

Döküm aşağıdadır:

  • Blob için aşağıdakiler dahil 124 bayt ek yük:

    • Son Değiştirme Zamanı
    • Size
    • Önbellek Denetimi
    • İçerik Türü
    • İçerik Dili
    • İçerik Kodlama
    • Content-MD5
    • İzinler
    • Anlık görüntü bilgileri
    • Kira
    • Bazı sistem meta verileri
  • Blob adı Unicode olarak depolanır, bu nedenle karakter sayısını alın ve iki ile çarpın.

  • Depolanan her meta veri bloğu için adın uzunluğunu (ASCII olarak depolanır) ve dize değerinin uzunluğunu ekleyin.

  • Blok blobları için:

    • Blok listesi için 8 bayt.

    • Blok kimliği boyutunun bayt cinsinden blok sayısı.

    • Tüm işlenen ve kaydedilmemiş bloklardaki verilerin boyutu.

      Dekont

      Anlık görüntüler kullanıldığında, bu boyut yalnızca bu temel veya anlık görüntü blobu için benzersiz verileri içerir. Kaydedilmemiş bloklar bir hafta sonra kullanılmazsa, bunlar çöp toplanır. Bundan sonra faturalamaya doğru sayılmazlar.

  • Sayfa blobları için:

    • 12 bayt veri çarpımlı, bağımsız olmayan sayfa aralıklarının sayısı. Bu, GetPageRanges API'sini çağırırken gördüğünüz benzersiz sayfa aralıklarının sayısıdır.

    • Depolanan tüm sayfaların bayt cinsinden veri boyutu.

      Dekont

      Anlık görüntüler kullanıldığında, bu boyut yalnızca temel blob için benzersiz sayfaları veya sayılmakta olan anlık görüntü blobunu içerir.

Örnek betik

# this script will show how to get the total size of the blobs in a container
# before running this, you need to create a storage account, create a container,
#    and upload some blobs into the container
# note: this retrieves all of the blobs in the container in one command.
#       connect Azure with Login-AzAccount before you run the script.
#       requests sent as part of this tool will incur transactional costs.
# command line usage: script.ps1 -ResourceGroup {YourResourceGroupName} -StorageAccountName {YourAccountName} -ContainerName {YourContainerName}
#

param(
    [Parameter(Mandatory=$true)]
    [string]$ResourceGroup,

    [Parameter(Mandatory=$true)]
    [string]$StorageAccountName,

    [Parameter(Mandatory=$true)]
    [string]$ContainerName
)

#Set-StrictMode will cause Get-AzStorageBlob returns result in different data types when there is only one blob
#Set-StrictMode -Version 2

$VerbosePreference = "Continue"

if((Get-Module -ListAvailable Az.Storage) -eq $null)
{
    throw "Azure Powershell not found! Please install from https://docs.microsoft.com/en-us/powershell/azure/install-Az-ps"
}

# function Retry-OnRequest
function Retry-OnRequest
{
    param(
        [Parameter(Mandatory=$true)]
        $Action)

    # It could encounter various of temporary errors, like network errors, or storage server busy errors.
    # Should retry the request on transient errors

    # Retry on storage server timeout errors
    $clientTimeOut = New-TimeSpan -Minutes 15
    $retryPolicy = New-Object -TypeName Microsoft.Azure.Storage.RetryPolicies.ExponentialRetry -ArgumentList @($clientTimeOut, 10)
    $requestOption = @{}
    $requestOption.RetryPolicy = $retryPolicy

    # Retry on temporary network errors
    $shouldRetryOnException = $false
    $maxRetryCountOnException = 3

    do
    {
        try
        {
            return $Action.Invoke($requestOption)
        }
        catch
        {
            if ($_.Exception.InnerException -ne $null -And $_.Exception.InnerException.GetType() -Eq [System.TimeoutException] -And $maxRetryCountOnException -gt 0)
            {
                $shouldRetryOnException = $true
                $maxRetryCountOnException--
            }
            else
            {
                $shouldRetryOnException = $false
                throw
            }
        }
    }
    while ($shouldRetryOnException)

}

# function Get-BlobBytes

function Get-BlobBytes
{
    param(
        [Parameter(Mandatory=$true)]
        $Blob,
        [Parameter(Mandatory=$false)]
        [bool]$IsPremiumAccount = $false)

    # Base + blobname
    $blobSizeInBytes = 124 + $Blob.Name.Length * 2

    # Get size of metadata
    $metadataEnumerator=$Blob.ICloudBlob.Metadata.GetEnumerator()
    while($metadataEnumerator.MoveNext())
    {
        $blobSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + $metadataEnumerator.Current.Value.Length
    }

    if (!$IsPremiumAccount)
    {
        if($Blob.BlobType -eq [Microsoft.Azure.Storage.Blob.BlobType]::BlockBlob)
        {
            $blobSizeInBytes += 8
            # Default is Microsoft.Azure.Storage.Blob.BlockListingFilter.Committed. Need All
            $action = { param($requestOption) return $Blob.ICloudBlob.DownloadBlockList([Microsoft.Azure.Storage.Blob.BlockListingFilter]::All, $null, $requestOption) }

            $blocks=Retry-OnRequest $action

            if ($null -eq $blocks)
            {
                $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
            }
            else
            {
                $blocks | ForEach-Object { $blobSizeInBytes += $_.Length + $_.Name.Length }
            }
        }
        elseif($Blob.BlobType -eq [Microsoft.Azure.Storage.Blob.BlobType]::PageBlob)
        {
            # It could cause server time out issue when trying to get page ranges of highly fragmented page blob
            # Get page ranges in segment can mitigate chance of meeting such kind of server time out issue
            # See https://blogs.msdn.microsoft.com/windowsazurestorage/2012/03/26/getting-the-page-ranges-of-a-large-page-blob-in-segments/ for details.
            $pageRangesSegSize = 148 * 1024 * 1024L
            $totalSize = $Blob.ICloudBlob.Properties.Length
            $pageRangeSegOffset = 0

            $pageRangesTemp = New-Object System.Collections.ArrayList

            while ($pageRangeSegOffset -lt $totalSize)
            {
                $action = {param($requestOption) return $Blob.ICloudBlob.GetPageRanges($pageRangeSegOffset, $pageRangesSegSize, $null, $requestOption) }

                Retry-OnRequest $action | ForEach-Object { $pageRangesTemp.Add($_) }  | Out-Null
                $pageRangeSegOffset += $pageRangesSegSize
            }

            $pageRanges = New-Object System.Collections.ArrayList

            foreach ($pageRange in $pageRangesTemp)
            {
                if($lastRange -eq $Null)
                {
                    $lastRange = New-Object PageRange
                    $lastRange.StartOffset = $pageRange.StartOffset
                    $lastRange.EndOffset =  $pageRange.EndOffset
                }
                else
                {
                    if (($lastRange.EndOffset + 1) -eq $pageRange.StartOffset)
                    {
                        $lastRange.EndOffset = $pageRange.EndOffset
                    }
                    else
                    {
                        $pageRanges.Add($lastRange)  | Out-Null
                        $lastRange = New-Object PageRange
                        $lastRange.StartOffset = $pageRange.StartOffset
                        $lastRange.EndOffset =  $pageRange.EndOffset
                    }
                }
            }

            $pageRanges.Add($lastRange) | Out-Null
            $pageRanges |  ForEach-Object {
                    $blobSizeInBytes += 12 + $_.EndOffset - $_.StartOffset
                }
        }
        else
        {
            $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
        }
        return $blobSizeInBytes
    }
    else
    {
        $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
    }
    return $blobSizeInBytes
}

# function Get-ContainerBytes

function Get-ContainerBytes
{
    param(
        [Parameter(Mandatory=$true)]
        [Microsoft.Azure.Storage.Blob.CloudBlobContainer]$Container,
        [Parameter(Mandatory=$false)]
        [bool]$IsPremiumAccount = $false)

    # Base + name of container
    $containerSizeInBytes = 48 + $Container.Name.Length*2

    # Get size of metadata
    $metadataEnumerator = $Container.Metadata.GetEnumerator()
    while($metadataEnumerator.MoveNext())
    {
        $containerSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + $metadataEnumerator.Current.Value.Length
    }

    # Get size for SharedAccessPolicies
    $containerSizeInBytes += $Container.GetPermissions().SharedAccessPolicies.Count * 512

    # Calculate size of all blobs.
    $blobCount = 0
    $Token = $Null
    $MaxReturn = 5000

    do {
        $Blobs = Get-AzStorageBlob -Context $storageContext -Container $Container.Name -MaxCount $MaxReturn -ContinuationToken $Token
        if($Blobs -eq $Null) { break }

        #Set-StrictMode will cause Get-AzStorageBlob returns result in different data types when there is only one blob
        if($Blobs.GetType().Name -eq "AzureStorageBlob")
        {
            $Token = $Null
        }
        else
        {
            $Token = $Blobs[$Blobs.Count - 1].ContinuationToken;
        }

        $Blobs | ForEach-Object {
                $blobSize = Get-BlobBytes $_ $IsPremiumAccount
                $containerSizeInBytes += $blobSize
                $blobCount++

                if(($blobCount % 1000) -eq 0)
                {
                    Write-Verbose("Counting {0} Sizing {1} " -f $blobCount, $containerSizeInBytes)
                }
            }
    }
    While ($Token -ne $Null)

    return @{ "containerSize" = $containerSizeInBytes; "blobCount" = $blobCount }
}

#Login-AzAccount

$storageAccount = Get-AzStorageAccount -ResourceGroupName $ResourceGroup -Name $StorageAccountName -ErrorAction SilentlyContinue
if($storageAccount -eq $null)
{
    throw "The storage account specified does not exist in this subscription."
}

$storageContext = $storageAccount.Context

if (-not ([System.Management.Automation.PSTypeName]'PageRange').Type)
{
    $Source = "
        public class PageRange
        {
            public long StartOffset;
            public long EndOffset;
        }"
    Add-Type -TypeDefinition $Source
}

$containers = New-Object System.Collections.ArrayList
if($ContainerName.Length -ne 0)
{
    $container = Get-AzStorageContainer -Context $storageContext -Name $ContainerName -ErrorAction SilentlyContinue |
        ForEach-Object { $containers.Add($_) } | Out-Null
}
else
{
    Get-AzStorageContainer -Context $storageContext | ForEach-Object { $containers.Add($_) } | Out-Null
}

$sizeInBytes = 0
$IsPremiumAccount = ($storageAccount.Sku.Tier -eq "Premium")

if($containers.Count -gt 0)
{
    $containers | ForEach-Object {
        Write-Output("Calculating container {0} ..." -f $_.CloudBlobContainer.Name)
        $result = Get-ContainerBytes $_.CloudBlobContainer $IsPremiumAccount
        $sizeInBytes += $result.containerSize

        Write-Output("Container '{0}' with {1} blobs has a sizeof {2:F2} MB." -f $_.CloudBlobContainer.Name,$result.blobCount,($result.containerSize/1MB))
    }
}
else
{
    Write-Warning "No containers found to process in storage account '$StorageAccountName'."
}

Sonraki adımlar