news 2026/9/18 19:58:26

从 `azure-storage-blob-go` 迁移到新版 `azblob` SDK:以 Grafana Tempo 的 Azure 后端为实战案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 `azure-storage-blob-go` 迁移到新版 `azblob` SDK:以 Grafana Tempo 的 Azure 后端为实战案例

azure-storage-blob-go迁移到新版azblobSDK:以 Grafana Tempo 的 Azure 后端为实战案例

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

Grafana Tempo 是一款高吞吐、低依赖的分布式链路追踪后端,可将链路数据持久化到 Azure Blob Storage。本文以仓库内随附的 Azure SDK for Go 迁移指南(vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/migrationguide.md)为主体,系统讲解如何从旧版azure-storage-blob-go模块(以及azblob早期测试版)迁移到新版azblob模块,并穿插 Tempo 在tempodb/backend/azure下的真实用法作为佐证。读完本文,你将掌握新版 SDK 的客户端构造、认证方式、分页列举与 HTTP Pipeline 配置的完整迁移路径,并能在自己的 Go 项目中直接套用。

为什么需要迁移:简化后的 API 表面

旧版azure-storage-blob-go的公开 API 是"扁平"的——所有客户端和支持类型都集中在azblob一个包内,导致包面难以导航,用户在数千个导出符号中寻找自己需要的 API 十分费力。

新版azblob模块(github.com/Azure/azure-sdk-for-go/sdk/storage/azblob)对设计做了重构,将客户端按职责拆分到多个子包中。从当前仓库的 vendor 目录(vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/)可以看到这套拆分后的包结构:

  • blob:所有 Blob 类型共有的 API(删除/恢复删除、设置元数据等);
  • container:容器特有 API(设置访问策略、属性等);
  • service:Blob 服务级 API(操作容器、获取账户信息等);
  • appendblob/blockblob/pageblob:针对三种特定 Blob 类型的专用客户端;
  • sas:共享访问签名(SAS)令牌的创建与操作工具;
  • bloberror:存储错误码与错误处理辅助工具。

Tempo 的 Azure 后端正是按这套子包来组织代码的。在 tempodb/backend/azure/azure.go 的 import 块中,可以看到它同时引用了azblobazblob/blobazblob/bloberrorazblob/blockblobazblob/container等多个子包——这正是新版 API 拆分后的典型用法。

客户端构造:从url.URL + Pipelinestring URL + Credential

旧版方式

azure-storage-blob-go中,客户端构造函数总是要求传入一个url.URL和一个Pipeline

// 旧代码(azure-storage-blob-go) u, _ := url.Parse("https://myaccount.blob.core.windows.net/") pipeline := azblob.NewPipeline(cred, azblob.PipelineOptions{}) client := azblob.NewServiceURL(*u, pipeline) // 以 url.URL 和 Pipeline 构造

新版方式

在新版azblob中,客户端构造函数改为接收string类型的 URL、指定的凭证类型以及可选的*ClientOptions(传nil表示接受默认选项):

// 新代码 client, err := azblob.NewClient("<my storage account URL>", cred, nil)

以 Tempo 的实际代码为例,在 tempodb/backend/azure/azure_helpers.go 中,客户端正是通过azblob.NewClient(u.String(), credential, &opts)azblob.NewClientWithSharedKeyCredential(u.String(), credential, &opts)构造的,其中uurl.Parse生成后再取其字符串形式传入,凭证对象则直接作为第二个参数。

从 vendor 目录中azblob/client.go的源码(vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/client.go#L33-L85)可以看到,新版模块实际上提供了四个构造函数,覆盖全部认证场景:

构造函数适用场景
NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOptions)Azure AD 令牌凭证(通常来自 azidentity 模块)
NewClientWithNoCredential(serviceURL string, options *ClientOptions)匿名访问或带 SAS 令牌的 URL
NewClientWithSharedKeyCredential(serviceURL string, cred *SharedKeyCredential, options *ClientOptions)共享密钥认证
NewClientFromConnectionString(connectionString string, options *ClientOptions)连接字符串

认证方式的迁移

Azure AD / OAuth 令牌认证

旧版azure-storage-blob-go通过NewTokenCredential提供有限的 OAuth 令牌认证支持。

新版azblob不再自带令牌凭证实现,而是统一改用 azidentity 模块提供的 Azure Identity 凭证。这也是 Azure SDK for Go 所有服务模块的通用做法。典型用法:

// 新代码。cred 是由 azidentity 模块创建的 AAD 令牌凭证 cred, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { // 处理错误 } client, err := azblob.NewClient("<my storage account URL>", cred, nil)

Tempo 对 azidentity 的运用可以印证这一点。在 tempodb/backend/azure/azure_helpers.go 中:

  • 当配置use_federated_token时,使用azidentity.NewWorkloadIdentityCredential(...)创建 Azure Workload Identity(联邦令牌)凭证;
  • 当配置use_managed_identity时,使用azidentity.NewManagedIdentityCredential(...)创建托管身份凭证,并可通过azidentity.ClientID(cfg.UserAssignedID)指定用户分配身份的 Client ID(未指定时默认使用系统分配身份)。

共享密钥认证

通过NewSharedKeyCredential进行共享密钥认证的方式在新版中保持不变:

cred, err := azblob.NewSharedKeyCredential(accountName, accountKey) client, err := azblob.NewClientWithSharedKeyCredential(u.String(), cred, &opts)

Tempo 的默认路径正是如此。在 tempodb/backend/azure/azure_helpers.go 中,注释明确写道:"如果未显式指定任何认证机制,则默认假定使用共享密钥凭证"("If no authentication mechanism has been explicitly specified, assume shared key credential"),随后用azblob.NewSharedKeyCredential加上azblob.NewClientWithSharedKeyCredential完成构造。账户名与密钥还可以分别从环境变量AZURE_STORAGE_ACCOUNTAZURE_STORAGE_KEY读取(见 azure_helpers.go 的getStorageAccountNamegetStorageAccountKey)。

匿名 / SAS 认证

旧版通过NewAnonymousCredential构造 Pipeline 来支持匿名或 SAS 认证。

新版改用专用构造函数NewClientWithNoCredential()

// 新代码 client, err := azblob.NewClientWithNoCredential("<public blob or blob with SAS URL>", nil)

client.go的注释可以看出,该构造函数专门用于匿名访问存储账户,或在服务 URL 中直接携带 SAS 令牌进行访问(vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/client.go#L44-L57)。

列举 Blob / 容器:从显式Marker*runtime.Pager[T]

旧版azure-storage-blob-go要求开发者显式创建Marker类型来对分页结果进行翻页,每次手动将返回的Marker回传以获取下一页。

新版azblob中,所有返回分页值的操作统一返回*runtime.Pager[T]。Pager 是azcore运行时提供的泛型分页器,自带More()NextPage()两个方法,遍历逻辑因此变得简洁一致:

// 新代码 pager := client.NewListBlobsFlatPager("my-container", nil) for pager.More() { page, err := pager.NextPage(context.TODO()) if err != nil { // 处理错误 } // 处理本页结果 for _, blob := range page.Segment.BlobItems { fmt.Println(*blob.Name) } }

Tempo 的 Azure 后端大量使用了 Pager 模式,可以作为最佳实践参考:

  • tempodb/backend/azure/azure.go 的List方法使用container.NewListBlobsHierarchyPager(dir, ...)(层级列举)遍历租户/目录下的 blob 前缀(BlobPrefixes),用于发现后端对象;
  • tempodb/backend/azure/azure.go 的ListBlocks方法使用NewListBlobsFlatPager(扁平列举)配合Prefix过滤,遍历某租户下的meta.json/meta.compacted.json文件来收集 block ID 列表;
  • tempodb/backend/azure/azure.go 的Find方法同样用NewListBlobsFlatPager迭代全部 blob,并通过b.Properties.LastModified向回调传递对象修改时间。

三处都遵循同一范式:for pager.More() { page, err := pager.NextPage(ctx) ... },可见 Pager 已成为新版 SDK 分页操作的统一抽象。

配置 HTTP Pipeline:从显式 Pipeline 到azcore.ClientOptions

旧版需要先显式构建带配置的 HTTP Pipeline,再把它作为参数传给客户端构造函数。

新版azblob中,HTTP Pipeline 在客户端构造期间自动创建,其配置通过azcore.ClientOptions类型注入:

// 新代码 client, err := azblob.NewClient(account, cred, &azblob.ClientOptions{ ClientOptions: azcore.ClientOptions{ // 在这里配置 HTTP Pipeline 选项 Transport: ..., Retry: ..., Telemetry: ..., }, })

Tempo 在这一环节做了相当细致的配置,是理解azcore.ClientOptions各字段的绝佳样例(见 tempodb/backend/azure/azure_helpers.go):

  • Retry:设置policy.RetryOptions{MaxRetries: 1, TryTimeout: 1 * time.Minute, RetryDelay: 4 * time.Second, MaxRetryDelay: 120 * time.Second},这些重试参数从旧 SDKazure-storage-blob-go继承而来(源码注释给出了旧实现出处);如果上下文携带 deadline,还会把TryTimeout调整为距离截止时间的剩余时长;
  • Transport:克隆http.DefaultTransport并把MaxIdleConnsPerHost提升到 100,减少连接周转;外层再包一层instrumentation.NewTransport用于指标采集;
  • 可选地,Tempo 还会用hedgedhttp包一层带统计的 RoundTripper 实现对冲请求(hedged requests),以降低长尾延迟——对应配置项HedgeRequestsAt/HedgeRequestsUpTo
  • Telemetry:设置ApplicationID: "Tempo",让 Azure 侧能够识别请求来源。

在 Tempo 中配置新版 azblob 后端

迁移指南之外,Tempo 对 Azure 后端的完整配置也值得一并掌握(详见 docs/sources/tempo/configuration/hosted-storage/azure.md 与 tempodb/backend/azure/config.go)。

Tempo 支持三种认证方式:共享密钥(storage_account_key)、托管身份(use_managed_identity/user_assigned_id)与 Azure Workload Identity 联邦令牌(use_federated_token)。单机(monolithic)模式下最小配置如下:

storage: trace: backend: azure azure: container_name: container-name storage_account_name: storage-account-name storage_account_key: ${STORAGE_ACCOUNT_ACCESS_KEY}

使用联邦令牌(Workload Identity)时:

storage: trace: backend: azure azure: container_name: container-name storage_account_name: storage-account-name use_federated_token: true

配置项与默认值(config.go中的RegisterFlagsAndApplyDefaults):

配置项默认值说明
storage_account_name空(可回退到环境变量AZURE_STORAGE_ACCOUNT存储账户名
storage_account_key空(可回退到环境变量AZURE_STORAGE_KEY共享密钥
use_managed_identityfalse使用 Azure 托管身份认证
use_federated_tokenfalse使用 Azure Workload Identity 联邦令牌
user_assigned_id用户分配身份的 Client ID
container_name存储 block 的容器名
prefix容器内存储对象的可选前缀
endpoint_suffixblob.core.windows.net目标端点,用于公有云以外的区域/主权云
max_buffers4同时上传的缓冲区数量
buffer_size3 * 1024 * 1024(3 MiB,代码内置默认)上传块大小
hedge_requests_at0(0 表示禁用)对冲请求触发延迟
hedge_requests_up_to2对冲请求最大并发数

需要特别说明的是 Azurite 本地模拟:Tempo 会将任何不以blob.开头的endpoint_suffix判定为 Azurite,并自动切换到模拟器 URL 风格(http://<endpoint>/<accountName>),见 azure_helpers.go 的注释与实现。这意味着一份配置即可在本地开发与云端生产之间切换。

迁移检查清单

  1. 替换模块依赖:将go.mod中的github.com/Azure/azure-storage-blob-go/azblob替换为github.com/Azure/azure-sdk-for-go/sdk/storage/azblob;如需 Azure AD 认证,再添加github.com/Azure/azure-sdk-for-go/sdk/azidentity
  2. 重写客户端构造:把"手动构造 Pipeline +url.URL传入构造函数"改为"直接传stringURL + 凭证 +*ClientOptions(可传nil)"。
  3. 替换凭证创建:用 azidentity 的NewDefaultAzureCredential/NewManagedIdentityCredential/NewWorkloadIdentityCredential替代旧版NewTokenCredential;共享密钥的NewSharedKeyCredential保持不变;匿名/SAS 场景改用NewClientWithNoCredential
  4. 改写分页逻辑:删除显式Marker管理,改用*runtime.Pager[T]More()/NextPage()循环。
  5. 迁移 Pipeline 配置:把旧 Pipeline 中的重试、传输、日志等配置平移到azcore.ClientOptionsRetryTransportTelemetryLogging等字段)。

完成以上步骤后,你的代码即可与 Tempo 一样,在统一、可导航、goroutine 安全的新版azblobAPI 之上构建存储层——Tempo 的全部相关实现位于 tempodb/backend/azure/,可作为迁移后的参考实现。

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 19:57:25

HIXL 传输路径总览:三引擎识别、日志定位与性能统计解读

HIXL 传输路径总览&#xff1a;三引擎识别、日志定位与性能统计解读 【免费下载链接】hixl HIXL&#xff08;Huawei Xfer Library&#xff09;是一个灵活、高效的昇腾单边通信库&#xff0c;面向集群场景提供简单、可靠、高效的点对点数据传输能力。 项目地址: https://gitco…

作者头像 李华
网站建设 2026/9/18 19:55:29

MySQL 1093错误详解:解决UPDATE子查询同表限制的5种方案

折腾 MySQL 的人&#xff0c;谁没跟“错误代码 1093”打过照面呢。刚入行那会儿&#xff0c;我在一个订单表上跑 UPDATE&#xff0c;子查询里顺手就写了从同一张表取数&#xff0c;结果 Workbench 直接甩给我一句&#xff1a;You can‘t specify target table ‘tb‘ for updat…

作者头像 李华
网站建设 2026/9/18 19:53:52

oh-my-hermes:React Native 的 Hermes 引擎配置与性能调优实战

做移动端开发这几年&#xff0c;有一个感受越来越深&#xff1a;React Native 项目跑到后期&#xff0c;性能问题基本都出在 JavaScript 引擎这一层。启动变慢、内存上涨、列表滚动掉帧&#xff0c;排查半天往往发现不是业务代码的问题&#xff0c;而是引擎配置根本没被认真对待…

作者头像 李华
网站建设 2026/9/18 19:51:15

阿里云Ubuntu部署饥荒联机版专用服务器完整教程

1. 为什么选择阿里云Ubuntu部署饥荒联机版服务器1.1 自建服务器的核心动机玩过饥荒联机版的朋友都知道&#xff0c;这游戏最舒服的体验就是几个人长期在一个固定世界里慢慢发展&#xff0c;建家、打Boss、过四季。但问题来了——官方服务器延迟高、Mod管理不灵活、世界存档不在…

作者头像 李华