Вычисление общего указываемого в счете размера контейнера больших двоичных объектов
В этом скрипте вычисляется размер контейнера в хранилище BLOB-объектов Azure для оценки затрат при выставлении счетов. При помощи скрипта вычисляется суммарный размер больших двоичных объектов в контейнере.
Внимание
Пример скрипта, приведенный в этой статье, может неточно рассчитывать размер с выставлением счетов для моментальных снимков BLOB-объектов.
Для этого примера требуется Azure PowerShell. Чтобы узнать версию, выполните команду Get-Module -ListAvailable Az
.
Если вам необходимо выполнить установку или обновление, см. статью об установке модуля Azure PowerShell.
Запустите командлет Connect AzAccount, чтобы подключиться к Azure.
Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.
Примечание.
В этом скрипте PowerShell вычисляется размер контейнера для выставления счетов. Если вы рассчитываете размер для других целей, воспользуйтесь простым сценарием в разделе Вычисление размера контейнера больших двоичных объектов.
Определение размера контейнера больших двоичных объектов
Общий размер контейнера больших двоичных объектов включает размер самого контейнера и размер всех больших двоичных объектов в контейнере.
В следующем разделе описывается, как вычисляется емкость хранилища для контейнеров больших двоичных объектов и больших двоичных объектов. В следующем разделе Len(X) означает число знаков в строке.
контейнеров BLOB-объектов;
В следующем вычислении показано, как оценить объем хранилища, потребляемого контейнером больших двоичных объектов.
48 bytes + Len(ContainerName) * 2 bytes +
For-Each Metadata[3 bytes + Len(MetadataName) + Len(Value)] +
For-Each Signed Identifier[512 bytes]
Ниже показан разбор:
48 байт нагрузки для каждого контейнера включают время последнего изменения, разрешения, общедоступные параметры и некоторые системные метаданные.
Имя контейнера хранится в формате Юникода, поэтому умножьте количество знаков на два.
Для всех сохраняемых блоков метаданных контейнера больших двоичных объектов сохраняется длина имени (в формате ASCII) и длина строкового значения.
512 байт каждого идентификатора подписи содержат имя подписанного идентификатора, время начала срока действия, время окончания срока действия и разрешения.
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-объект (базовый большой двоичный объект или моментальный снимок):
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)
Ниже показан разбор:
124 байт нагрузки для большого двоичного объекта, который включает в себя:
- время последнего изменения;
- Размер
- Cache-Control
- Тип контента
- Content-Language;
- Content-Encoding
- Content-MD5;
- Разрешения
- сведения о моментальном снимке;
- Аренда
- некоторые системные метаданные.
Имя большого двоичного объекта хранится в формате Юникода, поэтому умножьте количество знаков на два.
Для каждого блока сохраняемых метаданных сохраняется длина имени (в формате ASCII) и длина строкового значения.
Для блочных BLOB-объектов:
8 байт для списка блокировок;
количество блоков равно размеру идентификатора блока в байтах;
размер данных во всех зафиксированных и незафиксированных блоках.
Примечание.
При использовании моментальных снимков этот размер включает только уникальные данные для этого базового большого двоичного объекта или большого двоичного объекта моментального снимка. Если незафиксированные блоки не используются в течение недели, они удаляются при сборке мусора. После этого они не учитываются при выставлении счетов.
Для страничных BLOB-объектов:
Число непоследовательных диапазонов страниц данных равно 12 байтам. Это число уникальных диапазонов страницы, отображаемых при вызове API GetPageRanges.
Объем данных в байтах для всех сохраненных страниц.
Примечание.
При использовании моментальных снимков этот размер включает только учитываемые уникальные страницы для базового большого двоичного объекта или большого двоичного объекта моментального снимка.
Пример скрипта
# 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'."
}
Следующие шаги
Простой сценарий оценки размера контейнеров см. в разделе Вычисление размера контейнера больших двоичных объектов.
Дополнительные сведения о выставлении счетов в службе хранилища Azure см. в статье Understanding Windows Azure Storage Billing – Bandwidth, Transactions, and Capacity (Общие сведения о выставлении счетов в службе хранилища Azure. Пропускная способность, транзакции и емкость).
Дополнительные сведения о модуле Azure PowerShell см. в документации по Azure PowerShell.
Дополнительные примеры сценариев PowerShell хранилища см. в статье Примеры Azure PowerShell для хранилища BLOB-объектов Azure.