You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自动化Azure归档存储冷热层转换、通知及72小时后重归档?

基于Azure原生服务的归档存储自动化流转方案

针对你提出的Azure Archive Storage自动化需求,以下是一套低成本、无人工干预的实现方案,完全基于Azure原生服务构建:

整体流程概述

  1. 用户提交文件请求 → 触发Blob解冻(从Archive转至Cool/Hot层)
  2. Event Grid监听Blob层级变更事件,确认解冻完成后触发通知流程
  3. 生成72小时有效期的SAS URL并发送邮件通知用户
  4. 通过延时队列触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 12:54:54