第一章:Go语言沟通群运维告警失灵现象剖析
近期多个使用 Prometheus + Alertmanager + DingTalk 企业微信机器人链路的 Go 语言技术群反馈:关键服务宕机后,预期告警未触达群聊。经排查,问题并非源于监控采集失效,而是告警“抵达终点前悄然静默”。
告警路径中的 HTTP 中间件劫持
部分团队在 Alertmanager 的反向代理层(如 Nginx 或自研 Go 网关)中启用了 JSON 日志中间件,该中间件对 Content-Type: application/json 请求强制校验 Content-Length。而 Alertmanager v0.25+ 默认启用流式 JSON 编码(chunked transfer-encoding),导致无 Content-Length 头。中间件误判为非法请求,直接返回 400 Bad Request 并丢弃告警,但 Alertmanager 日志仅记录 sent to receiver,未暴露实际 HTTP 层失败。
验证方式:
# 拦截 Alertmanager 发往网关的请求(需提前配置 -web.external-url)
curl -v -X POST http://your-gateway/alert/dingtalk \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"test"}}'
# 若返回 400 且无 Content-Length,即为该问题
DingTalk 机器人签名过期未刷新
DingTalk 机器人启用“加签”后,timestamp 和 sign 参数需每小时动态生成。若运维脚本硬编码了静态签名(常见于早期 Shell 脚本集成),超时后钉钉服务端拒绝接收,返回 {"errcode":310000,"errmsg":"invalid signature"},但 Alertmanager 默认不解析响应体,仅记录 status=200(因 HTTP 状态码确为 200)。
修复步骤:
- 在 Alertmanager 配置中移除静态
sign参数; - 使用
webhook_configs的http_config启用authorization或改用支持动态签名的dingtalk_configs(v0.27+ 原生支持); - 或部署轻量签名服务,通过
url: http://sign-svc/v1/sign?timestamp={{ now.Unix }}动态注入。
告警抑制规则意外生效
以下抑制配置常被忽略其全局影响:
| 条件 | 效果 |
|---|---|
source_matchers: {alertname="HighCPU"}<br>target_matchers: {job="api-server"} |
抑制所有 job="api-server" 下的 HighCPU 告警 |
equal: [cluster, namespace] |
若 cluster 标签缺失,整条抑制规则失效,可能漏抑 |
建议定期执行:
# 检查活跃抑制规则是否匹配当前告警
curl -s 'http://alertmanager/api/v2/alerts?silenced=false' | jq '.[] | select(.labels.alertname=="HighCPU") | .labels'
第二章:SLI指标体系设计与go-kit服务埋点实践
2.1 群健康度核心SLI定义:消息延迟、成员活跃率、机器人响应成功率、群消息吞吐量、告警触达率
群健康度需通过可观测性驱动的SLI量化。五大核心指标构成闭环评估体系:
- 消息延迟:端到端P95延迟 ≤ 800ms(含序列化、路由、投递、渲染)
- 成员活跃率:7日内发送/接收≥1条消息的成员占比,剔除静默BOT账号
- 机器人响应成功率:HTTP 2xx + 业务态
{"code":0}双校验,排除超时重试流量 - 群消息吞吐量:单位时间(分钟)内成功投递的非系统消息数,按群维度聚合
- 告警触达率:从告警触发到用户终端弹窗/震动的完成率,依赖设备在线状态回传
# SLI计算伪代码(以机器人响应成功率为例)
def calc_bot_success_rate(window="5m"):
# 过滤:仅统计主动请求(非重试)、非心跳、非debug环境
success = count("bot_resp_code{code='0',retry='false',env!='dev'}")
total = count("bot_request_total{type='cmd',env!='dev'}")
return success / max(total, 1) # 防除零
该逻辑确保仅衡量真实业务意图的成功闭环,retry='false' 排除网络抖动干扰,env!='dev' 避免测试流量污染生产SLI。
| 指标 | 采集粒度 | 告警阈值 | 数据源 |
|---|---|---|---|
| 消息延迟 | 每条消息trace_id | P95 > 1200ms | OpenTelemetry Jaeger |
| 成员活跃率 | 每日快照 | 用户行为事件流 |
graph TD
A[群消息入队] --> B{延迟≤800ms?}
B -->|Yes| C[计入吞吐量]
B -->|No| D[归入延迟异常桶]
C --> E[成员读取事件]
E --> F[活跃率更新]
2.2 基于go-kit Endpoint Middleware实现请求级指标自动采集与上下文透传
在 go-kit 架构中,Endpoint 是核心抽象单元。通过在 Endpoint 层注入 Middleware,可无侵入地完成请求级可观测性增强。
指标采集 Middleware 实现
func MetricsMiddleware(counter *prometheus.CounterVec, hist *prometheus.HistogramVec) endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
start := time.Now()
defer func() {
status := "success"
if err != nil { status = "error" }
counter.WithLabelValues(status).Inc()
hist.WithLabelValues(status).Observe(time.Since(start).Seconds())
}()
return next(ctx, request)
}
}
}
该 Middleware 利用 context.Context 生命周期钩子,在调用前后自动记录 Prometheus 指标:counter 统计成功/失败次数,hist 记录耗时分布;status 标签实现错误分类,WithLabelValues 动态绑定维度。
上下文透传机制
- 自动将 trace ID、request ID 注入
ctx - 支持跨服务链路串联(需配合 OpenTracing 或 OTel)
- 与日志中间件共享
ctx.Value()键空间
| 组件 | 透传字段 | 用途 |
|---|---|---|
| HTTP Transport | X-Request-ID | 请求唯一标识 |
| gRPC Interceptor | grpc_ctxtags | 结构化日志上下文 |
| Endpoint MW | ctx.Value(key) | 中间件间状态共享 |
graph TD
A[HTTP Handler] --> B[Transport Decode]
B --> C[Endpoint Middleware Chain]
C --> D[Metrics MW]
D --> E[Tracing MW]
E --> F[Business Endpoint]
2.3 使用go-kit Transport层拦截器捕获HTTP/gRPC调用链路中的异常与超时事件
go-kit 的 Transport 层拦截器(如 http.ServerBefore、grpc.ServerRequestFunc)是观测调用链路的第一道防线,可在请求解码前/响应编码后统一注入可观测逻辑。
异常与超时的统一捕获点
- HTTP:在
http.ServerErrorEncoder中识别context.DeadlineExceeded或自定义错误类型 - gRPC:通过
grpc.ServerRequestFunc检查ctx.Err()并映射为codes.DeadlineExceeded
超时事件拦截示例(HTTP Server)
func timeoutInterceptor() http.ServerRequestFunc {
return func(ctx context.Context, r *http.Request) context.Context {
// 提前检查上下文是否已超时(如反向代理透传 Deadline)
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
metrics.TimeoutCounter.WithLabelValues("http").Inc()
}
return ctx
}
}
该拦截器在请求路由前执行,ctx.Err() 可直接反映网关或客户端设置的 timeout;metrics.TimeoutCounter 是 Prometheus 计数器,按 transport 类型打标。
异常分类统计表
| 错误类型 | HTTP 状态码 | gRPC Code | 触发时机 |
|---|---|---|---|
context.DeadlineExceeded |
408 | codes.DeadlineExceeded |
请求未完成即超时 |
ErrBadRequest |
400 | codes.InvalidArgument |
解码失败前主动注入 |
链路事件流转示意
graph TD
A[HTTP/gRPC 请求] --> B[Transport 拦截器]
B --> C{ctx.Err() == DeadlineExceeded?}
C -->|是| D[记录超时指标 + 日志]
C -->|否| E{error != nil?}
E -->|是| F[归类异常类型并上报]
2.4 群维度标识注入:通过GroupID Context Value + Prometheus Labels实现多租户指标隔离
在微服务多租户场景中,原始指标(如 http_request_duration_seconds)缺乏租户上下文,导致聚合混乱。核心解法是将运行时 GroupID 从请求链路透传至指标采集层,并映射为 Prometheus 原生 label。
数据同步机制
通过 OpenTelemetry SDK 在 Span Context 中注入 group_id,并在指标 exporter 中自动提取并附加为 group_id label:
# prometheus.yml 片段:确保 label 可被识别与分片
global:
external_labels:
cluster: "prod-east"
scrape_configs:
- job_name: 'service-metrics'
static_configs:
- targets: ['app1:9090']
metric_relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_group_id] # 来自 Pod Label
target_label: group_id
✅
__meta_kubernetes_pod_label_group_id由 Operator 自动注入 Pod,与服务实例生命周期一致;target_label: group_id使所有 scraped 指标天然携带租户维度,支持sum by(group_id)(rate(http_request_total[5m]))精确切分。
标签治理策略
| Label 名称 | 来源 | 是否必需 | 说明 |
|---|---|---|---|
group_id |
ContextValue / Pod | 是 | 租户唯一标识,不可为空 |
env |
Service Env Var | 否 | 用于环境级下钻 |
svc |
Instrumentation | 是 | 服务名,保障基础可追溯性 |
graph TD
A[HTTP Request] --> B[OpenTelemetry Tracer]
B --> C[ContextValue.put group_id=“tenant-a”]
C --> D[Metrics Exporter]
D --> E[Prometheus scrape]
E --> F[Label: group_id=“tenant-a”]
2.5 指标生命周期管理:动态注册/注销群实例指标,避免内存泄漏与Cardinality爆炸
核心挑战
高动态微服务场景下,集群节点频繁扩缩容,若指标静态注册或未及时注销,将导致:
Gauge/Counter实例持续累积,引发 JVM 堆内存泄漏- 标签组合(如
instance_id="i-abc123",shard="s1")呈指数级增长,触发 Prometheus Cardinality 爆炸
动态注册/注销契约
需严格遵循「创建即注册、销毁即注销」双阶段协议:
// 注册:绑定生命周期钩子
Gauge.builder("jvm.memory.used.bytes", memoryMeter, m -> m.getUsed())
.tag("instance_id", instanceId)
.register(meterRegistry); // ✅ 绑定到当前 MeterRegistry
// 注销:显式移除(非 GC 可自动回收!)
meterRegistry.remove("jvm.memory.used.bytes",
Tags.of("instance_id", instanceId)); // ✅ 必须传入完全匹配的 tag 集合
逻辑分析:
remove()要求name + tags全等匹配;若仅传instance_id而原始注册含shard标签,则注销失败,残留指标。参数meterRegistry是全局指标注册中心,所有注销操作必须作用于同一实例。
安全注销流程(mermaid)
graph TD
A[实例准备销毁] --> B{是否已调用 unregister?}
B -- 否 --> C[执行 meterRegistry.remove(name, tags)]
B -- 是 --> D[跳过]
C --> E[确认 metrics.size() 下降]
E --> F[释放实例资源]
第三章:Prometheus多维数据建模与实时评分引擎构建
3.1 基于Histogram与Gauge组合建模群健康度五维SLI时序数据
为精准刻画集群健康度,我们定义五维SLI:延迟(p95)、错误率、吞吐量、资源饱和度、服务可用性。其中延迟与吞吐量采用Histogram捕获分布特征,其余三者使用Gauge实时反映瞬时状态。
数据模型设计
cluster_sli_latency_seconds(Histogram):按cluster,service,endpoint,method,region五标签打点cluster_sli_error_ratio(Gauge):归一化浮点值,范围[0.0, 1.0]cluster_sli_cpu_saturation(Gauge):当前CPU使用率 / 预留上限
核心采集逻辑(Prometheus Client Python)
from prometheus_client import Histogram, Gauge
# Histogram:延迟分布(桶边界自适应业务RTT)
latency_hist = Histogram(
'cluster_sli_latency_seconds',
'P95 latency per request',
['cluster', 'service', 'endpoint', 'method', 'region'],
buckets=(0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0)
)
# Gauge:错误率(需外部计算后set)
error_gauge = Gauge(
'cluster_sli_error_ratio',
'Error ratio in last minute',
['cluster', 'service', 'endpoint']
)
逻辑分析:
buckets参数显式声明分位统计粒度,避免动态桶导致TSDB cardinality爆炸;error_gauge不自动采集,由告警聚合模块每60s计算并set(),确保SLI语义严格对齐SLO窗口。
五维标签组合示例
| cluster | service | endpoint | method | region | value_type |
|---|---|---|---|---|---|
| prod-us | api-gw | /v1/users | POST | us-west | Histogram |
| prod-us | auth-svc | /token | GET | us-east | Gauge |
graph TD
A[原始指标流] --> B{按维度分流}
B --> C[Histogram路径:延迟/吞吐量]
B --> D[Gauge路径:错误率/饱和度/可用性]
C --> E[Prometheus TSDB]
D --> E
3.2 使用PromQL编写群健康度加权评分表达式(含滑动窗口归一化与异常衰减因子)
群健康度需融合多维度指标,避免单点失效导致误判。核心思路:对 up, http_request_duration_seconds_bucket, process_cpu_seconds_total 等信号加权聚合,并引入时间敏感性。
滑动窗口归一化
# 过去5分钟内各实例可用率(0~1)归一化
avg_over_time(up[5m]) / on(instance) group_left() count_over_time(up[5m])
逻辑:
avg_over_time(up[5m])给出实例存活率均值;count_over_time(up[5m])提供采样总数,相除消除采样密度偏差,确保跨集群可比。
异常衰减因子设计
| 指标类型 | 衰减权重 | 触发条件 |
|---|---|---|
up == 0 |
×0.1 | 实例宕机,快速降权 |
rate(http_requests_total[5m]) < 1 |
×0.3 | 流量骤降,疑似服务失活 |
histogram_quantile(0.99, ...) > 2s |
×0.5 | 响应延迟超标,部分降权 |
加权评分主表达式
(
0.4 * avg_over_time(up[5m])
+ 0.3 * (1 - histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])))
+ 0.3 * clamp_min(rate(http_requests_total[5m]), 0.01)
) * (
1 - (1 - avg_over_time(up[5m])) * 0.9 # 异常衰减项:宕机则整体×0.1
)
该表达式输出
[0, 1]区间连续分值,支持告警阈值动态校准与看板热力映射。
3.3 实时评分结果导出为Summary指标并同步至Alertmanager触发分级告警
数据同步机制
实时评分服务(如 Prometheus Exporter)将每秒生成的 anomaly_score 指标以 Summary 类型暴露:
# HELP anomaly_score_summary Anomaly severity summary (0.0–1.0)
# TYPE anomaly_score_summary summary
anomaly_score_summary{quantile="0.5"} 0.32
anomaly_score_summary{quantile="0.9"} 0.78
anomaly_score_summary{quantile="0.99"} 0.94
anomaly_score_summary_sum 1245.6
anomaly_score_summary_count 1580
逻辑分析:Summary 类型自动聚合分位数与总量,避免高基数标签爆炸;
_sum/_count支持计算平均分(sum/count),为告警阈值提供统计基线。
分级告警策略
| 级别 | 触发条件 | Alertmanager Route Label |
|---|---|---|
| P3 | avg_over_time(anomaly_score_summary{quantile="0.9"}[5m]) > 0.5 |
severity="warning" |
| P1 | anomaly_score_summary{quantile="0.99"} > 0.9 |
severity="critical" |
同步流程
graph TD
A[Exporter 输出 Summary] --> B[Prometheus 抓取]
B --> C[PromQL 计算分级表达式]
C --> D[Alertmanager 接收告警]
D --> E[按 severity 路由至 Slack/PagerDuty]
第四章:可视化看板与智能运维闭环落地
4.1 Grafana看板设计:群健康度热力图、SLI趋势对比矩阵、TOP-N异常群下钻分析
群健康度热力图
基于 Prometheus 指标 group_health_score{group_id, region} 构建二维热力图,横轴为集群分组(group_id),纵轴为地域(region),颜色深浅映射 0–100 健康分。
# 热力图数据源查询(Grafana Heatmap Panel)
avg by (group_id, region) (
histogram_quantile(0.95, sum(rate(group_health_bucket[1h])) by (le, group_id, region))
)
逻辑说明:使用直方图分位数聚合近1小时健康指标分布;
le标签确保桶边界对齐;avg by实现跨时间降维,适配热力图坐标系。
SLI趋势对比矩阵
采用 Compare 视图叠加 3 类 SLI(可用性/延迟/错误率),按周同比着色。关键字段需统一标签 sliset="prod" 以支持矩阵自动分组。
| SLI类型 | 查询表达式示例 | 告警阈值 |
|---|---|---|
| 可用性 | 1 - rate(http_requests_total{code=~"5.."}[1h]) |
|
| P95延迟 | histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[1h])) by (le)) |
> 800ms |
TOP-N异常群下钻分析
点击热力图高危单元格,跳转至动态仪表盘,自动注入 var-group_id 和 var-region,触发以下下钻链路:
graph TD
A[热力图点击] --> B[URL参数注入]
B --> C[加载group_id专属PromQL]
C --> D[关联TraceID采样]
D --> E[展示Top 5慢请求链路]
核心能力依赖 Grafana 9+ 的 Template Variable Auto-refresh 与 Linked Dashboards 联动机制。
4.2 基于Webhook的群健康度变更通知:集成企业微信/钉钉机器人推送结构化诊断报告
当群健康度指标(如消息衰减率、成员沉默比、会话中断频次)触发阈值时,系统通过 Webhook 主动推送 JSON 格式诊断报告至企业微信或钉钉机器人。
推送数据结构
{
"msgtype": "markdown",
"markdown": {
"content": "### 📊 群健康度告警\n- **群ID**: `grp_7a2f`\n- **健康分**: `62`(↓15%)\n- **根因**: 消息响应延迟 > 300s(占比78%)"
}
}
该结构兼容双平台解析逻辑;content 字段支持 Markdown 子集,确保关键指标高亮可读。
平台适配差异
| 字段 | 企业微信 | 钉钉 |
|---|---|---|
| 请求方法 | POST | POST |
| Content-Type | application/json |
application/json |
| 签名机制 | timestamp+secret |
timestamp+sign |
事件触发流程
graph TD
A[健康度计算引擎] -->|delta > 5%| B{Webhook 路由器}
B --> C[企业微信适配器]
B --> D[钉钉适配器]
C --> E[加密签名 & 发送]
D --> E
4.3 运维干预反馈通道:通过/go-kit-admin API提交人工校准标记,反哺评分模型迭代
运维人员在发现模型误判(如将正常请求标记为异常)时,可通过统一管理端点实时注入校准信号:
curl -X POST "https://api.example.com/go-kit-admin/v1/feedback" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"trace_id": "a1b2c3d4",
"label": "false_positive",
"reason": "backend_latency_under_200ms",
"operator": "ops-lee",
"timestamp": "2024-06-15T09:22:31Z"
}'
该请求携带完整上下文:trace_id 关联原始调用链,label 定义校准类型(false_positive/false_negative/ambiguous),reason 提供结构化归因标签,供后续特征工程复用。
数据同步机制
反馈数据经 Kafka 持久化后,由离线管道按小时切片写入特征仓库,触发模型重训练任务。
校准类型语义表
| 标签类型 | 含义 | 触发模型动作 |
|---|---|---|
false_positive |
模型误判正常行为为异常 | 降低对应特征权重 |
false_negative |
模型漏判真实异常 | 增强时序突变敏感度 |
ambiguous |
边界案例需人工复核 | 进入主动学习候选池 |
graph TD
A[运维终端] -->|HTTP POST| B[/go-kit-admin/v1/feedback/]
B --> C{鉴权 & 校验}
C -->|通过| D[Kafka Topic: feedback-raw]
D --> E[流处理:去重/补全/打标]
E --> F[特征仓库 → 模型训练 Pipeline]
4.4 多环境灰度发布机制:基于Prometheus Service Discovery动态加载群配置与评分策略
灰度发布需实时感知服务拓扑变化,避免静态配置导致的策略滞后。本机制依托 Prometheus 的 file_sd 与自定义 discovery.reloader 实现配置热加载。
动态配置注入示例
# /etc/prometheus/file-sd/groups.yaml
- targets: ['10.1.2.100:8080', '10.1.2.101:8080']
labels:
env: staging
group: api-v2
score_policy: latency_95th_weighted
该文件由 CI/CD 流水线按环境自动渲染,prometheus.yml 中声明 file_sd_configs 后,Prometheus 每30s轮询变更并触发服务发现重载。
评分策略映射表
| 策略标识 | 权重维度 | 触发阈值 |
|---|---|---|
latency_95th_weighted |
P95延迟 × 实例QPS | > 200ms |
error_rate_fallback |
5分钟错误率 | > 0.5% |
执行流程
graph TD
A[CI推送新group.yaml] --> B[Reloader监听文件变更]
B --> C[触发Prometheus SD重载]
C --> D[Operator拉取最新label集]
D --> E[动态绑定评分器实例]
核心优势在于解耦发布节奏与配置生命周期,使灰度权重计算始终基于真实、实时的服务元数据。
第五章:总结与展望
技术栈演进的实际影响
在某大型电商平台的微服务重构项目中,团队将原有单体架构迁移至基于 Kubernetes 的云原生体系。迁移后,平均部署耗时从 47 分钟缩短至 92 秒,CI/CD 流水线失败率下降 63%。关键变化在于:
- 使用 Helm Chart 统一管理 87 个服务的发布配置
- 引入 OpenTelemetry 实现全链路追踪,定位一次支付超时问题的时间从平均 6.5 小时压缩至 11 分钟
- Istio 网关策略使灰度发布成功率稳定在 99.98%,近半年无因发布引发的 P0 故障
生产环境中的可观测性实践
以下为某金融风控系统在 Prometheus + Grafana 中落地的核心指标看板配置片段:
- name: "risk-service-alerts"
rules:
- alert: HighLatencyRiskCheck
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="risk-api"}[5m])) by (le)) > 1.2
for: 3m
labels:
severity: critical
该规则上线后,成功在用户投诉前 4.2 分钟自动触发告警,并联动 PagerDuty 启动 SRE 响应流程。过去三个月内,共拦截 17 起潜在服务降级事件。
多云架构下的成本优化成果
某政务云平台采用混合云策略(阿里云+本地数据中心),通过 Crossplane 统一编排资源后,实现以下量化收益:
| 维度 | 迁移前 | 迁移后 | 降幅 |
|---|---|---|---|
| 月度计算资源成本 | ¥1,284,600 | ¥792,300 | 38.3% |
| 跨云数据同步延迟 | 842ms(峰值) | 47ms(P99) | 94.4% |
| 容灾切换耗时 | 22 分钟 | 87 秒 | 93.5% |
核心手段包括:基于 Karpenter 的弹性节点池自动扩缩、S3 兼容对象存储的跨云元数据同步、以及使用 Velero 实现跨集群应用状态一致性备份。
AI 辅助运维的落地场景
在某运营商核心网管系统中,集成 Llama-3-8B 微调模型用于日志根因分析。模型在真实生产日志样本(含 12.7TB 历史告警日志+拓扑关系图谱)上训练后,对“基站退服连锁反应”类复杂故障的归因准确率达 89.6%,较传统规则引擎提升 41.2 个百分点。实际运行中,模型输出直接嵌入 Grafana 面板的“智能诊断”Tab,支持一键生成修复命令并推送至 Ansible Tower 执行队列。
开源社区协作模式转变
团队参与 CNCF 孵化项目 Thanos 的贡献已覆盖 3 个版本:
- v0.31:提交
query-frontend并发限流补丁(PR #6241),解决高负载下 OOM 频发问题 - v0.32:主导设计多租户配额控制 API(RFC-029),被采纳为 v0.33 正式特性
- v0.33:维护中国区文档本地化分支,同步更新 142 个 YAML 示例与中文注释
当前社区中,该团队成员担任 SIG-Storage 的 Maintainer,负责审核所有对象存储适配器相关 PR。
安全左移的工程化验证
在某医疗 SaaS 产品中,将 Trivy + Syft 集成至 GitLab CI,对每个 MR 自动扫描容器镜像与 SBOM 清单。上线 6 个月后,CVE-2023-27997 类高危漏洞的平均修复周期从 18.4 天缩短至 3.2 小时,且 100% 的生产镜像均通过 CIS Docker Benchmark v1.4.0 全项检测。关键改进点在于构建阶段即注入 --security-opt=no-new-privileges 和只读 /tmp 挂载策略。
