此指令碼會就估計成本計費之目的計算 Azure Blob 儲存體中的容器大小。 指令碼會加總容器中的 blob 大小。
重要
本文中提供的範例指令碼可能不會精確計算 Blob 快照集的計費大小。
此範例需要 Azure PowerShell。 執行 Get-Module -ListAvailable Az 以尋找版本。
如果您需要安裝或升級,請參閱安裝 Azure PowerShell 模組。
執行 Connect-AzAccount Cmdlet 以連線到 Azure。
如果您沒有 Azure 帳戶,請在開始之前建立 免費帳戶 。
注意
這個 PowerShell 指令碼會就計費目的計算容器大小。 如果您計算容器大小是要用於其他用途,請參閱計算 Blob 儲存體容器的大小總計,以了解提供估計值的簡單指令碼。
決定 Blob 容器的大小
Blob 容器的大小總計包含容器本身的大小和容器下所有 Blob 的大小。
以下各節描述對 Blob 容器和 Blob 儲存體容量的計算方式。 在下節中,Len(X) 表示字串中的字元數。
Blob 容器
以下計算說明如何估計每個 Blob 容器使用的儲存體數量:
48 bytes + Len(ContainerName) * 2 bytes +
For-Each Metadata[3 bytes + Len(MetadataName) + Len(Value)] +
For-Each Signed Identifier[512 bytes]
以下是分解:
每個容器 48 個位元組的額外負荷包含上次修改時間、權限、公用設定,以及一些系統中繼資料。
容器名稱會儲存為 Unicode,因此取得字元數目並乘以 2。
對於儲存的每個 Blob 容器中繼資料區塊,我們會儲存名稱的長度 (ASCII) 再加上字串值的長度。
每一簽署的識別碼 512 個位元組包括簽署的識別碼名稱、開始時間、到期時間和權限。
Blob群
以下計算顯示如何估計每個 Blob 使用的儲存體數量。
區塊 BLOB(基礎 BLOB 或快照):
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)分頁 Blob(基礎 Blob 或快照):
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)
以下是分解:
Blob 的額外負荷為 124 位元組,其中包含:
- 上次修改時間
- 大小
- Cache-Control
- 內容-類型
- 內容語言
- 內容編碼
- 內容-MD5
- 權限
- 快照資訊
- 租用
- 部分系統中繼資料
Blob 名稱會儲存為 Unicode,因此取得字元數目並乘以 2。
對於儲存的每個中繼資料區塊,加上名稱的長度 (以 ASCII 儲存),再加上字串值的長度。
對於區塊 Blob:
區塊清單需要 8 字節。
區塊數目 × 區塊 ID 的位元組大小。
所有已提交和未提交的區塊中的資料大小。
注意
使用快照集時,此大小只包含此基底或快照集 Blob 的唯一資料。 如果未認可的區塊在一週後仍未被使用,將進行垃圾回收。 此後,這些不會計入帳單。
對於 Page Blobs:
非連續分頁範圍的數量乘以具有資料的 12 個位元組。 這是呼叫 GetPageRanges API 時會看到的唯一分頁範圍的數目。
所有儲存的分頁中資料的大小 (以位元組為單位)。
注意
使用快照時,此大小僅包含基底 Blob 或被計算的快照 Blob 的唯一頁面。
範例指令碼
# 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'."
}
下一步
請參閱計算 Blob 儲存體容器的大小總計提供容器大小之估計值的簡單指令碼。
如需有關 Azure 儲存體計費的詳細資訊,請參閱了解 Windows Azure 儲存體計費。
如需有關 Azure PowerShell 模組的詳細資訊,請參閱 Azure PowerShell 文件。
您可以在 Azure 儲存體的 PowerShell 範例 找到其他的儲存體 PowerShell 指令碼範例。