第一章:eBPF在Go云原生可观测性中的底层赋能
eBPF(extended Berkeley Packet Filter)已从网络包过滤演进为内核可编程的通用运行时,成为云原生可观测性的关键基础设施。它允许在不修改内核源码、不重启服务的前提下,安全、高效地注入观测逻辑——这对高可用Go微服务集群尤为关键。
eBPF与Go生态的协同机制
Go程序天然具备静态链接、无依赖运行的特性,但其运行时(如GC、goroutine调度、HTTP处理)缺乏直接暴露的可观测接口。eBPF通过kprobe/uprobe钩住Go二进制中的符号(如runtime.mallocgc、net/http.(*ServeMux).ServeHTTP),捕获函数入口/出口事件;借助bpf_perf_event_output将采样数据零拷贝传递至用户态,由Go程序消费。例如,追踪HTTP延迟需先定位Go二进制中http.(*Server).Serve的符号地址:
# 获取Go二进制中目标函数偏移量(需启用-debug-info或strip前保留符号)
readelf -s ./my-service | grep "Serve$" | head -1
# 输出示例:23456: 00000000004a7890 36 FUNC GLOBAL DEFAULT 13 http.(*Server).Serve
Go侧eBPF数据消费范式
Go可通过github.com/cilium/ebpf库加载eBPF程序并读取perf ring buffer。典型流程包括:打开perf event array、启动轮询goroutine、解析二进制事件结构体。关键约束是:eBPF map键值必须严格对齐Go struct字段(含padding),且需用binary.Read()按字节序解析。
核心能力对比表
| 能力维度 | 传统Go pprof | eBPF增强方案 |
|---|---|---|
| 函数调用栈深度 | 仅用户态(受限于GC栈) | 内核+用户态全栈(含syscall路径) |
| 采样开销 | ~5% CPU(wall-clock) | |
| 部署粒度 | 全局开启/关闭 | 按Pod、Namespace、甚至HTTP路径动态启停 |
实时延迟热力图生成示例
使用eBPF采集每个HTTP请求的on_enter和on_exit时间戳,Go服务聚合后输出Prometheus直方图指标:
// 在perf event handler中
histogram.WithLabelValues(method, path).Observe(float64(latencyNs) / 1e6) // 单位:ms
第二章:Kratos微服务框架的云原生架构实践
2.1 Kratos核心分层模型与Go泛型驱动的Service抽象
Kratos 的分层模型遵循“Transport → Service → Biz → Data”四层解耦设计,其中 Service 层 是业务逻辑的核心载体,也是 Go 泛型能力落地的关键环节。
泛型 Service 接口定义
// Service 定义支持任意请求/响应类型,消除重复接口声明
type Service[Req, Resp any] interface {
Handle(ctx context.Context, req *Req) (*Resp, error)
}
该泛型接口使同一服务契约可复用于 UserCreate、OrderQuery 等异构场景;Req 和 Resp 类型在编译期绑定,兼顾类型安全与复用性。
分层职责对比
| 层级 | 职责 | 典型实现方式 |
|---|---|---|
| Transport | 协议适配(HTTP/gRPC) | http.Server / grpc.Server |
| Service | 业务编排与泛型契约 | Service[*v1.UserReq, *v1.UserReply] |
| Biz | 领域规则与状态校验 | user.Validate() |
| Data | 数据访问与事务封装 | userRepo.Create() |
数据流示意
graph TD
A[HTTP Request] --> B[Transport Handler]
B --> C[Service[*v1.UserReq,*v1.UserReply]]
C --> D[Biz Logic]
D --> E[Data Repository]
E --> C
C --> B
B --> F[HTTP Response]
2.2 基于Kratos Middleware链的eBPF事件注入与上下文透传
Kratos 的 Middleware 链天然支持跨层上下文传递,为 eBPF 事件注入提供了轻量级集成通道。核心在于将 eBPF 用户态探针(如 libbpf-go)封装为 transport.Handler,在 RPC 请求生命周期中精准注入可观测事件。
数据同步机制
通过 context.WithValue() 将 eBPF 采集的 trace ID、CPU 毛刺标记等注入 ctx,经 Kratos ServerOption 注册至 middleware 链首节点:
func EBPFContextMiddleware() middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
// 注入 eBPF 采集的调度延迟指标(纳秒级)
ctx = context.WithValue(ctx, "ebpf.sched_delay_ns", uint64(128500))
return handler(ctx, req)
}
}
}
逻辑分析:该中间件在请求进入时注入 eBPF 实时采集的调度延迟值(
sched_delay_ns),参数uint64(128500)表示当前线程被抢占 128.5μs,供下游服务做 SLA 熔断判断。
上下文透传路径
| 阶段 | 透传载体 | 示例键名 |
|---|---|---|
| eBPF probe | BPF ringbuf | sched_delay_ns |
| 用户态接收 | Go context | "ebpf.sched_delay_ns" |
| HTTP header | X-Ebpf-Delay |
128500(自动序列化) |
graph TD
A[eBPF kprobe] -->|ringbuf| B[libbpf-go]
B -->|SetContext| C[Kratos Middleware]
C --> D[Service Logic]
D -->|Read ctx.Value| E[动态限流决策]
2.3 Kratos+OpenTelemetry SDK深度集成:自动Span注入与指标埋点标准化
Kratos 框架通过 middleware/tracing 中间件实现 OpenTelemetry SDK 的无侵入式集成,HTTP/gRPC 请求生命周期自动创建 Span。
自动 Span 注入机制
func Tracing() middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
// 从 HTTP Header 或 gRPC metadata 提取 traceparent
span := otel.Tracer("kratos").Start(ctx, "http.server.request")
defer span.End()
return handler(context.WithValue(ctx, tracingKey, span), req)
}
}
}
逻辑分析:otel.Tracer("kratos") 使用全局注册的 SDK 实例;Start() 自动关联父 Span(通过 W3C TraceContext);defer span.End() 确保异常路径下 Span 正确终止。
标准化指标埋点字段
| 指标名 | 类型 | 示例值 | 说明 |
|---|---|---|---|
| http.server.duration | Histogram | 124.5ms | 基于 OTel 语义约定 |
| rpc.server.requests | Counter | +1 per call | 自动按 method/status 维度打点 |
数据同步机制
graph TD
A[HTTP Request] --> B[Tracing Middleware]
B --> C[Span Start + Context Propagation]
C --> D[Service Handler]
D --> E[Metrics Exporter]
E --> F[OTLP Endpoint]
2.4 Kratos服务网格侧车(Sidecar-Light)模式下的Terraform声明式部署适配
Kratos 的 Sidecar-Light 模式剥离了传统 Istio Envoy 的全量代理逻辑,仅嵌入轻量级流量拦截与协议感知模块(如 gRPC-Web 转换、熔断指标上报),由 Terraform 统一编排其生命周期。
核心部署结构
- 与主应用 Pod 共享网络命名空间,但不共享进程(区别于经典 sidecar)
- 通过
initContainer注入 iptables 规则,仅劫持9000-9999端口范围内的 gRPC 流量 - 所有配置通过 ConfigMap 声明式注入,支持
kubectl apply -f与terraform apply双路径交付
Terraform 模块关键参数
| 参数 | 类型 | 说明 |
|---|---|---|
sidecar_image |
string | Kratos-sidecar-light:v1.8.3,需兼容 Go 1.21+ runtime |
traffic_ports |
list(number) | 显式声明需代理的端口列表,避免全端口劫持 |
telemetry_endpoint |
string | 指向集群内 OpenTelemetry Collector 的 gRPC 地址 |
resource "kubernetes_config_map" "kratos_sidecar_config" {
metadata {
name = "kratos-sidecar-config"
namespace = "default"
}
data = {
"config.yaml" = yamlencode({
telemetry = {
endpoint = "otel-collector.default.svc.cluster.local:4317"
interval = "30s"
}
traffic = {
ports = [9090, 9100]
}
})
}
}
该 ConfigMap 被挂载至 sidecar 容器 /etc/kratos/config.yaml,驱动其动态加载策略;yamlencode 确保配置结构安全序列化,避免 HCL 字符串拼接引发的 YAML 注入风险。
graph TD
A[Terraform Plan] --> B[生成 ConfigMap + Deployment]
B --> C[Sidecar-Light InitContainer]
C --> D[iptables -t nat -A OUTPUT -p tcp --dport 9090 -j REDIRECT --to-port 15001]
D --> E[主应用gRPC调用自动重定向]
2.5 Kratos生产级配置热加载与eBPF动态过滤规则协同演进
Kratos 的 config 模块通过 Watcher 接口实现配置变更的秒级热加载,而 eBPF 程序则通过 bpf_map_update_elem() 动态更新过滤策略映射表,二者通过统一的 RuleVersion 字段对齐语义版本。
数据同步机制
配置中心推送新规则后:
- Kratos 更新本地
ConfigMap并触发OnChange回调 - 回调中序列化规则为
struct bpf_filter_rule,写入 pinned BPF map
// 同步规则至eBPF map(伪代码)
rule := &bpfFilterRule{
SrcIP: net.ParseIP("10.0.1.100").To4(),
Port: 8080,
Action: BPF_ACTION_ALLOW,
Version: 12345, // 与Kratos config.version一致
}
bpfMap.Update(unsafe.Pointer(&key), unsafe.Pointer(rule), 0)
该调用将规则原子写入 filter_rules map,eBPF verifier 保证内存安全;Version 字段用于下游 eBPF 程序校验规则新鲜度,避免脏读。
协同演进关键参数
| 参数 | 作用 | 示例值 |
|---|---|---|
config.version |
Kratos 配置版本戳 | "v2.3.1-20240521" |
bpf_map.max_entries |
过滤规则上限 | 65536 |
bpf.prog.attach_point |
过滤挂载点 | SK_SKB |
graph TD
A[Config Center] -->|Push v2.3.1| B(Kratos Watcher)
B --> C[Update ConfigMap]
C --> D[Serialize & bpfMap.Update]
D --> E[eBPF Program]
E -->|Apply in-line| F[Network Packet Path]
第三章:OpenTelemetry Go SDK的统一遥测体系建设
3.1 OpenTelemetry Collector定制化Receiver开发:对接eBPF perf event数据流
为实现内核级可观测性,需将 eBPF perf_event 数据(如 CPU cycles、page-faults)实时注入 OpenTelemetry Collector。核心在于实现自定义 receiver,继承 component.Receiver 接口并注册 Start()/Shutdown() 生命周期方法。
数据同步机制
采用 ring buffer + batch pull 模式避免阻塞:
- eBPF 程序将采样事件写入
perf_event_array; - Go 侧通过
github.com/cilium/ebpf/perf库轮询读取; - 批量转换为
pmetric.Metric后交由consumer.Metrics处理。
// 初始化 perf reader
reader, err := perf.NewReader(bpfMap, 4*os.Getpagesize())
if err != nil {
return fmt.Errorf("failed to create perf reader: %w", err)
}
// 参数说明:
// bpfMap:已加载的 BPF_MAP_TYPE_PERF_EVENT_ARRAY;
// 4*os.Getpagesize():单次最大读取缓冲区大小(页对齐)
关键配置字段
| 字段 | 类型 | 说明 |
|---|---|---|
perf_map_name |
string | BPF 程序中 perf event array 的 map 名称 |
sample_rate |
int | eBPF bpf_perf_event_read_value() 采样频率(Hz) |
batch_size |
int | 单次提交的 metric 数量上限 |
graph TD
A[eBPF perf_event] -->|mmap'd ring buffer| B[Go perf.NewReader]
B --> C[Parse to pdata.Metrics]
C --> D[OTel Metrics Exporter]
3.2 Go应用端Tracing语义约定与Kratos gRPC拦截器的零侵入集成
OpenTelemetry 定义了标准的 gRPC Tracing 语义:rpc.system="grpc"、rpc.method、rpc.service 及状态码映射(如 status.code=2 → STATUS_CODE_OK)。
Kratos 的 UnaryServerInterceptor 可自动注入 span,无需修改业务 handler:
import "github.com/go-kratos/kratos/v2/middleware/tracing"
// 注册拦截器(仅需一行)
srv := grpc.NewServer(
grpc.Middleware(
tracing.Server(),
),
)
该拦截器自动:
- 从
metadata提取traceparent并继续 trace 上下文 - 设置
rpc.method为/helloworld.v1.Greeter/SayHello - 记录
net.peer.ip和http.status_code(适配 gRPC HTTP/2 映射)
| 字段 | 来源 | 示例 |
|---|---|---|
rpc.service |
proto service name | helloworld.v1.Greeter |
rpc.method |
full method path | SayHello |
status.code |
gRPC status code | (OK) |
graph TD A[Incoming gRPC Request] –> B{tracing.Server Interceptor} B –> C[Extract Trace Context] B –> D[Start Span with OTel Semantics] B –> E[Attach Attributes per RPC Spec] D –> F[Invoke Handler] F –> G[End Span with Status]
3.3 基于OTLP+Prometheus Exporter的多维指标聚合与Terraform监控栈编排
数据同步机制
OTLP Collector 通过 prometheusremotewrite exporter 将多维指标(如 http_requests_total{job="terraform",env="prod",region="us-east-1"})按标签维度聚合后,转换为 Prometheus 远程写协议格式。
# otel-collector-config.yaml
exporters:
prometheusremotewrite:
endpoint: "https://prometheus.example.com/api/v1/write"
headers:
Authorization: "Bearer ${PROM_TOKEN}"
此配置启用安全远程写入:
endpoint指向 Prometheus Pushgateway 兼容端点;headers注入认证令牌确保租户隔离;${PROM_TOKEN}由 Terraform secrets 模块注入,实现凭证动态绑定。
Terraform 监控栈编排
使用模块化声明式编排,统一管理 OTLP Collector、Prometheus Server 与 Exporter 生命周期:
| 组件 | 版本 | 部署方式 | 标签继承 |
|---|---|---|---|
| otel-collector | v0.104.0 | Helm | metrics_job=terraform |
| prometheus | v2.47.0 | Kustomize | 自动注入 cluster_id label |
指标聚合流程
graph TD
A[Terraform Provider Metrics] --> B[OTLP gRPC Endpoint]
B --> C[Label-Based Aggregation]
C --> D[Prometheus Remote Write]
D --> E[Prometheus TSDB]
- 聚合粒度由
resource_attributes和metric_labels双重控制 - 所有指标自动携带
terraform_workspace和module_source标签,支持跨环境对比分析
第四章:Terraform驱动的基础设施即代码(IaC)协同治理
4.1 Terraform模块化设计:封装eBPF探针部署、Kratos服务集群与OTel Collector资源栈
模块职责解耦
将可观测性栈划分为三个高内聚子模块:
ebpf-probe:基于bpfprogram资源注入 eBPF 字节码,支持动态加载/卸载;kratos-cluster:声明式定义 Kratos 微服务 Pod、Service 及 HPA;otel-collector:配置 receivers(OTLP/Jaeger)、processors(batch、memory_limiter)、exporters(to Loki + Tempo)。
核心模块调用示例
module "observability_stack" {
source = "./modules/observability"
# 共享参数注入
cluster_name = var.cluster_name
namespace = "observability"
ebpf_bytecode = filebase64("${path.module}/assets/trace_kprobe.o")
kratos_replicas = 3
}
此调用统一入口抽象底层资源依赖。
filebase64确保 eBPF 字节码安全嵌入,避免挂载卷权限问题;kratos_replicas驱动 HorizontalPodAutoscaler 的minReplicas与maxReplicas自动推导。
组件协同关系
graph TD
A[eBPF Probe] -->|OTLP over gRPC| B[OTel Collector]
C[Kratos Service] -->|OTLP Exporter| B
B --> D[Loki for Logs]
B --> E[Tempo for Traces]
参数映射表
| 参数名 | 类型 | 用途 | 默认值 |
|---|---|---|---|
enable_profiling |
bool | 启用 eBPF CPU/heap profiling | false |
collector_image |
string | OTel Collector 镜像版本 | "otel/opentelemetry-collector:0.102.0" |
4.2 Terraform Provider扩展开发:支持Kratos服务健康检查与eBPF运行时状态校验
为实现云原生可观测性闭环,需在Terraform Provider中集成双重校验能力:既验证Kratos gRPC服务的可用性,又确认eBPF程序在目标节点的实际加载状态。
核心校验逻辑设计
- Kratos健康检查:通过
/healthz端点发起gRPC Health Check协议请求; - eBPF状态校验:读取
/sys/kernel/btf/vmlinux及bpftool prog list输出,匹配预期程序名与状态标志。
Terraform资源定义示例
resource "kratos_ebpf_monitor" "api_gateway" {
endpoint = "localhost:9000"
bpf_program = "kratos_auth_trace"
timeout_ms = 5000
}
该配置触发Provider调用kratos.HealthCheck()与ebpf.ProgStatus("kratos_auth_trace"),任一失败即中断apply流程。
状态映射表
| 检查项 | 成功条件 | 失败响应 |
|---|---|---|
| Kratos健康 | status == SERVING |
408 Timeout或UNAVAILABLE |
| eBPF程序加载 | state == "RUNNING"且jited == 1 |
ENOENT或state == "ERROR" |
执行流程
graph TD
A[terraform apply] --> B[Init kratos_ebpf_monitor]
B --> C{Kratos /healthz call}
C -->|Success| D{eBPF prog list}
C -->|Fail| E[Plan error]
D -->|Matched| F[Resource created]
D -->|Not found| G[Plan error]
4.3 GitOps流水线中Terraform State与OpenTelemetry SLO配置的版本联动机制
数据同步机制
GitOps控制器(如Flux v2)监听infra/terraform/与slo/otel/两个路径变更,通过SHA-256哈希比对触发协同部署:
# kustomization.yaml —— 声明跨目录依赖关系
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../terraform/
- ../otel-slo/
patchesStrategicMerge:
- patch: |
- op: add
path: /spec/dependsOn/-
value: {name: "terraform-state-sync", namespace: "flux-system"}
该补丁强制SLO资源配置等待Terraform状态同步完成,避免指标采集目标缺失。
版本锚点一致性保障
| 组件 | 锚定方式 | 验证机制 |
|---|---|---|
| Terraform State | backend.tf 中 bucket = "state-${GIT_COMMIT}" |
S3前缀校验 + ETag比对 |
| OpenTelemetry SLO | slo.yaml 中 version: ${GIT_COMMIT} |
Admission Webhook拦截非法版本 |
联动流程
graph TD
A[Git Push] --> B[Flux detects infra/terraform/ & slo/otel/]
B --> C{Hash match?}
C -->|Yes| D[Apply Terraform Plan]
C -->|No| E[Reject sync]
D --> F[Update state backend metadata]
F --> G[Trigger Otel SLO reconciler with same commit ref]
Terraform输出的outputs.tf中注入otel_endpoint和service_name字段,被SLO配置模板自动引用,实现基础设施与可观测性策略的原子级对齐。
4.4 多环境(Dev/Staging/Prod)差异化eBPF观测策略的Terraform变量驱动实现
不同环境对可观测性精度、采样率与资源开销容忍度差异显著:开发环境需全量追踪调试,预发布环境侧重关键路径采样,生产环境则强调低开销与稳定性。
环境策略映射表
| 环境 | eBPF程序类型 | 采样率 | 跟踪深度 | 日志保留时长 |
|---|---|---|---|---|
dev |
tracepoint |
100% | full | 1h |
staging |
kprobe |
5% | service | 24h |
prod |
uprobe |
0.1% | http/rpc | 7d |
Terraform变量驱动核心逻辑
variable "env" {
description = "Target deployment environment: dev/staging/prod"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.env)
error_message = "env must be one of 'dev', 'staging', or 'prod'."
}
}
locals {
ebpf_config = {
dev = { sampling_rate = 1.0, program_type = "tracepoint", depth = "full" },
staging = { sampling_rate = 0.05, program_type = "kprobe", depth = "service" },
prod = { sampling_rate = 0.001, program_type = "uprobe", depth = "http/rpc" }
}[var.env]
}
该代码通过 var.env 动态索引 locals.ebpf_config,将环境语义直接转化为eBPF运行参数。sampling_rate 控制 bpf_perf_event_output 触发频率;program_type 决定加载的eBPF字节码镜像;depth 指导内核探针注入点层级(如 http/rpc 仅挂载在 http_send_response 和 rpc_call_enter 等关键函数)。
数据同步机制
eBPF map 数据经 libbpfgo 提取后,由环境感知的 exporter 根据 local.ebpf_config.sampling_rate 动态调节上报批次大小与重试间隔,确保 Dev 环境高保真、Prod 环境低抖动。
第五章:CI/CD模板落地与四层架构演进展望
模板化流水线在金融核心系统的首次规模化部署
2023年Q4,某全国性股份制银行将标准化CI/CD模板(基于GitLab CI + Argo CD + Helm)落地至17个关键交易系统。模板强制嵌入三项合规检查:静态代码扫描(SonarQube规则集v9.5)、密钥泄露检测(TruffleHog 3.6)、Kubernetes资源配置审计(kube-bench CIS v1.6.1)。所有流水线均启用“双签门禁”——开发提交后需经安全组+运维组双重审批方可进入预发布环境。实际运行数据显示,平均构建耗时从原先的18.3分钟降至6.7分钟,生产变更回滚时间由小时级压缩至92秒。
四层架构演进中的CI/CD适配挑战
| 架构层级 | 传统CI/CD痛点 | 演进后适配方案 | 实测效果 |
|---|---|---|---|
| 基础设施层(IaC) | Terraform apply无灰度能力 | 引入Terragrunt模块化+Atlantis PR驱动 | 变更失败率下降76% |
| 平台服务层(Service Mesh) | Sidecar注入导致测试环境不可控 | 流水线中集成istioctl verify + 自定义Envoy配置校验脚本 | 配置错误拦截率达100% |
| 应用服务层(微服务) | 多语言服务共用同一Pipeline易冲突 | 基于语言特征自动加载Dockerfile模板(Go/Java/Python专用镜像基线) | 构建成功率提升至99.92% |
| 数据服务层(CDC同步) | Flink作业版本升级缺乏回滚验证 | 在CI阶段注入Flink SQL语法校验+State Backend兼容性测试 | 生产数据一致性事故归零 |
实战案例:电商大促前的四层协同发布
2024年618大促前,某头部电商平台完成四层架构联合发布演练:基础设施层通过Terraform动态扩缩容云资源;平台层滚动更新Istio Gateway配置以支持新流量路由策略;应用层按服务依赖图谱分批次发布(订单→支付→物流);数据层同步启用Debezium增量同步开关。整个过程由单一流水线模板驱动,各层状态通过Prometheus指标实时反馈至统一看板,异常时自动触发熔断机制并推送企业微信告警。
# 示例:四层架构感知型Pipeline片段
stages:
- infra-validate
- platform-sync
- app-deploy
- data-migration
infra-validate:
stage: infra-validate
script:
- terragrunt validate --terragrunt-working-dir ./iac/prod
- curl -s "https://api.prometheus.io/api/v1/query?query=up{job='terraform'}" | jq '.data.result[].value[1]'
架构演进对CI/CD可观测性的新要求
随着四层架构深度耦合,传统日志+指标监控已无法定位跨层故障。团队在流水线中嵌入OpenTelemetry Collector,自动采集从Terraform执行、Envoy代理配置变更、Spring Boot Actuator健康检查到Flink Checkpoint延迟的全链路Span。Mermaid流程图展示关键路径追踪逻辑:
graph LR
A[Terraform Apply] --> B[Envoy Config Push]
B --> C[Spring Boot Health Probe]
C --> D[Flink State Snapshot]
D --> E[Prometheus Alert Trigger]
E --> F[自动回滚决策引擎]
安全左移在四层架构中的具象实践
安全能力不再仅限于SAST扫描,而是按架构层级注入差异化控制点:基础设施层校验AWS IAM策略最小权限原则;平台层验证Istio PeerAuthentication是否启用mTLS;应用层强制注入OpenAPI 3.0规范校验;数据层实施SQL注入模式匹配(基于SQLMap规则库裁剪版)。所有校验结果以JUnit XML格式输出,未通过项直接阻断Pipeline下一阶段。
持续演进的技术债治理机制
为避免CI/CD模板僵化,建立“模板健康度仪表盘”,实时统计各系统对模板的定制化修改比例(当前阈值设定为≤15%)。当某服务连续3次构建因模板兼容性失败,自动触发模板升级工单并关联架构委员会评审。最近一次升级中,将Helm Chart渲染逻辑从Shell脚本迁移至Helmfile,使Chart版本管理准确率提升至100%。
