如何自动化Azure归档存储冷热层转换、通知及72小时后重归档?
基于Azure原生服务的归档存储自动化流转方案
针对你提出的Azure Archive Storage自动化需求,以下是一套低成本、无人工干预的实现方案,完全基于Azure原生服务构建:
整体流程概述
- 用户提交文件请求 → 触发Blob解冻(从Archive转至Cool/Hot层)
- Event Grid监听Blob层级变更事件,确认解冻完成后触发通知流程
- 生成72小时有效期的SAS URL并发送邮件通知用户
- 通过延时队列触发72小时后的Blob归位操作(转回Archive层)
核心组件与实现细节
1. 解冻触发与状态检测
- 触发解冻:使用HTTP触发的Azure Function作为用户请求入口,接收文件路径、用户邮箱和目标层级(Cool/Hot),调用Azure Storage SDK的
SetBlobTierAsync方法发起解冻操作。同时将请求记录写入Azure Table Storage(存储Blob路径、用户邮箱等信息)。 - 状态检测:配置Azure Event Grid订阅存储账户的
BlobTierChanged事件,设置筛选规则:仅当Blob层级变为目标Cool/Hot层且状态为Available时,触发后续Function。Event Grid的免费层级足以覆盖这类事件的触发需求。
2. 发送含SAS URL的通知邮件
- 当Event Grid触发状态检测Function后,从Table Storage中获取对应请求的用户邮箱。
- 使用
BlobSasBuilder生成只读权限、72小时有效期的SAS URL,确保用户只能下载且链接到期后自动失效。 - 通过Azure Functions的SendGrid绑定(或Azure Communication Services)发送通知邮件,内容包含SAS URL和时效提示。
3. 72小时后自动移回归档层
- 在发送邮件的Function中,将Blob路径写入Azure Queue Storage,并设置消息的可见性超时时间为72小时(消息72小时后才会被消费)。
- 配置Queue触发的Azure Function,当消息变为可见时,调用
SetBlobTierAsync将Blob切换回Archive层。
代码示例(C#)
解冻触发Function
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; public static class TriggerUnfreezeFunction { [FunctionName("TriggerUnfreeze")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { var blobPath = req.Query["blobPath"]; var userEmail = req.Query["userEmail"]; var targetTier = req.Query["targetTier"] ?? "Cool"; if (string.IsNullOrEmpty(blobPath) || string.IsNullOrEmpty(userEmail)) return new BadRequestObjectResult("请提供blobPath和userEmail参数"); var connStr = Environment.GetEnvironmentVariable("StorageConnectionString"); var blobServiceClient = new BlobServiceClient(connStr); var blobClient = blobServiceClient.GetBlobClient(blobPath); // 发起解冻操作 await blobClient.SetBlobTierAsync(targetTier.Equals("Hot", StringComparison.OrdinalIgnoreCase) ? AccessTier.Hot : AccessTier.Cool); // 记录请求到Table Storage var tableClient = blobServiceClient.GetTableClient("UnfreezeRequests"); await tableClient.CreateIfNotExistsAsync(); await tableClient.AddEntityAsync(new UnfreezeRequest(blobPath, userEmail)); return new OkObjectResult("解冻请求已提交,预计5-12小时完成,完成后将发送下载链接至您的邮箱"); } } public class UnfreezeRequest : Azure.Data.Tables.TableEntity { public UnfreezeRequest(string blobPath, string userEmail) { PartitionKey = "Requests"; RowKey = blobPath; UserEmail = userEmail; } public string UserEmail { get; set; } }
通知与延时队列Function
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Sas; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.EventGrid; using Microsoft.Azure.WebJobs.Extensions.SendGrid; using Microsoft.Extensions.Logging; using SendGrid.Helpers.Mail; using System; using System.Threading.Tasks; public static class NotifyAndScheduleArchiveFunction { [FunctionName("NotifyAndScheduleArchive")] public static async Task Run( [EventGridTrigger] Microsoft.Azure.EventGrid.Models.EventGridEvent eventItem, [Table("UnfreezeRequests", "Requests", "{data.url}")] UnfreezeRequest request, [SendGrid(ApiKey = "SendGridApiKey")] IAsyncCollector<SendGridMessage> messageCollector, ILogger log) { var blobUrl = eventItem.Data["url"].ToString(); var blobClient = new BlobClient(new Uri(blobUrl)); // 生成72小时有效期的只读SAS URL var sasBuilder = new BlobSasBuilder { BlobContainerName = blobClient.BlobContainerName, BlobName = blobClient.Name, ExpiresOn = DateTime.UtcNow.AddHours(72), Permissions = BlobSasPermissions.Read }; var sasToken = sasBuilder.ToSasQueryParameters(blobClient.GetSharedAccessSignatureCredential()).ToString(); var sasUrl = $"{blobUrl}?{sasToken}"; // 发送通知邮件 var msg = new SendGridMessage(); msg.AddTo(request.UserEmail); msg.SetFrom("no-reply@yourdomain.com", "Archive Storage Service"); msg.SetSubject("您请求的文件已可下载"); msg.AddContent(MimeType.Text, $"文件解冻完成,下载链接:{sasUrl}\n链接72小时后失效,文件将自动转回归档层"); await messageCollector.AddAsync(msg); // 写入延时队列,72小时后处理归位 var queueClient = new QueueClient(Environment.GetEnvironmentVariable("StorageConnectionString"), "archive-queue"); await queueClient.CreateIfNotExistsAsync(); await queueClient.SendMessageAsync(blobUrl, visibilityTimeout: TimeSpan.FromHours(72)); } }
归位到Archive层Function
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Logging; using System.Threading.Tasks; public static class MoveToArchiveFunction { [FunctionName("MoveToArchive")] public static async Task Run( [QueueTrigger("archive-queue")] string blobUrl, ILogger log) { var blobClient = new BlobClient(new Uri(blobUrl)); await blobClient.SetBlobTierAsync(AccessTier.Archive); log.LogInformation($"Blob {blobUrl} 已成功转回归档层"); } }
成本优化要点
- 使用消耗计划的Azure Functions:仅在触发时计费,闲置时无成本,适合这类低频次触发的场景。
- 利用Azure服务的免费层级:Event Grid每月10万条免费事件,Queue/Table Storage的存储和操作成本极低。
- 无需额外中间件:所有流程基于Azure原生服务,避免第三方服务的额外开销。
注意事项
- 确保存储账户已启用Event Grid事件(在存储账户的「事件」选项卡中配置)。
- SAS URL权限严格设置为只读,避免数据被意外修改。
- 可添加错误处理逻辑:如解冻失败时通知用户、队列处理失败时自动重试。
- 若用户重复请求同一文件,可在Table Storage中记录当前解冻状态,避免重复操作。
内容的提问来源于stack exchange,提问作者Shlok Jadeja
相关产品推荐
相关产品推荐

