Thanos源码专题【左扬精讲】——Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\blocks\v1.go)
Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\blocks\v1.go)
https://github.com/thanos-io/thanos/blob/v0.26.0/pkg/api/blocks/v1.go
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
package v1
import (
"net/http"
"time"
"github.com/go-kit/log" // 日志库
"github.com/oklog/ulid" // ulid库
"github.com/opentracing/opentracing-go" // opentracing库,用于分布式追踪
"github.com/pkg/errors" // 错误处理库
"github.com/prometheus/client_golang/prometheus" // prometheus库,用于监控和度量指标收集
"github.com/prometheus/client_golang/prometheus/promauto" // promauto库,用于自动注册度量指标
"github.com/prometheus/common/route" // route库,用于路由管理
"github.com/thanos-io/thanos/pkg/api" // api库,用于处理API请求和响应
"github.com/thanos-io/thanos/pkg/block" // block库,用于处理块数据
"github.com/thanos-io/thanos/pkg/block/metadata" // metadata库,用于处理块元数据
extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" // extpromhttp库,用于扩展Prometheus HTTP客户端功能
"github.com/thanos-io/thanos/pkg/logging" // logging库,用于处理日志记录
"github.com/thanos-io/thanos/pkg/objstore" // objstore库,用于处理对象存储
)
// BlocksAPI is a very simple API used by Thanos Block Viewer.
// BlocksAPI 是一个用于Thanos Block Viewer的非常简单的API。
type BlocksAPI struct {
baseAPI *api.BaseAPI // 嵌入了api.BaseAPI,用于处理一些基础API操作
logger log.Logger // 日志记录器,用于记录日志信息
globalBlocksInfo *BlocksInfo // 全局块信息
loadedBlocksInfo *BlocksInfo // 加载的块信息
disableCORS bool // 是否禁用CORS
bkt objstore.Bucket // 对象存储桶,用于存储和检索块数据
}
// BlocksInfo 是块信息结构体,包含了标签、块元数据和刷新时间等信息。
type BlocksInfo struct {
Label string `json:"label"` // 标签,用于标识块信息
Blocks []metadata.Meta `json:"blocks"` // 块元数据,包含了块的详细信息
RefreshedAt time.Time `json:"refreshedAt"` // 刷新时间,表示块信息最后一次刷新的时间
Err error `json:"err"` // 错误信息,如果获取块信息时发生错误,则包含具体的错误
}
// ActionType int32 枚举类型,表示不同的操作类型。
type ActionType int32
const (
Deletion ActionType = iota // 删除操作
NoCompaction // 不压缩操作
Unknown // 未知操作
)
// parse 函数根据传入的字符串 s 返回对应的 ActionType 类型
//
// 参数:
//
// s string: 待解析的字符串
//
// 返回值:
//
// ActionType: 返回对应的 ActionType 类型
func parse(s string) ActionType {
// 根据传入的字符串s进行分支判断
switch s {
case "DELETION":
// 当s为"DELETION"时,返回Deletion类型
return Deletion
case "NO_COMPACTION":
// 当s为"NO_COMPACTION"时,返回NoCompaction类型
return NoCompaction
default:
// 当s既不是"DELETION"也不是"NO_COMPACTION"时,返回Unknown类型
return Unknown
}
}
// NewBlocksAPI creates a simple API to be used by Thanos Block Viewer.
// NewBlocksAPI 创建一个新的 BlocksAPI 实例
//
// 参数:
// logger: 用于记录日志的 log.Logger 实例
// disableCORS: 是否禁用 CORS
// label: BlocksAPI 实例的标签
// flagsMap: 传递给 API 的标志映射
// bkt: 用于存储对象的 objstore.Bucket 实例
//
// 返回值:
// *BlocksAPI: 返回一个新的 BlocksAPI 实例
func NewBlocksAPI(logger log.Logger, disableCORS bool, label string, flagsMap map[string]string, bkt objstore.Bucket) *BlocksAPI {
// 创建一个新的BlocksAPI实例
return &BlocksAPI{
// 创建baseAPI实例,传入logger, disableCORS, flagsMap参数
baseAPI: api.NewBaseAPI(logger, disableCORS, flagsMap),
// 传入logger参数
logger: logger,
// 创建globalBlocksInfo实例,并设置Blocks为空数组和Label为传入的label参数
globalBlocksInfo: &BlocksInfo{
Blocks: []metadata.Meta{},
Label: label,
},
// 创建loadedBlocksInfo实例,并设置Blocks为空数组和Label为传入的label参数
loadedBlocksInfo: &BlocksInfo{
Blocks: []metadata.Meta{},
Label: label,
},
// 传入disableCORS参数
disableCORS: disableCORS,
// 传入bkt参数
bkt: bkt,
}
}
// Register 注册BlocksAPI路由到路由器
//
// 参数:
//
// r *route.Router: 路由器对象
// tracer opentracing.Tracer: OpenTracing追踪器对象
// logger log.Logger: 日志记录器对象
// ins extpromhttp.InstrumentationMiddleware: 监控中间件对象
// logMiddleware *logging.HTTPServerMiddleware: HTTP服务器中间件对象
func (bapi *BlocksAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
// 调用基类API的注册方法
bapi.baseAPI.Register(r, tracer, logger, ins, logMiddleware)
// 获取API的Instrumentation实例
instr := api.GetInstr(tracer, logger, ins, logMiddleware, bapi.disableCORS)
// 注册GET请求处理函数
// 路径为"/blocks",处理函数为bapi.blocks
r.Get("/blocks", instr("blocks", bapi.blocks))
// 注册POST请求处理函数
// 路径为"/blocks/mark",处理函数为bapi.markBlock
r.Post("/blocks/mark", instr("blocks_mark", bapi.markBlock))
}
// markBlock 函数用于标记一个块(Block)执行特定的操作。
//
// 参数:
// r: *http.Request 类型,包含请求信息的HTTP请求对象。
//
// 返回值:
// interface{}: 无返回值,故为nil。
// []error: 错误列表,这里不返回错误,故为nil。
// *api.ApiError: API错误对象,当发生错误时返回。
func (bapi *BlocksAPI) markBlock(r *http.Request) (interface{}, []error, *api.ApiError) {
// 获取请求参数
idParam := r.FormValue("id") // 获取请求参数中的"id",表示要操作的块的ID
actionParam := r.FormValue("action") // 获取请求参数中的"action",表示要执行的操作类型
detailParam := r.FormValue("detail") // 获取请求参数中的"detail",表示操作的详细信息,例如原因或备注
// 检查ID是否为空
if idParam == "" {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("ID cannot be empty")}
}
// 检查Action是否为空
if actionParam == "" {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("Action cannot be empty")}
}
// 解析ULID
id, err := ulid.Parse(idParam)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("ULID %q is not valid: %v", idParam, err)}
}
// 解析Action类型
actionType := parse(actionParam)
switch actionType {
case Deletion:
// 执行删除操作
err := block.MarkForDeletion(r.Context(), bapi.logger, bapi.bkt, id, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
case NoCompaction:
// 执行不压缩操作
err := block.MarkForNoCompact(r.Context(), bapi.logger, bapi.bkt, id, metadata.ManualNoCompactReason, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
default:
// 返回不支持的操作错误
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("not supported marker %v", actionParam)}
}
return nil, nil, nil
}
// blocks 函数用于处理BlocksAPI的blocks请求。
//
// 参数:
//
// r *http.Request: HTTP请求对象
//
// 返回值:
//
// interface{}: 返回的响应数据
// []error: 返回的错误列表
// *api.ApiError: API错误对象
func (bapi *BlocksAPI) blocks(r *http.Request) (interface{}, []error, *api.ApiError) {
// 获取URL查询参数中的"view"参数
viewParam := r.URL.Query().Get("view")
// 如果"view"参数值为"loaded"
if viewParam == "loaded" {
// 返回已加载的区块信息
return bapi.loadedBlocksInfo, nil, nil
}
// 返回全局区块信息
return bapi.globalBlocksInfo, nil, nil
}
// set 方法用于更新 BlocksInfo 结构体中的数据
//
// 参数:
// - blocks:[]metadata.Meta 类型的切片,包含要更新的区块数据
// - err:error 类型,包含错误信息,如果更新成功则为 nil
func (b *BlocksInfo) set(blocks []metadata.Meta, err error) {
// 判断是否存在错误
if err != nil {
// 如果存在错误,则保持上次视图不变
// Last view is maintained.
b.RefreshedAt = time.Now()
b.Err = err
return
}
// 更新视图时间
b.RefreshedAt = time.Now()
// 更新区块数据
b.Blocks = blocks
// 设置错误信息
b.Err = err
}
// SetGlobal updates the global blocks' metadata in the API.
// SetGlobal 设置全局块信息
//
// 参数:
//
// blocks - []metadata.Meta:块信息的切片
// err - error:错误信息
//
// 说明:
//
// 将blocks和err参数传递给bapi.globalBlocksInfo的set方法,用于设置全局块信息
func (bapi *BlocksAPI) SetGlobal(blocks []metadata.Meta, err error) {
// 设置全局块信息
// 将blocks和err参数传递给bapi.globalBlocksInfo的set方法
bapi.globalBlocksInfo.set(blocks, err)
}
// SetLoaded 设置 BlocksAPI 实例的已加载区块信息
//
// 参数:
// - blocks []metadata.Meta:已加载的区块元数据列表
// - err error:加载区块过程中出现的错误
func (bapi *BlocksAPI) SetLoaded(blocks []metadata.Meta, err error) {
// 调用 loadedBlocksInfo 的 set 方法,将 blocks 和 err 传入
bapi.loadedBlocksInfo.set(blocks, err)
}

浙公网安备 33010602011771号