Posted in

【Go中台服务可观测性建设白皮书】:零基础搭建Prometheus+OpenTelemetry+Jaeger三位一体监控体系

第一章:Go中台服务可观测性建设全景概览

可观测性不是监控的简单升级,而是面向云原生与微服务架构下,对系统内部状态进行深度理解的能力体系。在Go语言构建的中台服务场景中,其核心由三大支柱构成:日志(Logging)、指标(Metrics)和链路追踪(Tracing),三者协同支撑故障定位、性能分析与容量规划。

日志采集与结构化治理

Go服务应避免使用fmt.Println或未结构化的log.Printf。推荐采用zap(高性能)或slog(Go 1.21+ 标准库)进行结构化日志输出:

import "log/slog"

func handler(w http.ResponseWriter, r *http.Request) {
    // 自动注入请求ID、时间戳、服务名等上下文字段
    logger := slog.With(
        "service", "user-center",
        "request_id", r.Header.Get("X-Request-ID"),
        "path", r.URL.Path,
    )
    logger.Info("HTTP request started")
    defer logger.Info("HTTP request completed")
}

日志需经Filebeat或OpenTelemetry Collector统一采集,转为JSON格式接入ELK或Loki。

指标暴露与标准化实践

所有Go服务必须通过/metrics端点暴露Prometheus兼容指标。使用prometheus/client_golang注册关键业务与运行时指标:

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

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

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

配合Prometheus配置静态抓取目标,并通过Grafana构建服务健康看板。

分布式链路追踪集成

借助OpenTelemetry SDK实现零侵入追踪注入:

  • 在HTTP中间件中自动创建span
  • 使用otelhttp.NewHandler包装路由处理器
  • 通过OTEL_EXPORTER_OTLP_ENDPOINT指向Jaeger或Tempo后端
维度 推荐工具链 关键价值
日志 zap + OpenTelemetry Collector 高吞吐、低GC、上下文关联
指标 prometheus/client_golang + Grafana 多维聚合、告警驱动运维
追踪 OpenTelemetry Go SDK + Tempo 跨服务延迟分析、根因定位

可观测性建设需贯穿研发、测试、发布全流程,而非仅部署后补救。每个Go服务模块应默认携带可观察能力出厂。

第二章:Prometheus监控体系深度集成

2.1 Prometheus服务发现与Go应用指标暴露原理与实践

Prometheus通过服务发现(Service Discovery)动态感知目标实例,而Go应用需主动暴露符合OpenMetrics规范的指标端点。

指标暴露:基于promhttp的标准实践

package main

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", "status"},
    )
)

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

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

该代码注册了带标签的计数器,并在HTTP处理中实时更新。promhttp.Handler()将自动响应/metrics路径,输出文本格式指标;MustRegister确保指标注册失败时panic,避免静默失效。

服务发现机制对比

发现方式 动态性 配置复杂度 适用场景
static_configs 测试/固定IP环境
consul_sd_config 微服务注册中心
kubernetes_sd_config K8s原生集群

数据同步机制

graph TD A[Prometheus Server] –>|HTTP GET /metrics| B(Go App) B –> C[Exposes metrics in OpenMetrics text format] A –> D[Scrapes every ‘scrape_interval’] D –> E[Stores in TSDB with labels]

2.2 自定义Go业务指标(Counter/Gauge/Histogram)设计与埋点规范

核心指标选型原则

  • Counter:仅单调递增,适用于请求总量、错误累计等;
  • Gauge:可增可减,适合当前活跃连接数、内存使用量等瞬时状态;
  • Histogram:记录观测值分布,如HTTP延迟、队列等待时长,自动分桶统计。

埋点命名规范

// 推荐:service_name_metric_type_suffix{labels}
http_requests_total{method="POST",status="200"}  // Counter
order_queue_length{region="cn-east"}             // Gauge
payment_duration_seconds_bucket{le="0.1"}        // Histogram

逻辑说明:_total 后缀显式标识 Counter;_bucket 是 Histogram 必备后缀;所有 label 值需经 prometheus.LabelValue 校验,避免非法字符导致采集失败。

指标注册与初始化(示例)

var (
    // Counter:订单创建总数
    orderCreatedCounter = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "order_created_total",
            Help: "Total number of orders created",
        },
        []string{"source"}, // 动态维度:app, api, admin
    )
)

参数说明:promauto.NewCounterVec 自动注册并全局唯一;[]string{"source"} 定义 label 键名,运行时通过 .WithLabelValues("api") 绑定具体值。

指标类型 是否支持负值 是否支持分位数 典型场景
Counter 请求计数、失败次数
Gauge 当前并发数、缓存命中率
Histogram 是(via _sum, _count, _bucket API 响应延迟分布
graph TD
    A[业务代码] --> B[调用 Inc()/Set()/Observe()]
    B --> C{指标类型路由}
    C --> D[Counter:原子累加]
    C --> E[Gauge:CAS 更新]
    C --> F[Histogram:分桶+计数器更新]
    D & E & F --> G[Prometheus Exporter]

2.3 Prometheus Rule配置与告警策略在微服务场景下的落地实现

在微服务架构中,服务粒度细、实例动态伸缩,需基于标签(job, instance, service)构建可复用的告警规则。

核心告警规则示例

# alert-rules.yml
groups:
- name: microservice-alerts
  rules:
  - alert: HighErrorRate5m
    expr: |
      sum by (service, job) (rate(http_request_duration_seconds_count{status=~"5.."}[5m]))
      /
      sum by (service, job) (rate(http_request_duration_seconds_count[5m]))
      > 0.05
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "High HTTP 5xx rate for {{ $labels.service }}"

该规则按 servicejob 聚合计算 5 分钟内 5xx 错误率,阈值设为 5%。for: 10m 避免瞬时抖动误报;by (service, job) 确保告警精准归属到具体服务与部署单元。

告警分级策略

级别 触发条件 通知渠道
critical P99 延迟 > 2s 且持续 5min 电话 + 钉钉
warning 错误率 > 5% 或 CPU > 90% 钉钉 + 邮件
info 实例重启次数/小时 > 3 企业微信

动态服务发现适配

graph TD
  A[Prometheus scrape config] --> B[基于Consul SD发现实例]
  B --> C[自动注入 service/job 标签]
  C --> D[Rule Engine 按 service 分组评估]
  D --> E[Alertmanager 按 receiver 路由]

2.4 Grafana可视化看板构建:面向Go中台的多维度SLO仪表盘实战

核心指标建模

面向Go中台服务,SLO仪表盘聚焦三大维度:可用性(HTTP 5xx / total)延迟(p95 、饱和度(goroutines > 500)。指标统一通过Prometheus暴露,路径为 /metrics

Prometheus查询语句示例

# 可用性SLO:过去1小时错误率
rate(http_requests_total{status=~"5.."}[1h]) 
/ 
rate(http_requests_total[1h])

逻辑说明:rate()自动处理计数器重置;[1h]窗口适配SLO计算周期;分母含所有请求确保分母完备性。

Grafana面板配置关键参数

字段 说明
Min Step 30s 匹配Go服务metrics采集间隔
Max Data Points 240 平衡精度与前端渲染性能
Thresholds 0.01, 0.05 对应99% & 95% SLO达标线

数据同步机制

Grafana通过Prometheus数据源直连,启用query timeout: 30shttp method: POST保障高并发下稳定性。

2.5 Prometheus联邦与长期存储方案:应对高基数指标的Go服务集群演进

随着Go微服务实例数突破500+,单体Prometheus面临内存飙升与查询超时问题。联邦机制成为关键分流手段。

联邦配置示例

# 全局联邦目标(采集各区域Prometheus的聚合指标)
- job_name: 'federate'
  scrape_interval: 15s
  honor_labels: true
  metrics_path: '/federate'
  params:
    'match[]':
      - '{job=~"go-service-.*", __name__=~"http_requests_total|go_goroutines"}'
  static_configs:
    - targets: ['region-a-prom:9090', 'region-b-prom:9090']

该配置仅拉取高业务价值聚合指标(非原始直方图),honor_labels: true 保留源job/instance标签;match[] 严格限定指标白名单,避免基数爆炸。

存储分层策略对比

方案 写入延迟 查询灵活性 运维复杂度 适用场景
Thanos Sidecar 多集群统一视图
VictoriaMetrics 极低 单集群高吞吐场景
Cortex(多租户) SaaS型监控平台

数据同步机制

graph TD
  A[Go服务] -->|Push via OpenTelemetry| B(OTLP Gateway)
  B --> C[Prometheus Remote Write]
  C --> D{Storage Tier}
  D --> E[Thanos Object Store]
  D --> F[VictoriaMetrics TSDB]

联邦降低中心Prometheus负载,而远程写将原始高基数指标卸载至长期存储,实现“热数据本地查、冷数据对象存”的演进路径。

第三章:OpenTelemetry统一遥测数据采集

3.1 OpenTelemetry Go SDK初始化与上下文传播机制解析与实操

OpenTelemetry Go SDK 的初始化是可观测性能力落地的起点,核心在于 sdktrace.TracerProvider 与全局 otel.Tracer 的绑定,以及 otel.GetTextMapPropagator() 对上下文传播的支撑。

初始化关键步骤

  • 调用 sdktrace.NewTracerProvider() 配置采样器、处理器(如 stdout 或 Jaeger exporter)
  • 使用 otel.SetTracerProvider() 注入全局 tracer provider
  • 设置 otel.SetTextMapPropagator(propagation.TraceContext{}) 启用 W3C Trace Context 标准传播

上下文传播原理

ctx := context.Background()
ctx, span := tracer.Start(ctx, "api-handler")
defer span.End()

// 在 HTTP 服务端提取 trace context
carrier := propagation.HeaderCarrier(r.Header)
ctx = otel.GetTextMapPropagator().Extract(ctx, carrier)

此代码从 HTTP 请求头中提取 traceparent 字段,还原分布式调用链上下文。HeaderCarrier 实现了 TextMapCarrier 接口,Extract() 方法解析并注入 span context 到 ctx 中,确保后续 Start() 创建的 span 自动关联 parent。

组件 作用 默认实现
TracerProvider 管理 tracer 生命周期与导出策略 sdktrace.NewTracerProvider()
Propagator 序列化/反序列化 trace context propagation.TraceContext{}
graph TD
    A[HTTP Client] -->|inject traceparent| B[HTTP Server]
    B -->|Extract from headers| C[span context]
    C --> D[tracer.Start(ctx, ...)]

3.2 自动化+手动双模链路追踪注入:覆盖HTTP/gRPC/数据库调用全路径

在微服务全景观测中,单一注入方式难以兼顾兼容性与可控性。双模注入机制通过自动化探针(如OpenTelemetry Auto-Instrumentation)捕获标准协议流量,同时开放手动API(Tracer.withSpan())供关键路径深度埋点。

注入策略对比

模式 覆盖范围 灵活性 典型场景
自动化注入 HTTP/gRPC/Redis/JDBC 标准框架调用
手动注入 任意代码段 异步任务、消息体解析等

手动注入示例(Java)

// 在数据库连接池获取后显式创建子Span
Span dbSpan = tracer.spanBuilder("db.query")
    .setParent(Context.current().with(parentSpan))
    .setAttribute("db.statement", "SELECT * FROM users WHERE id = ?")
    .startSpan();
try (Scope scope = dbSpan.makeCurrent()) {
    // 执行JDBC查询
} finally {
    dbSpan.end(); // 必须显式结束,避免Span泄漏
}

逻辑分析:spanBuilder 构建命名Span;setParent 显式继承上下文,确保跨线程链路连续;setAttribute 补充业务语义标签;makeCurrent() 激活当前作用域,使后续自动注入Span可正确关联。

全链路协同流程

graph TD
    A[HTTP入口] -->|自动注入| B[Controller]
    B -->|手动注入| C[Async Task]
    B -->|自动注入| D[gRPC Client]
    D -->|自动注入| E[Remote Service]
    B -->|手动注入| F[JDBC Connection]
    F -->|自动注入| G[MySQL Driver]

3.3 资源属性、Span属性与语义约定在Go中台服务中的标准化实践

在微服务治理中,统一资源标识与可观测性上下文是链路追踪准确归因的前提。我们基于 OpenTelemetry Go SDK,在网关、订单、库存等中台服务中落地语义约定。

标准化资源属性注入

import "go.opentelemetry.io/otel/sdk/resource"

res, _ := resource.Merge(
    resource.Default(),
    resource.NewWithAttributes(
        semconv.SchemaURL,
        semconv.ServiceNameKey.String("order-service"),
        semconv.ServiceVersionKey.String("v2.4.0"),
        semconv.DeploymentEnvironmentKey.String("prod"),
        semconv.CloudProviderKey.String("aliyun"),
        semconv.CloudRegionKey.String("cn-shanghai"),
    ),
)

该代码将服务名、版本、环境、云厂商与地域作为全局资源属性注入 SDK。semconv 来自 go.opentelemetry.io/otel/semconv/v1.21.0,确保跨语言语义一致;Merge 保留默认主机信息(如 host.name),避免覆盖关键基础设施元数据。

Span 属性规范映射表

场景 推荐属性键 示例值 说明
HTTP 路由 http.route /api/v1/orders/{id} 静态模板,非实际路径
数据库操作 db.operation SELECT 统一 SQL 动词
业务领域标识 biz.tenant_id "tenant-a" 自定义命名空间,带 biz. 前缀

追踪上下文传播流程

graph TD
    A[HTTP Handler] -->|Inject: traceparent + resource attrs| B[Service Logic]
    B --> C[DB Client]
    C -->|Add: db.statement, db.operation| D[Span End]
    D --> E[Export to Jaeger]

所有 Span 必须携带 service.name(来自资源)与 http.method(来自 HTTP 适配器),确保后端分析平台可聚合维度。

第四章:Jaeger分布式追踪闭环治理

4.1 Jaeger后端部署与Go服务Trace采样策略调优(自适应采样+头部优先)

Jaeger后端推荐采用all-in-one轻量部署快速验证,生产环境则建议分离collectorquerystorage(如Cassandra/Elasticsearch):

# docker-compose.yml 片段:启用自适应采样器
environment:
  - SPAN_STORAGE_TYPE=elasticsearch
  - COLLECTOR_SAMPLING_MANAGER_HOST_PORT=sampling-manager:8080

COLLECTOR_SAMPLING_MANAGER_HOST_PORT 指向独立的采样策略服务,使采样决策脱离单点瓶颈,支持动态更新。

自适应采样核心逻辑

Jaeger通过adaptive-sampler基于近期trace速率自动调整采样率(0.001–1.0),避免突发流量打爆存储:

指标 说明 默认值
initialSamplingRate 启动初始采样率 0.01
samplingRatePerOperation 按操作名独立配置 {"/api/user": 0.5}

Go客户端头部优先(Head-based)采样实现

import "github.com/jaegertracing/jaeger-client-go/config"

cfg := config.Configuration{
  Sampler: &config.SamplerConfig{
    Type:  "probabilistic", // 兼容头部透传的轻量策略
    Param: 0.001,          // 仅当无上游traceID或flags=1时生效
  },
}

此配置确保:若HTTP请求携带uber-trace-idflags=1(即已标记需采样),则强制保留该trace,实现“头部优先”语义;否则按概率采样,兼顾性能与可观测性。

graph TD A[HTTP Request] –>|Has uber-trace-id & flags=1| B[Force Sample] A –>|No valid header| C[Probabilistic Sampling] B –> D[Send to Collector] C –> D

4.2 追踪数据关联Metrics与Logs:基于OpenTelemetry Collector构建可观测三角

OpenTelemetry Collector 是实现 traces、metrics、logs 三者语义关联的核心枢纽。其关键在于利用 resourcespan 层级的共用属性(如 service.nametrace_idspan_id)建立跨信号绑定。

数据同步机制

Collector 通过 batch + memory_limiter 确保信号在内存中暂存对齐,再由 otlpexporter 统一输出至后端(如 Jaeger + Prometheus + Loki)。

processors:
  batch:
    timeout: 10s
    send_batch_size: 8192
  # 关键:为 logs 注入 trace_id(若日志中已含 trace_id 字段)
  attributes/logs:
    actions:
      - key: trace_id
        from_attribute: attributes.trace_id  # 从日志字段提取
        action: insert

该配置将日志中解析出的 trace_id 显式注入 resource 属性,使 Loki 可通过 {|trace_id="..."|} 查询关联日志。send_batch_size 控制批处理粒度,避免高频小包导致 backend 关联延迟。

关联能力对比表

信号类型 关联锚点 Collector 处理方式
Traces trace_id 原生携带,无需额外注入
Metrics trace_id(可选) 需通过 metricstransform 添加标签
Logs trace_id 字段 attributes/logs 提取并传播
graph TD
  A[Instrumented App] -->|OTLP/HTTP| B[OTel Collector]
  B --> C{Processor Pipeline}
  C --> D[batch]
  C --> E[attributes/logs]
  C --> F[metricstransform]
  D --> G[Exporters: OTLP/Jaeger/Prometheus/Loki]

4.3 根因分析实战:从Jaeger火焰图定位Go Goroutine阻塞与内存泄漏

火焰图中的异常模式识别

在Jaeger UI中展开服务调用链,重点关注持续高宽(>5s)、顶部平坦或阶梯状堆叠的火焰片段——这往往对应 runtime.gopark 长期挂起,或 runtime.mallocgc 频繁调用。

关键诊断命令

# 采集带goroutine stack的pprof数据
curl "http://localhost:8080/debug/pprof/goroutine?debug=2" > goroutines.txt
curl "http://localhost:8080/debug/pprof/heap" -o heap.pb.gz
  • debug=2 输出完整goroutine栈(含状态、等待对象);
  • heap.pb.gz 是二进制格式,需 go tool pprof heap.pb.gz 可视化分析。

常见阻塞诱因对照表

现象 可能原因 检查点
大量 semacquire channel 写入无接收者 select{ case ch<-v: } 是否漏default
netpollWait 占比高 HTTP长连接未设超时或连接池耗尽 http.Client.TimeoutMaxIdleConns

内存泄漏定位流程

graph TD
    A[Jaeger发现延迟突增] --> B{火焰图聚焦 runtime.mallocgc}
    B --> C[pprof heap --inuse_space]
    C --> D[按 source line 排序,定位高分配函数]
    D --> E[检查是否循环引用/全局map未清理]

4.4 分布式上下文透传增强:跨消息队列(Kafka/RabbitMQ)的TraceID延续方案

在异步消息场景中,TraceID常因生产者未注入、消费者未提取而断裂。需在序列化前注入、反序列化后提取上下文。

消息头注入策略

  • Kafka:使用 Headers(如 trace-id, span-id)携带 OpenTracing 标准字段
  • RabbitMQ:通过 MessageProperties.headers 注入,兼容 Spring AMQP 的 MessagePostProcessor

Kafka 生产端注入示例

ProducerRecord<String, byte[]> record = new ProducerRecord<>("order-topic", orderBytes);
record.headers().add("trace-id", tracer.activeSpan().context().traceIdString().getBytes());
record.headers().add("span-id", tracer.activeSpan().context().spanIdString().getBytes());

逻辑分析:利用 tracer.activeSpan() 获取当前活跃 Span 上下文;traceIdString() 确保十六进制字符串格式(如 "463ac35c9f6413ad48a892ba904d34"),避免二进制序列化歧义;getBytes() 采用 UTF-8 编码,保障跨语言兼容性。

跨队列一致性能力对比

队列 Header 支持 自动传播 Spring Cloud Sleuth 内置支持
Kafka ❌(需手动) ✅(spring-cloud-starter-sleuth + kafka-streams
RabbitMQ ✅(via ChannelInterceptor
graph TD
    A[Service A] -->|1. inject trace-id to headers| B[Kafka Producer]
    B --> C[Kafka Broker]
    C --> D[Kafka Consumer]
    D -->|2. extract & activate span| E[Service B]

第五章:可观测性能力演进与未来展望

从日志聚合到全信号融合的工程实践

某头部在线教育平台在2022年Q3完成可观测性栈升级:将ELK日志系统、Prometheus指标采集与Jaeger链路追踪统一接入OpenTelemetry Collector,通过自定义Exporter将埋点数据按业务域(如“直播课间房”“题库作答流”)打标并路由至不同后端。实际运行中,告警平均定位时长由47分钟压缩至6.3分钟;关键路径P95延迟突增事件的根因识别准确率从58%提升至91%。其核心改造在于将trace_id注入Nginx access日志与MySQL慢查询日志,实现跨组件上下文透传。

基于eBPF的零侵入式深度观测

某金融云厂商在Kubernetes集群中部署Pixie(基于eBPF),无需修改应用代码即捕获HTTP/gRPC请求头、TLS握手耗时、TCP重传率等传统APM无法覆盖的网络层指标。在一次支付网关超时故障中,eBPF探针直接暴露了上游服务TLS证书校验耗时异常(平均2.1s),而应用层指标显示一切正常——该问题源于证书吊销列表(CRL)DNS解析阻塞,最终通过配置OCSP Stapling解决。以下为典型eBPF采集字段示例:

字段名 类型 说明
http_status_code uint16 HTTP响应状态码
tls_handshake_time_ns uint64 TLS握手纳秒级耗时
tcp_retrans_segs uint32 TCP重传段数

可观测性即代码的CI/CD集成

某跨境电商团队将SLO验证嵌入GitOps流水线:每次服务发布前,自动执行以下步骤:

  1. 从Prometheus拉取过去2小时order_submit_success_rate指标(SLI)
  2. 计算当前滚动窗口SLO达标率(目标值99.95%)
  3. 若达标率
  4. 同步生成本次发布的Trace采样策略(如对/api/v2/checkout路径强制100%采样)

该机制上线后,生产环境SLO违规事件同比下降73%,且所有发布变更均附带可追溯的观测基线快照。

# .github/workflows/slo-guard.yml 片段
- name: Validate SLO compliance
  run: |
    curl -s "http://prometheus:9090/api/v1/query?query=100%20-%20avg_over_time(rate(http_request_total{status=~'5..'}[1h]))%20by%20(job)" \
      | jq -r '.data.result[].value[1]' > /tmp/slo_violation_rate
    if (( $(cat /tmp/slo_violation_rate) > 0.05 )); then
      echo "SLO violation detected: $(cat /tmp/slo_violation_rate)%"
      exit 1
    fi

AI驱动的异常模式自发现

某智能客服平台训练LSTM模型分析12类核心指标(含对话响应延迟、ASR识别错误率、意图分类置信度)的时序关联。模型在无监督状态下发现“用户情绪分值骤降→ASR错误率上升→人工转接率激增”的隐性因果链,并自动生成动态告警规则:当情绪分值连续5分钟下降超40%且ASR错误率同步上升时,立即触发语音流质量诊断任务。该机制使客户投诉量下降22%,且诊断报告中87%的根因指向前端麦克风降噪算法失效——此前该问题从未被传统阈值告警捕获。

graph LR
A[原始指标流] --> B[多维时序特征工程]
B --> C[LSTM异常模式挖掘]
C --> D{是否发现新因果链?}
D -->|是| E[生成动态规则]
D -->|否| F[更新基线模型]
E --> G[实时注入Alertmanager]
F --> C

边缘场景下的轻量化可观测性

在工业物联网项目中,某PLC设备仅具备16MB内存与ARM Cortex-M4处理器。团队采用TinyGo编译轻量探针,仅采集3个关键信号:Modbus RTU CRC校验失败次数、串口缓冲区溢出率、心跳包超时占比。所有数据经LZ4压缩后通过MQTT QoS1发送至边缘网关,再批量上传至中心集群。实测探针内存占用稳定在1.2MB,CPU峰值负载

可观测性正从被动响应转向主动免疫,其能力边界持续向硬件层、协议栈底层及AI推理过程渗透。

关注异构系统集成,打通服务之间的最后一公里。

发表回复

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