Azure 스토리지 BLOB에 캐시 제어 및 만료 헤더 추가
정적 파일 블롭을 제공하기 위해 Azure 스토리지를 사용하고 있지만 대역폭 비용을 줄이기 위해 파일/블롭에 캐시 제어 및 만료 헤더를 추가하고 싶습니다.
CloudXplor 및 Cerebrata의 Cloud Storage Studio와 같은 애플리케이션은 컨테이너 및 블롭에 메타데이터 속성을 설정할 수 있는 옵션을 제공하지만 Cache-Control을 추가하려고 하면 문제가 발생합니다.
이 헤더들을 파일로 설정할 수 있는지 아는 사람?
저는 약 600,000개의 블롭에 대한 일괄 작업을 실행해야 했고 실제로 도움이 되는 두 가지를 발견했습니다.
- 동일한 데이터 센터의 작업자 역할에서 작업을 실행합니다.Azure 서비스가 동일한 선호도 그룹에 있는 한 서비스 간 속도가 매우 빠릅니다.또한 데이터 전송 비용도 없습니다.
작업을 병렬로 실행합니다..net v4의 TPL(Task Parallel Library)은 이를 매우 쉽게 해줍니다.컨테이너의 모든 BLOB에 대해 캐시 제어 헤더를 병렬로 설정하는 코드는 다음과 같습니다.
// get the info for every blob in the container var blobInfos = cloudBlobContainer.ListBlobs( new BlobRequestOptions() { UseFlatBlobListing = true }); Parallel.ForEach(blobInfos, (blobInfo) => { // get the blob properties CloudBlob blob = container.GetBlobReference(blobInfo.Uri.ToString()); blob.FetchAttributes(); // set cache-control header if necessary if (blob.Properties.CacheControl != YOUR_CACHE_CONTROL_HEADER) { blob.Properties.CacheControl = YOUR_CACHE_CONTROL_HEADER; blob.SetProperties(); } });
여기 애저의 넷 5와 V12를 사용한 조엘 필모어의 답변의 업데이트된 버전이 있습니다.보관소.Blobs. (단, 부모 컨테이너에 기본 헤더 속성을 설정할 수 있다면 좋지 않을까요?)
웹 사이트를 만들고 작업자 역할을 사용하는 대신 Azure는 "웹 작업"을 실행할 수 있습니다.저장소 계정이 있는 동일한 데이터 센터의 웹 사이트에서 필요에 따라 실행 파일을 실행하여 캐시 헤더 또는 다른 헤더 필드를 설정할 수 있습니다.
- 스토리지 계정과 동일한 데이터 센터에 일회용 임시 웹 사이트를 생성합니다.선호도 그룹에 대해 걱정하지 말고 빈 ASP.NET 사이트 또는 다른 단순 사이트를 만듭니다.내용은 중요하지 않습니다.적어도 B1 서비스 플랜을 사용해야 했습니다. 그렇지 않으면 5분 후에 웹 작업이 중단되었습니다.
- 업데이트된 Azure Storage API와 함께 작동하는 아래 코드를 사용하여 콘솔 프로그램을 만듭니다.릴리스용으로 컴파일한 다음 실행 파일과 필요한 모든 DLL을 .zip 파일로 압축하거나 Visual Studio에서 게시하고 아래 #3을 건너뜁니다.
- WebJob을 생성하고 2단계에서 .zip 파일을 업로드합니다.
- 웹 작업을 실행합니다.콘솔에 작성된 모든 내용은 생성된 로그 파일에서 볼 수 있으며 WebJob 제어 페이지에서 액세스할 수 있습니다.

- 임시 웹 사이트를 삭제하거나 "스케일 업"에서 자유 계층으로 변경합니다.
아래 코드는 각 컨테이너에 대해 별도의 작업을 실행하며 분당 최대 10만 개의 헤더가 업데이트됩니다(시간에 따라 다름).탈출 비용 없음.
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AzureHeaders
{
class Program
{
private static string connectionString = "DefaultEndpointsProtocol=https;AccountName=REPLACE_WITH_YOUR_CONNECTION_STRING";
private static string newCacheControl = "public, max-age=7776001"; // 3 months
private static string[] containersToProcess = { "container1", "container2" };
static async Task Main(string[] args)
{
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
var tasks = new List<Task>();
foreach (var container in containersToProcess)
{
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(container);
tasks.Add(Task.Run(() => UpdateHeaders(containerClient, 1000))); // I have no idea what segmentSize should be!
}
Task.WaitAll(tasks.ToArray());
}
private static async Task UpdateHeaders(BlobContainerClient blobContainerClient, int? segmentSize)
{
int processed = 0;
int failed = 0;
try
{
// Call the listing operation and return pages of the specified size.
var resultSegment = blobContainerClient.GetBlobsAsync()
.AsPages(default, segmentSize);
// Enumerate the blobs returned for each page.
await foreach (Azure.Page<BlobItem> blobPage in resultSegment)
{
var tasks = new List<Task>();
foreach (BlobItem blobItem in blobPage.Values)
{
BlobClient blobClient = blobContainerClient.GetBlobClient(blobItem.Name);
tasks.Add(UpdateOneBlob(blobClient));
processed++;
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine($"Container {blobContainerClient.Name} processed: {processed}");
}
}
catch (RequestFailedException e)
{
Console.WriteLine(e.Message);
failed++;
}
Console.WriteLine($"Container {blobContainerClient.Name} processed: {processed}, failed: {failed}");
}
private static async Task UpdateOneBlob(BlobClient blobClient) {
Response<BlobProperties> propertiesResponse = await blobClient.GetPropertiesAsync();
BlobHttpHeaders httpHeaders = new BlobHttpHeaders
{
// copy any existing headers you wish to preserve
ContentType = propertiesResponse.Value.ContentType,
ContentHash = propertiesResponse.Value.ContentHash,
ContentEncoding = propertiesResponse.Value.ContentEncoding,
ContentDisposition = propertiesResponse.Value.ContentDisposition,
// update CacheControl
CacheControl = newCacheControl
};
await blobClient.SetHttpHeadersAsync(httpHeaders);
}
}
}
Cerebrata Cloud Storage Studio의 최신 버전인 v2011.04.23.00은 개별 BLOB 개체에 대한 캐시 제어 설정을 지원합니다.BLOB 개체를 마우스 오른쪽 버튼으로 클릭하고 "BLOB 속성 보기/편집"을 선택한 다음 값을 설정합니다.Cache-Control기여하다.(예:public, max-age=2592000).
curl을 사용하여 Blob 객체의 HTTP 헤더를 확인하면 설정한 값과 함께 캐시 제어 헤더가 반환됩니다.
때로는 가장 간단한 답이 가장 좋은 답입니다.소량의 블롭만 관리하려는 경우 Azure Management를 사용하여 블롭의 헤더/메타데이터를 변경할 수 있습니다.
- 스토리지를 클릭한 다음 스토리지 계정 이름을 클릭합니다.
- 컨테이너 탭을 클릭한 다음 컨테이너를 클릭합니다.
- 블롭을 클릭한 다음 화면 하단에 있는 편집을 클릭합니다.
해당 편집 창에서 캐시 제어, 내용 인코딩, 내용 언어 등을 사용자 정의할 수 있습니다.
참고:현재 Azure 포털에서 이 데이터를 편집할 수 없습니다.
최신 CloudBerry Explorer가 이제 캐시 제어를 지원합니다. http://www.cloudberrylab.com/forum/default.aspx?g=posts&t=3047
다음은 Windows Azure를 사용하는 Joel Fillmore의 답변 업데이트 버전입니다.Storage v9.3.3.3.ListBlobsSegmentedAsync가 페이지 크기를 5,000개 반환하므로 BlobContinuation이 표시됩니다.토큰이 사용됩니다.
public async Task BackfillCacheControlAsync()
{
var container = await GetCloudBlobContainerAsync();
BlobContinuationToken continuationToken = null;
do
{
var blobInfos = await container.ListBlobsSegmentedAsync(string.Empty, true, BlobListingDetails.None, null, continuationToken, null, null);
continuationToken = blobInfos.ContinuationToken;
foreach (var blobInfo in blobInfos.Results)
{
var blockBlob = (CloudBlockBlob)blobInfo;
var blob = await container.GetBlobReferenceFromServerAsync(blockBlob.Name);
if (blob.Properties.CacheControl != "public, max-age=31536000")
{
blob.Properties.CacheControl = "public, max-age=31536000";
await blob.SetPropertiesAsync();
}
}
}
while (continuationToken != null);
}
private async Task<CloudBlobContainer> GetCloudBlobContainerAsync()
{
var storageAccount = CloudStorageAccount.Parse(_appSettings.AzureStorageConnectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("uploads");
return container;
}
답변하기에는 너무 늦었을 수도 있지만, 최근에는 이미지 목록이 있고 파워셸 스크립트(물론 Azure 스토리지 어셈블리의 도움을 받아)를 사용하여 적용해야 하는 다른 방식으로 동일한 작업을 수행하고 싶었습니다.
파워셸 스크립트를 사용한 Set Azure blob 캐시 제어에서 제공되는 완전한 설명
Add-Type -Path "C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.3\ref\Microsoft.WindowsAzure.StorageClient.dll"
$accountName = "[azureaccountname]"
$accountKey = "[azureaccountkey]"
$blobContainerName = "images"
$storageCredentials = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey -ArgumentList $accountName,$accountKey
$storageAccount = New-Object Microsoft.WindowsAzure.CloudStorageAccount -ArgumentList $storageCredentials,$true
#$blobClient = $storageAccount.CreateCloudBlobClient()
$blobClient = [Microsoft.WindowsAzure.StorageClient.CloudStorageAccountStorageClientExtensions]::CreateCloudBlobClient($storageAccount)
$cacheControlValue = "public, max-age=604800"
echo "Setting cache control: $cacheControlValue"
Get-Content "imagelist.txt" | foreach {
$blobName = "$blobContainerName/$_".Trim()
echo $blobName
$blob = $blobClient.GetBlobReference($blobName)
$blob.Properties.CacheControl = $cacheControlValue
$blob.SetProperties()
}
다음은 PowerShell이 설치된 윈도우즈 시스템에 설치되지 않은 모든 사용자를 위한 배치/유닉스 스크립트입니다.다음 스크립트는 모든 블롭을 순환하고 블롭의 Content-Cache 속성(Cache-Control http 헤더)을 개별적으로 설정합니다.
안타깝게도 여러 블롭에 동시에 속성을 설정할 수 있는 방법이 없으므로 시간이 많이 소요되는 작업입니다.보통 한 방울당 1-2초 정도 걸립니다.그러나 Jay Boresth가 지적했듯이 스토리지 계정과 동일한 데이터 센터의 서버에서 실행하면 프로세스가 상당히 가속화됩니다.
# Update Azure Blob Storage blob's cache-control headers
# /content-cache properties
#
# Quite slow, since there is no `az storage blob update-batch`
#
# Created by Jon Tingvold, March 2021
#
#
# If you want progress, you need to install pv:
# >>> brew install pv # Mac
# >>> sudo apt install pv # Ubuntu
#
set -e # exit when any command fails
AZURE_BLOB_CONNECTION_STRING='DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=XXXXXXXXXXXX;AccountKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='
CONTAINER_NAME=main
BLOB_PREFIX='admin/'
CONTENT_CACHE='max-age=3600'
NUM_RESULTS=10000000 # Defaults to 5000
BLOB_NAMES=$(az storage blob list --connection-string $AZURE_BLOB_CONNECTION_STRING --container-name $CONTAINER_NAME --query '[].name' --output tsv --num-results $NUM_RESULTS --prefix $BLOB_PREFIX)
NUMBER_OF_BLOBS=$(echo $BLOB_NAMES | wc -w)
echo "Ask Azure for files in Blob Storage ..."
echo "Set content-cache on $NUMBER_OF_BLOBS blobs ..."
for BLOB_NAME in $BLOB_NAMES
do
az storage blob update --connection-string $AZURE_BLOB_CONNECTION_STRING --container-name $CONTAINER_NAME --name $BLOB_NAME --content-cache $CONTENT_CACHE > /dev/null;
echo "$BLOB_NAME"
# If you don't have pv install, uncomment everything after done
done | cat | pv -pte --line-mode --size $NUMBER_OF_BLOBS > /dev/null
PowerShell 스크립트별로 스토리지 BLOB 캐시 제어 속성 설정
https://gallery.technet.microsoft.com/How-to-set-storage-blob-4774aca5
#creat CloudBlobClient
Add-Type -Path "C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.3\ref\Microsoft.WindowsAzure.StorageClient.dll"
$storageCredentials = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey -ArgumentList $StorageName,$StorageKey
$blobClient = New-Object Microsoft.WindowsAzure.StorageClient.CloudBlobClient($BlobUri,$storageCredentials)
#set Properties and Metadata
$cacheControlValue = "public, max-age=60480"
foreach ($blob in $blobs)
{
#set Metadata
$blobRef = $blobClient.GetBlobReference($blob.Name)
$blobRef.Metadata.Add("abcd","abcd")
$blobRef.SetMetadata()
#set Properties
$blobRef.Properties.CacheControl = $cacheControlValue
$blobRef.SetProperties()
}
언급URL : https://stackoverflow.com/questions/4507657/add-cache-control-and-expires-headers-to-azure-storage-blobs
'codememo' 카테고리의 다른 글
| 코코아 포드를 설치하려면 어떻게 해야 합니까? (0) | 2023.05.23 |
|---|---|
| Python: openpyxl 글꼴을 굵게 변경합니다. (0) | 2023.05.23 |
| Bash 스크립트에 전달된 인수 수를 확인하려면 어떻게 해야 합니까? (0) | 2023.05.23 |
| #if RELEASE가 C#에서 DEBUG가 #처럼 작동합니까? (0) | 2023.05.23 |
| ReportGenerator에서 코드 적용 범위 결과 게시가 작동하지 않음 (0) | 2023.05.23 |