Posted in

Go可观测性基建搭建(OpenTelemetry + Prometheus + Loki):零侵入埋点方案

第一章:Go可观测性基建搭建(OpenTelemetry + Prometheus + Loki):零侵入埋点方案

现代 Go 服务需在不修改业务逻辑的前提下,实现指标、日志与链路的统一采集。本方案基于 OpenTelemetry SDK 的自动插件机制,结合 Prometheus 和 Loki 构建轻量级、可扩展的可观测性基座。

OpenTelemetry 自动化注入配置

使用 otelhttp 和 otelsql 等官方 Instrumentation 包,通过 HTTP 中间件和数据库驱动包装实现零代码侵入。在 main.go 中仅需初始化全局 TracerProvider 和 MeterProvider:

import (
    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
    "go.opentelemetry.io/contrib/instrumentation/database/sql/otelsql"
    _ "github.com/lib/pq" // PostgreSQL 驱动需提前导入
)

func initTracing() {
    // 使用 OTLP 协议上报至 Collector(如 Jaeger 或 Tempo)
    exp, _ := otlptrace.New(context.Background(), otlptracegrpc.NewClient(
        otlptracegrpc.WithEndpoint("localhost:4317"),
    ))
    tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample), sdktrace.WithSpanProcessor(sdktrace.NewBatchSpanProcessor(exp)))
    otel.SetTracerProvider(tp)
    otel.SetPropagators(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
}

Prometheus 指标采集配置

启用 OpenTelemetry 的 prometheus exporter,并通过 /metrics 端点暴露标准 Prometheus 格式指标:

// 启动 Prometheus HTTP handler
promHandler := prometheus.NewHandler()
http.Handle("/metrics", promHandler)

Prometheus scrape_configs 示例:

- job_name: 'go-service'
  static_configs:
  - targets: ['localhost:8080']

Loki 日志集成策略

利用 OpenTelemetry Collector 的 lokiexporter 将结构化日志(通过 logrus 或 zerolog + otellog 桥接)发送至 Loki。关键配置片段:

组件 作用
filelog receiver 读取 stdout/stderr 或文件日志
lokiexporter 将日志按 trace_id、service.name 打标后推送
prometheusremotewrite 可选:将指标同步至 Prometheus 远程写入

Loki 查询示例(Grafana 中):
{job="go-service"} | logfmt | traceID="0xabcdef123456"

所有组件可通过 Docker Compose 快速启动,无需修改业务函数签名或添加 span.Start() 调用——真正实现“零侵入”。

第二章:可观测性核心概念与Go生态适配原理

2.1 分布式追踪、指标、日志三位一体的理论模型

在云原生系统中,可观测性不再依赖单一数据源,而是由追踪(Tracing)、指标(Metrics)与日志(Logging)构成互补闭环:追踪定位请求路径与延迟瓶颈,指标反映系统状态趋势,日志提供上下文细节与异常现场。

三者协同关系

  • 追踪提供请求唯一标识(如 trace_id),作为跨服务关联的锚点
  • 指标聚合高频数值(如 P99 延迟、错误率),驱动告警与容量规划
  • 日志嵌入 trace_id 和 span_id,实现从统计异常到具体事件的下钻

典型关联示例

# OpenTelemetry Python SDK 中的日志注入示例
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.trace import get_current_span

provider = TracerProvider()
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("process_order") as span:
    span.set_attribute("order.id", "ORD-789")
    # 自动注入 trace_id/span_id 到结构化日志
    logger.info("Order processed", extra={
        "trace_id": format_trace_id(span.get_span_context().trace_id),
        "span_id": format_span_id(span.get_span_context().span_id)
    })

该代码通过 extra 字段将 OpenTelemetry 上下文注入日志,确保日志可被 trace_id 关联。format_trace_id() 将 128-bit 整数转为 32 位十六进制字符串,符合 W3C Trace Context 规范。

维度 数据形态 采样策略 典型工具
分布式追踪 有向有环图 动态采样 Jaeger, Zipkin
指标 时间序列 全量/降采样 Prometheus, Grafana
日志 结构化文本 按严重级过滤 Loki, ELK
graph TD
    A[HTTP 请求] --> B[生成 trace_id]
    B --> C[Span 创建与传播]
    C --> D[指标采集器聚合]
    C --> E[结构化日志输出]
    D & E --> F[统一可观测平台]
    F --> G[基于 trace_id 关联分析]

2.2 OpenTelemetry SDK在Go中的无侵入注入机制剖析

OpenTelemetry Go SDK 的无侵入注入核心在于 otelhttp 和 oteltrace 的中间件式封装,而非修改业务逻辑。

自动注入原理

  • 利用 Go 的 http.RoundTripper 和 http.Handler 接口抽象
  • 通过装饰器模式包裹原始客户端/服务端实例
  • 追踪上下文通过 context.Context 隐式透传,零代码修改

HTTP 客户端自动注入示例

import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"

client := &http.Client{
    Transport: otelhttp.NewTransport(http.DefaultTransport),
}
// 发起请求时自动创建 span 并注入 traceparent header
resp, _ := client.Get("https://api.example.com")

otelhttp.NewTransport 包装底层 Transport,在 RoundTrip 调用前后自动开启/结束 span;traceparent 由 otelhttp.HeaderSetter 注入,无需手动 SpanContext.Extract()。

关键注入点对比

注入位置 触发时机 上下文传递方式
HTTP Client RoundTrip 开始前 context.WithValue()
HTTP Server ServeHTTP 入口 Request.Context()
Database Driver Query/Exec 调用 context.Context 参数
graph TD
    A[HTTP Request] --> B[otelhttp.Transport.RoundTrip]
    B --> C[Start span with context]
    C --> D[Inject traceparent header]
    D --> E[Delegate to original Transport]
    E --> F[End span on response]

2.3 Prometheus指标采集协议与Go原生metrics暴露实践

Prometheus通过HTTP端点以文本格式(text/plain; version=0.0.4)拉取指标,遵循简单、可扩展的暴露协议。

指标暴露原理

客户端需提供/metrics端点,返回符合Exposition Format的纯文本,如:

  • # TYPE http_requests_total counter
  • http_requests_total{method="GET",code="200"} 123

Go原生metrics实践

使用prometheus/client_golang库暴露指标:

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    httpRequests = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests.",
        },
        []string{"method", "code"},
    )
)

func init() {
    prometheus.MustRegister(httpRequests)
}

func handler(w http.ResponseWriter, r *http.Request) {
    httpRequests.WithLabelValues(r.Method, "200").Inc()
    w.WriteHeader(200)
}

逻辑分析:NewCounterVec创建带标签的计数器;MustRegister将其注册到默认注册表;WithLabelValues动态绑定标签值;Inc()原子递增。所有指标自动通过promhttp.Handler()在/metrics暴露。

常见指标类型对比

类型 适用场景 是否支持标签 示例方法
Counter 累计事件(请求总数) ✅ Inc(), Add()
Gauge 可增可减状态(内存使用) ✅ Set(), Inc()
Histogram 观察值分布(响应延迟) ✅ Observe()

数据流概览

graph TD
    A[Go应用] --> B[metrics注册表]
    B --> C[HTTP /metrics handler]
    C --> D[Prometheus Server]
    D --> E[定时Pull请求]

2.4 Loki日志管道设计与Go结构化日志零改造接入

Loki 不索引日志内容,仅索引标签(labels),因此高效管道设计依赖于标签建模与日志格式对齐。

标签驱动的日志路由策略

  • job、host、level 等标签决定日志流分片与保留策略
  • Go 应用无需修改日志调用,只需注入 log.With().Str("job", "api-server")

零改造接入原理

通过 log.Logger 包装器劫持 Write() 方法,自动提取结构化字段为 Loki labels:

func (w *lokiWriter) Write(p []byte) (n int, err error) {
    var fields map[string]interface{}
    json.Unmarshal(p, &fields) // 解析 zap/zapcore 或 logrus 结构化 JSON
    labels := lokiLabelsFromFields(fields) // 提取 level/service/trace_id 等
    return w.pusher.Push(labels, p) // 直接写入 Loki HTTP API
}

逻辑说明:lokiWriter 拦截原始字节流,反序列化为 map[string]interface{},从 fields 中提取预设键(如 "level" → level="error")生成 label set;pusher 封装 /loki/api/v1/push 请求,自动处理 tenant ID、stream ordering 与 batch 压缩。

字段名 是否作为 label 说明
level ✅ 用于日志级别过滤与告警
trace_id ✅ 关联链路追踪,支持 traceID 跳转
msg ❌ 仅存于日志行体,不索引
graph TD
    A[Go App log.Info] --> B[JSON Structured Log]
    B --> C[lokiWriter.Write]
    C --> D[Extract Labels]
    D --> E[Batch + Compress]
    E --> F[Loki /api/v1/push]

2.5 上下文传播与跨服务TraceID自动透传的底层实现

分布式追踪的核心在于 TraceID 的全链路一致性。当请求穿越网关、RPC、消息队列等多跳组件时,必须确保 TraceID 不丢失、不重复、不污染。

关键传播机制

  • 基于 ThreadLocal + InheritableThreadLocal 构建上下文快照
  • HTTP 场景通过 X-B3-TraceId(Zipkin 兼容)头透传
  • gRPC 使用 Metadata 进行拦截器注入

自动透传的拦截器示例(Spring Cloud Sleuth)

@Bean
public BeanPostProcessor tracingBeanPostProcessor() {
    return new TracingBeanPostProcessor(tracing); // 注入Tracing实例
}

该处理器在 @Bean 初始化阶段自动织入 Tracing 实例,使 Tracer.currentSpan() 在任意线程中可安全调用;tracing 包含 Propagation 策略,决定如何序列化/反序列化上下文。

跨线程传递保障

传播方式 支持场景 是否需手动干预
ExecutorService 线程池任务 否(已封装为 TracingExecutors)
CompletableFuture 异步链式调用 否(TracingCompletableFuture)
RxJava 响应式流 是(需 TracingSubscriber)
graph TD
    A[HTTP入口] -->|注入X-B3-TraceId| B[WebFilter]
    B --> C[Tracer.currentSpan()]
    C --> D[RPC Client Interceptor]
    D -->|透传至gRPC Metadata| E[下游服务]

第三章:OpenTelemetry Go SDK深度实践

3.1 自动化Instrumentation:HTTP/gRPC/Database零代码插桩

现代可观测性平台通过字节码增强(Bytecode Instrumentation)与运行时钩子(Runtime Hooking),在不修改业务代码前提下自动注入埋点逻辑。

原理简述

  • JVM Agent 动态织入 HTTP 客户端(如 OkHttp、Apache HttpClient)拦截器
  • gRPC Java SDK 提供 ClientInterceptor / ServerInterceptor 接口,Agent 自动注册全局拦截器
  • 数据库驱动层(如 JDBC)通过 DriverManager 代理或 DataSource 包装实现 SQL 拦截

支持协议与组件对照表

协议/组件 插桩方式 捕获字段示例
HTTP Servlet Filter / Netty ChannelHandler status_code, method, path, duration
gRPC Interceptor 注册 method_name, status, request_size
JDBC DataSource Wrapper sql, params, row_count, db_type
// 示例:JDBC 自动插桩生成的 Span 片段(伪代码)
Span span = Tracer.startSpan("jdbc.execute");
span.tag("db.statement", "SELECT * FROM users WHERE id = ?");
span.tag("db.type", "postgresql");
// ⚠️ 无需开发者调用 —— 由 Agent 在 PreparedStatement.execute() 调用前自动注入

该代码块体现 Agent 在 execute() 方法入口处通过 ASM 修改字节码,注入 Tracer.startSpan() 调用;db.statement 为脱敏后的 SQL 模板,db.type 来自 Connection.getMetaData().getDatabaseProductName()。

graph TD
A[应用启动] –> B[Agent 加载]
B –> C{检测类加载}
C –>|匹配 okhttp3.OkHttpClient| D[注入 NetworkInterceptor]
C –>|匹配 javax.sql.DataSource| E[包装 DataSource 实例]
D & E –> F[上报 Trace/Metrics/Logs]

3.2 自定义Span与语义约定(Semantic Conventions)合规实践

自定义 Span 是可观测性落地的关键环节,但必须遵循 OpenTelemetry 语义约定以确保跨系统互操作性。

合规 Span 构建示例

from opentelemetry import trace
from opentelemetry.semconv.trace import SpanAttributes

tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("user.profile.fetch") as span:
    span.set_attribute(SpanAttributes.HTTP_METHOD, "GET")
    span.set_attribute(SpanAttributes.HTTP_URL, "https://api.example.com/v1/users/123")
    span.set_attribute("user.role", "premium")  # 自定义属性(需命名空间前缀)

逻辑分析:SpanAttributes.HTTP_METHOD 确保属性名符合官方规范;自定义属性 user.role 使用小写字母+点分隔,避免与标准属性冲突;所有非标准属性应带业务前缀(如 user.、payment.),便于分类与过滤。

常见语义属性分类对照表

类别 标准属性示例 用途说明
HTTP http.method, http.status_code 描述网络请求基础特征
Database db.system, db.statement 标识数据库类型与执行语句
Messaging messaging.system, messaging.operation 消息中间件行为标准化

属性命名治理流程

graph TD
    A[定义业务场景] --> B[查语义约定文档]
    B --> C{是否存在标准属性?}
    C -->|是| D[直接使用 SpanAttributes]
    C -->|否| E[申请新属性或采用命名空间前缀]
    E --> F[记录至内部可观测性规范库]

3.3 资源(Resource)、属性(Attribute)与采样策略的生产级配置

在可观测性系统中,Resource 定义服务的静态身份(如 service.name、host.id),Attribute 描述动态上下文(如 http.status_code、user.role),二者共同构成遥测数据的语义骨架。

核心配置实践

  • Resource 应在 SDK 初始化时一次性声明,避免运行时变更;
  • 关键业务属性需通过 Span.setAttributes() 显式注入,而非依赖自动插件;
  • 采样策略须按流量特征分层:高价值交易启用 AlwaysOnSampler,后台任务采用 TraceIdRatioBasedSampler(0.01)。
# opentelemetry-collector-config.yaml
processors:
  probabilistic_sampler:
    hash_seed: 42
    sampling_percentage: 5.0  # 生产环境建议 ≤1% 避免压垮后端

该配置基于 TraceID 哈希实现无状态采样,sampling_percentage 控制整体保留率,hash_seed 确保集群内采样一致性。

维度 Resource 示例 Attribute 示例
服务标识 service.name: "api-gw" http.method: "POST"
运行环境 deployment.environment: "prod" error.type: "timeout"
graph TD
  A[HTTP Request] --> B{Sampler Decision}
  B -->|Keep| C[Export to Backend]
  B -->|Drop| D[Discard Locally]

采样决策发生在 Span 创建后、导出前,确保低开销且可审计。

第四章:多组件协同与生产就绪部署

4.1 Prometheus联邦+Remote Write与Go服务指标生命周期管理

数据同步机制

Prometheus联邦用于跨集群聚合指标,而Remote Write将原始样本异步推送至长期存储(如VictoriaMetrics、Thanos):

# prometheus.yml 片段:启用Remote Write
remote_write:
  - url: "http://vm-insert:8428/api/v1/write"
    queue_config:
      max_samples_per_send: 1000     # 每次HTTP请求最多发送样本数
      max_shards: 10                 # 并发写入分片数,提升吞吐

该配置避免本地TSDB压力陡增,同时保障高基数指标(如http_request_duration_seconds_bucket{service="auth", path="/login"})的持久化可靠性。

指标生命周期分层

  • 采集层:Go服务通过promhttp.Handler()暴露/metrics,含counter、histogram等原生指标
  • 传输层:Prometheus拉取后触发联邦或Remote Write,依据__name__和标签筛选
  • 存储层:远程存储按retention策略自动清理过期数据(如30天冷数据归档)
阶段 延迟敏感度 数据一致性要求
实时告警 高 强一致
审计分析 低 最终一致

架构协同流程

graph TD
  A[Go服务] -->|暴露/metrics| B[Prometheus拉取]
  B --> C{联邦查询}
  B --> D[Remote Write]
  C --> E[上级Prometheus聚合]
  D --> F[远程存储]

4.2 Loki Promtail轻量采集器与Go应用日志格式标准化对接

日志格式统一规范

Go 应用需输出结构化 JSON 日志,字段包含 ts(RFC3339)、level、msg 和 service:

// main.go:标准日志输出示例
log.Printf(`{"ts":"%s","level":"info","msg":"user logged in","service":"auth","uid":"u123"}`, 
    time.Now().UTC().Format(time.RFC3339))

此写法确保每行单条 JSON,兼容 Promtail 的 json 解析器;ts 字段为 UTC 时间且带时区,避免 Loki 时间戳解析偏移。

Promtail 配置关键项

# promtail-config.yaml
positions:
  filename: /var/log/positions.yaml
clients:
  - url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: go-app
  static_configs:
  - targets: [localhost]
    labels:
      job: go-api
      __path__: /var/log/go/*.log
  pipeline_stages:
  - json:
      expressions:
        ts: ts
        level: level
        msg: msg
        service: service
        uid: uid
  - labels:
      level: level
      service: service

json.expressions 显式映射字段,提升解析稳定性;labels 提取维度供 Loki 查询过滤。

字段语义对齐表

Go 日志字段 Loki 标签用途 示例值
service 多租户隔离维度 payment
level 告警分级依据 error
uid 用户级链路追踪锚点 u789

日志采集流程

graph TD
    A[Go App stdout] --> B{Promtail tail}
    B --> C[JSON 解析]
    C --> D[提取 labels & timestamp]
    D --> E[Loki HTTP push]

4.3 Grafana统一面板构建:Trace-Metrics-Logs三链路联动可视化

实现可观测性闭环的关键,在于打破三大数据孤岛。Grafana 9.0+ 原生支持 Loki(Logs)、Prometheus(Metrics)与 Tempo(Traces)的跨源关联查询。

数据同步机制

通过 traceID 作为全局关联键,在日志行、指标标签与追踪 span 中注入统一标识:

# Prometheus metric label 示例(应用埋点)
http_request_duration_seconds{job="api", traceID="a1b2c3d4"}

此处 traceID 必须为 16/32 位十六进制字符串,且需与 Tempo 的 trace_id 字段格式一致,确保 Grafana Explore 中可自动跳转。

联动视图配置要点

  • 日志查询中启用 Add context from traces
  • 指标图表添加 Trace to Logs 链接变量
  • Tempo 查看器开启 Show related logs/metrics
组件 关联字段 查询语法示例
Loki traceID {job="api"} | traceID="{{traceID}}"
Tempo trace_id trace_id="{{traceID}}"
Prometheus traceID rate(http_requests_total{traceID=~".+"}[5m])
graph TD
    A[用户点击Trace Span] --> B[Grafana提取traceID]
    B --> C[Loki执行日志上下文检索]
    B --> D[Prometheus聚合对应指标]
    C & D --> E[统一时间轴叠加渲染]

4.4 告警闭环设计:基于Prometheus Alertmanager与Loki日志触发的Go服务自愈流程

自愈流程核心架构

通过 Alertmanager 接收 Prometheus 告警,经 webhook 转发至 Go 编写的自愈网关;网关联动 Loki 查询上下文日志,执行预定义恢复动作(如重启Pod、刷新缓存、降级开关)。

关键组件协同逻辑

// 自愈网关接收Alertmanager webhook payload
type Alert struct {
    Labels      map[string]string `json:"labels"`
    Annotations map[string]string `json:"annotations"`
}

该结构解析告警元数据(如 service="auth-api"、severity="critical"),驱动后续日志检索与策略匹配。

Loki日志上下文增强

字段 示例值 用途
cluster prod-us-east 定位日志源集群
job auth-api 绑定服务标识
level error 过滤高危日志行

自愈决策流

graph TD
A[Alertmanager告警] --> B[Go网关解析labels]
B --> C{匹配自愈策略?}
C -->|是| D[Loki查询最近5m error日志]
D --> E[提取traceID/panic栈]
E --> F[执行kubectl rollout restart或API熔断]
C -->|否| G[转人工工单]

策略注册示例

  • 每条策略含 matchers(标签匹配)、lokiQuery(日志过滤表达式)、actions(可执行命令列表)
  • 支持幂等性校验与执行结果回写至Alertmanager注解

第五章:总结与展望

核心成果回顾

在实际落地的金融风控项目中,我们基于本系列方法论构建了实时反欺诈引擎,日均处理交易请求 2300 万次,平均响应延迟控制在 87ms(P95

技术栈演进路径

阶段 主要技术组件 关键改进点 上线周期
V1.0 Spring Boot + MySQL + Quartz 基于静态规则批处理(T+1) 3周
V2.0 Flink + Redis + Drools 实时流式计算 + 规则热加载 6周
V3.0 Flink CEP + Kafka + PyTorch模型服务 动态行为模式识别 + 模型在线推理 11周

典型故障应对案例

2024年Q2某次大促期间,流量峰值达日常 4.2 倍,Flink 作业出现 Checkpoint 超时(>10min)。通过以下操作快速恢复:

  • 紧急扩容 TaskManager 从 12 → 24 个
  • 将 RocksDB State Backend 切换为增量快照(state.backend.rocksdb.incremental.enabled: true)
  • 调整 checkpoint.timeout 至 15 分钟并启用 enable-checkpointing 的 fail-on-checkpointing-errors: false
  • 同步启用背压监控告警(通过 Flink Web UI 的 BackPressure 页面定位 Source 并发瓶颈)
# 生产环境状态检查命令示例
kubectl exec -it flink-jobmanager-0 -- flink list -a | grep "RUNNING"
curl -s http://flink-metrics:9249/metrics | jq '.["taskmanager_Status_Full_GC_Count"]'

架构演进路线图

graph LR
A[当前架构:Flink+Kafka+模型服务] --> B[2024 Q4:引入 Flink Statefun 实现复杂事件编排]
B --> C[2025 Q1:集成 Iceberg 构建统一特征湖]
C --> D[2025 Q2:落地 WASM 沙箱执行第三方风控策略]
D --> E[2025 Q3:构建联邦学习框架支持跨机构联合建模]

运维效能提升实证

通过将 Prometheus + Grafana + Alertmanager 集成到 CI/CD 流水线,实现变更后自动注入 17 类核心指标监控(如 flink_jobmanager_job_status, kafka_consumer_lag)。过去 6 个月,平均故障发现时间(MTTD)从 18.3 分钟降至 2.7 分钟,平均修复时间(MTTR)缩短至 11.4 分钟,SLO 达成率稳定在 99.95%。

业务协同新范式

在某城商行试点中,将风控模型输出结果以 GraphQL API 形式开放给营销团队,支撑“高风险用户精准挽留”场景:当模型判定用户存在套现倾向时,自动触发营销侧的优惠券发放策略(限制使用场景+有效期),使该类用户次月流失率降低 31%。API 调用量已达日均 4.2 万次,平均 P99 延迟 93ms。

开源社区贡献实践

向 Apache Flink 社区提交 PR #21892(修复 KafkaSource 在 Exactly-Once 模式下 offset 提交异常),已被 v1.19.1 版本合并;主导维护开源项目 flink-ml-adapter,已支持 XGBoost/LightGBM 模型在 Flink SQL 中直接调用,被 3 家金融机构生产采用。

下一代挑战清单

  • 多模态数据融合:整合设备指纹(WebGL/Canvas)、APP埋点、通话信令等异构数据源的实时对齐
  • 隐私计算落地:在不共享原始数据前提下,完成与 2 家同业机构的横向联邦建模联调
  • 硬件加速适配:验证 NVIDIA Triton 推理服务器在 A10 GPU 上部署风控模型的吞吐量提升效果
  • 可解释性增强:集成 SHAP 值实时计算模块,向业务方提供每笔拦截决策的关键特征贡献度报告

技术债治理进展

完成历史 Python 脚本(共 83 个)向 Flink SQL 的迁移,消除 100% 的 Cron 依赖;重构 Kafka Topic 分区策略,将 risk-event 主题分区数从 12 扩容至 48,解决因单分区写入瓶颈导致的延迟毛刺问题;清理过期 Flink Savepoint 存储,释放 HDFS 空间 12.7TB。

热爱算法,相信代码可以改变世界。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注