在现代云原生架构中,可观测性(Observability)是保障服务可靠性的基石。Google Cloud 提供了强大的 Cloud Monitoring 和 Cloud Logging 服务,帮助团队从指标采集、日志分析到告警策略构建完整的运维闭环。本文将从实际生产场景出发,深入讲解如何搭建一套生产级的监控与日志体系,涵盖自定义指标采集、日志结构化与查询优化、告警策略设计、SLO/SLI 管理,以及与 Terraform 的基础设施即代码实践。

一、Cloud Monitoring 核心架构与概念
Cloud Monitoring(前身为 Stackdriver Monitoring)是 GCP 原生的指标监控服务。它采用指标-时间序列-告警的三层模型:指标(Metric)描述了要观测的对象,时间序列(Time Series)记录了指标随时间的变化,告警策略(Alerting Policy)定义了何时触发通知。
1.1 指标类型与资源层级
GCP 的指标体系围绕受监控资源(Monitored Resource)组织。每个指标都绑定到特定的资源类型,如
1 | gce_instance |
、
1 | k8s_container |
、
1 | cloud_function |
等。理解资源层级是构建有效监控的前提:
- 系统指标:GCP 服务自动采集,如 CPU 利用率、请求延迟、错误率
- 自定义指标:用户通过 API 或 OpenTelemetry 上报的业务指标
- 日志指标:基于日志内容提取的派生指标(Distribution 或 Delta 类型)
查看所有可用的指标类型,可以使用 gcloud 命令:
1
2
3
4
5 # 列出所有可用的指标描述符
gcloud monitoring metrics list --filter="metricType=starts_with('custom.')"
# 查看特定指标的详细信息
gcloud monitoring metrics describe compute.googleapis.com/instance/cpu/usage_time
1.2 时间序列数据模型
每条时间序列由以下要素唯一标识:
| 要素 | 说明 | 示例 | ||||
|---|---|---|---|---|---|---|
| 指标类型 | 指标的完整路径 |
|
||||
| 受监控资源 | 资源类型 + 标签 |
+
|
||||
| 指标标签 | 维度切分 |
|
这种多维数据模型允许我们按不同维度聚合和切分,比如按区域、服务版本、HTTP 状态码等维度分析延迟分布。
二、自定义指标采集:从 OpenTelemetry 到 API 直推
系统指标只能覆盖基础设施层面,业务可观测性依赖自定义指标。GCP 提供了两种主要上报方式:OpenTelemetry Collector 集成和直接 API 推送。
2.1 OpenTelemetry Collector 集成
OpenTelemetry 已成为云原生可观测性的事实标准。通过 Google Cloud 的 OTLP Exporter,可以将应用指标无缝推送到 Cloud Monitoring:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 # otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
send_batch_size: 1024
timeout: 5s
resourcedetection:
detectors: [gcp]
exporters:
googlecloud:
metric:
prefix: "custom.googleapis.com/opentelemetry/"
resource_filters:
- prefix: "cloud.resource_id"
project: my-gcp-project
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch, resourcedetection]
exporters: [googlecloud]
在 GKE 中部署 Collector 时,建议使用 Sidecar 模式确保每个 Pod 的指标独立采集,或者使用 DaemonSet 模式集中收集节点级指标。关键配置项包括
1 | send_batch_size |
(控制 API 调用频率)和
1 | resourcedetection |
(自动注入 GCP 资源标签)。
2.2 直接 API 推送自定义指标
对于不支持 OpenTelemetry 的遗留系统或需要精细控制的场景,可以直接使用 Monitoring API 推送指标。首先需要创建指标描述符:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 from google.cloud import monitoring_v3
from google.api import metric_pb2, label_pb2
import time
client = monitoring_v3.MetricServiceClient()
project_name = f"projects/my-gcp-project"
# 创建自定义指标描述符
descriptor = metric_pb2.MetricDescriptor()
descriptor.type = "custom.googleapis.com/payment/transaction_latency"
descriptor.metric_kind = metric_pb2.MetricDescriptor.DISTRIBUTION
descriptor.value_type = metric_pb2.MetricDescriptor.DOUBLE
descriptor.description = "Payment transaction latency distribution"
descriptor.display_name = "Payment Latency"
label = label_pb2.LabelDescriptor()
label.key = "payment_method"
label.value_type = label_pb2.LabelDescriptor.STRING
label.description = "Payment method (credit_card, alipay, wechat_pay)"
descriptor.labels.append(label)
descriptor = client.create_metric_descriptor(
name=project_name, metric_descriptor=descriptor
)
print(f"Created metric descriptor: {descriptor.name}")
指标描述符创建后,即可上报时间序列数据。注意 DISTRIBUTION 类型的指标需要构建
1 | Distribution |
对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 # 上报分布类型指标
from google.api import distribution_pb2
series = monitoring_v3.TimeSeries()
series.metric.type = "custom.googleapis.com/payment/transaction_latency"
series.metric.labels["payment_method"] = "credit_card"
series.resource.type = "gce_instance"
series.resource.labels["instance_id"] = "123456789"
series.resource.labels["zone"] = "asia-east1-a"
point = monitoring_v3.Point()
point.interval.end_time.seconds = int(time.time())
dist = distribution_pb2.Distribution()
dist.mean = 245.5
dist.count = 1000
dist.sum_of_squared_deviation = 1500000.0
dist.bucket_options.explicit.bounds.extend([50, 100, 200, 500, 1000, 2000])
dist.bucket_counts.extend([50, 120, 280, 350, 150, 50, 0])
point.value.distribution_value.CopyFrom(dist)
series.points.append(point)
client.create_time_series(name=project_name, time_series=[series])
最佳实践:使用 DISTRIBUTION 类型而非 GAUGE 记录延迟数据,因为分布指标天然支持百分位数查询(p50、p95、p99),这对 SLO 监控至关重要。
三、Cloud Logging 结构化日志与查询优化
Cloud Logging(前身为 Stackdriver Logging)不仅是日志存储服务,更是日志分析和可观测性的核心组件。在海量日志场景下,结构化日志和高效查询是运维效率的关键。

3.1 结构化日志最佳实践
JSON 格式的结构化日志可以被 Cloud Logging 自动解析为字段,支持精确的字段级查询。以下是 Python 应用的推荐日志格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 import json
import logging
import datetime
class StructuredLogger:
def __init__(self, service_name, version="1.0.0"):
self.service_name = service_name
self.version = version
self.logger = logging.getLogger(service_name)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(message)s'))
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)
def _log(self, level, message, **kwargs):
entry = {
"severity": level,
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
"service": self.service_name,
"version": self.version,
"message": message,
**kwargs
}
self.logger.log(getattr(logging, level), json.dumps(entry))
def info(self, message, **kwargs):
self._log("INFO", message, **kwargs)
def error(self, message, **kwargs):
self._log("ERROR", message, **kwargs)
def request_log(self, method, path, status_code, latency_ms,
user_id=None, trace_id=None):
self._log("INFO", f"{method} {path} {status_code}",
http_request={
"request_method": method,
"request_path": path,
"status": status_code,
"latency": f"{latency_ms}ms"
},
user_id=user_id,
trace_id=trace_id
)
# 使用示例
logger = StructuredLogger("payment-service", version="2.3.1")
logger.request_log("POST", "/api/v2/charge", 200, 145.3,
user_id="u_8x9a2b", trace_id="trace_abc123")
logger.error("Database connection pool exhausted",
db_host="db-primary", pool_size=50, active=50, waiting=23)
关键设计要点:
- http_request 字段:使用 Cloud Logging 的保留字段名,可被自动识别为 HTTP 请求日志
- trace_id 字段:与 Cloud Trace 集成,实现日志与链路追踪的关联
- severity 字段:使用 Cloud Logging 标准的 severity 级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)
- 避免嵌套过深:查询时深层嵌套字段语法繁琐,建议将关键字段平铺在顶层
3.2 高效日志查询语法
Cloud Logging 使用 Lucene 风格的查询语言,支持字段精确匹配、正则表达式和范围查询。以下是生产环境常用的查询模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 # 查找支付服务最近1小时的错误日志
severity>=ERROR
resource.type="gce_instance"
jsonPayload.service="payment-service"
timestamp>="2026-08-06T00:00:00Z"
# 按 HTTP 状态码过滤
jsonPayload.http_request.status>=500
jsonPayload.http_request.status<600
# 按追踪ID关联查找
jsonPayload.trace_id="trace_abc123"
# 正则匹配错误模式
jsonPayload.message=~"connection.*timeout|pool.*exhausted"
# 聚合查询:统计每个错误码的出现次数
# 使用 Log Analytics (BigQuery SQL)
SELECT
jsonPayload.http_request.status AS status_code,
COUNT(*) AS error_count
FROM `my-project.logging_analytics._Default`
WHERE severity >= "ERROR"
AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
GROUP BY status_code
ORDER BY error_count DESC
3.3 日志路由与长期存储
Cloud Logging 默认保留 30 天日志。对于合规审计或长期分析需求,需要配置日志接收器(Sink)将日志导出到 Cloud Storage 或 BigQuery:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 # Terraform: 日志路由到 BigQuery 用于长期分析
resource "google_logging_project_sink" "bigquery_sink" {
name = "prod-logs-to-bigquery"
destination = "bigquery.googleapis.com/projects/my-project/datasets/logging_analytics"
filter = <<EOF
severity >= WARNING
resource.type = ("gce_instance" OR "k8s_container")
EOF
# 使用 BigQuery 分区表优化查询成本
bigquery_options {
use_partitioned_tables = true
}
unique_writer_identity = true
}
# 授予 Sink 服务账号 BigQuery 写入权限
resource "google_project_iam_binding" "bigquery_writer" {
role = "roles/bigquery.dataEditor"
members = [
google_logging_project_sink.bigquery_sink.writer_identity
]
}
四、告警策略设计:从阈值到多条件组合
告警策略的质量直接决定了 On-Call 工程师的生活质量。一个好的告警系统应该具有高信噪比——真故障立即触发,正常波动绝不误报。
4.1 告警策略的黄金法则
在设计告警策略之前,请牢记以下原则:
- 基于症状告警:告警用户可感知的问题(错误率上升、延迟增加),而非根因(CPU 高、内存不足)。CPU 高本身不是问题,只有当它导致服务降级时才需要告警
- 设置合理的窗口:单次异常不告警,使用滑动窗口(如”5 分钟内持续”)过滤噪声
- 多条件组合:组合多个指标(如错误率 > 1% 且 请求量 > 100/s)降低误报
- 分级通知:P0 级立即电话/PagerDuty,P1 级 Slack 通知,P2 级仅记录工单
4.2 Terraform 管理告警策略
以下是一个生产级的告警策略配置,监控 HTTP 服务的错误率和延迟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 # 错误率告警
resource "google_monitoring_alert_policy" "high_error_rate" {
display_name = "High Error Rate - Payment Service"
combiner = "AND"
enabled = true
conditions {
display_name = "Error rate exceeds 1% for 5 minutes"
condition_threshold {
filter = <<-EOF
resource.type="gce_instance"
AND metric.type="loadbalancing.googleapis.com/https/request_count"
AND resource.label."url_map_name"="payment-lb"
EOF
duration = "300s" # 持续5分钟
comparison = "COMPARISON_GT"
# 计算错误率:5xx 占总请求的比例
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
group_by_fields = ["resource.label.url_map_name"]
}
threshold_value = 0.01 # 1%
}
}
conditions {
display_name = "Request volume above minimum threshold"
condition_threshold {
filter = <<-EOF
resource.type="gce_instance"
AND metric.type="loadbalancing.googleapis.com/https/request_count"
AND resource.label."url_map_name"="payment-lb"
EOF
duration = "300s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
}
threshold_value = 100 # 最少100 req/s,避免低流量误报
}
}
notification_channels = [
google_monitoring_notification_channel.pagerduty.id,
google_monitoring_notification_channel.slack.id
]
documentation {
content = <<-DOC
## 故障排查步骤
1. 查看 Logging: `severity>=ERROR jsonPayload.service="payment-service"`
2. 检查最近部署: `gcloud run revisions list --service=payment-service`
3. 检查数据库连接池状态
4. 联系 On-Call: @payment-team-oncall
DOC
mime_type = "text/markdown"
}
}
# 通知渠道:Slack
resource "google_monitoring_notification_channel" "slack" {
display_name = "Payment Team Slack"
type = "slack"
labels = {
channel_name = "#payment-alerts"
}
sensitive_labels {
auth_token = var.slack_auth_token
}
}
4.3 MQL 高级告警查询
对于复杂的监控需求,Monitoring Query Language(MQL)提供了比标准过滤器更强大的表达力。例如,计算 p99 延迟的同比环比变化:
1
2
3
4
5
6
7
8
9 # MQL: 当 p99 延迟比上周同期增长 50% 以上时告警
fetch https_lb_rule
| metric 'loadbalancing.googleapis.com/https/total_latencies'
| filter metric.response_code_class = '2xx'
| align delta(5m)
| group_by [resource.url_map_name],
percentile(value, 99)
| condition val() > prev(val(), 7d) * 1.5 [AND]
val() > 500 # 且绝对值超过 500ms
五、SLO/SLI 管理:用错误预算驱动可靠性决策
SLO(Service Level Objective)是可观测性的终极目标——它将运维从被动响应转变为主动管理。Cloud Monitoring 原生支持 SLO 监控,配合错误预算(Error Budget)可以科学地平衡可靠性与迭代速度。

5.1 定义 SLI 指标
SLI(Service Level Indicator)是衡量服务水平的具体指标。常见的 SLI 类型有两种:
- 可用性 SLI:成功请求 / 总请求
- 延迟 SLI:满足延迟阈值的请求 / 总请求
使用 Terraform 创建 SLO:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 # 支付服务可用性 SLO: 99.9% (月度错误预算 ~43分钟)
resource "google_monitoring_slo" "payment_availability" {
service = google_monitoring_service.payment.service_id
slo_id = "payment-availability-slo"
display_name = "Payment Service Availability - 99.9%"
goal = 0.999
rolling_period_days = 30
basic_sli {
availability {
enabled = true
}
}
}
# 支付服务延迟 SLO: 99% 的请求在 500ms 内完成
resource "google_monitoring_slo" "payment_latency" {
service = google_monitoring_service.payment.service_id
slo_id = "payment-latency-slo"
display_name = "Payment Service Latency - p99 < 500ms"
goal = 0.99
rolling_period_days = 30
request_based_sli {
good_total_ratio {
good_service_filter = join(" AND ", [
"resource.type="gce_instance"",
"metric.type="loadbalancing.googleapis.com/https/total_latencies"",
"metric.response_code_class = "2xx"",
])
total_service_filter = join(" AND ", [
"resource.type="gce_instance"",
"metric.type="loadbalancing.googleapis.com/https/total_latencies"",
])
}
}
}
5.2 错误预算告警
当错误预算消耗过快时,应该触发预警。Cloud Monitoring 支持基于 SLO 的告警策略——在错误预算消耗达到特定阈值时通知团队:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 # 错误预算消耗速率告警
resource "google_monitoring_alert_policy" "error_budget_burn_rate" {
display_name = "Payment SLO - Error Budget Burning Too Fast"
combiner = "OR"
enabled = true
conditions {
display_name = "Error budget burn rate exceeds 14.4x (will exhaust in < 2 hours)"
condition_monitoring_query_language {
query = <<-MQL
fetch cloud_monitoring_slo
| metric 'monitoring.googleapis.com/slo/error_budget_burn_rate'
| filter resource.slo_id = '${google_monitoring_slo.payment_availability.slo_id}'
| value(val() > 14.4)
MQL
duration = "600s"
}
}
notification_channels = [
google_monitoring_notification_channel.pagerduty.id
]
documentation {
content = "支付服务 SLO 错误预算消耗速率异常,预计 2 小时内耗尽。请立即排查。"
}
}
常用的错误预算告警速率阈值:
| 燃烧速率 | 含义 | 建议操作 |
|---|---|---|
| 1x | 30 天内恰好耗尽 | 无需操作,正常消耗 |
| 6x | 5 天内耗尽 | Slack 通知,安排排查 |
| 14.4x | 2 天内耗尽 | PagerDuty 告警,优先处理 |
| 43.2x | 6 小时内耗尽 | 紧急响应,可能需要回滚 |
六、Dashboard 构建与信息辐射
好的 Dashboard 是团队共享运维状态的信息辐射器。Cloud Monitoring Dashboard API 允许通过代码定义和部署仪表盘:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 # Terraform: 生产级监控仪表盘
resource "google_monitoring_dashboard" "payment_service" {
dashboard_json = jsonencode({
displayName = "Payment Service - Production"
mosaicLayout = {
tiles = [
# 错误率折线图
{
width = 6
height = 4
widget = {
title = "Error Rate by Endpoint"
xyChart = {
dataSets = [{
timeSeriesQuery = {
timeSeriesFilter = {
filter = join(" AND ", [
"resource.type="gce_instance"",
"metric.type="loadbalancing.googleapis.com/https/request_count"",
"metric.response_code_class!="2xx""
])
aggregation = {
alignmentPeriod = "60s"
perSeriesAligner = "ALIGN_RATE"
groupByFields = ["metric.response_code_class"]
}
}
}
}]
}
}
},
# 延迟热力图
{
width = 6
height = 4
widget = {
title = "Request Latency Heatmap"
xyChart = {
dataSets = [{
timeSeriesQuery = {
timeSeriesFilter = {
filter = join(" AND ", [
"resource.type="gce_instance"",
"metric.type="loadbalancing.googleapis.com/https/total_latencies""
])
aggregation = {
alignmentPeriod = "60s"
perSeriesAligner = "ALIGN_DELTA"
}
}
}
plotType = "HEATMAP"
}]
}
}
}
]
}
})
}
七、成本优化与最佳实践总结
监控和日志本身也可能成为成本黑洞。以下是控制成本的关键策略:
- 日志采样:对高吞吐量、低价值的日志(如健康检查)在应用层做采样,仅记录 1%-10%
- 排除过滤器:使用日志接收器的排除过滤器在入口处丢弃不需要的日志,避免写入计费
- BigQuery 分区:导出到 BigQuery 时使用分区表和聚簇表,查询时始终带时间范围条件
- 自定义指标降采样:在本地聚合后再上报,减少 API 调用次数
- SLO 精简:只为关键服务定义 SLO,每个服务不超过 2-3 个 SLO
1
2
3
4
5
6
7
8
9
10 # 日志排除过滤器:丢弃健康检查日志
resource "google_logging_project_exclusion" "health_check" {
name = "exclude-health-checks"
description = "Exclude load balancer health check logs"
filter = <<-EOF
resource.type="http_load_balancer"
jsonPayload.request_path="/healthz"
severity="INFO"
EOF
}
生产环境检查清单
在将监控体系推向生产之前,请确认以下事项:
- 所有关键服务已配置结构化日志输出
- 自定义指标使用 Distribution 类型记录延迟
- 告警策略包含多条件组合,避免单指标误报
- 错误预算告警已启用(6x 和 14.4x 两级)
- 日志接收器已配置 BigQuery 长期存储
- 排除过滤器已配置,减少无效日志写入
- Dashboard 已部署,团队可快速查看服务健康状态
- 所有监控配置使用 Terraform 管理,纳入 GitOps 流程
Cloud Monitoring 和 Cloud Logging 的组合为 Google Cloud 用户提供了从指标采集到告警响应的完整可观测性方案。通过结构化日志、自定义指标、SLO 管理和基础设施即代码实践,团队可以构建一套既全面又经济的监控体系。记住,监控的目标不是收集尽可能多的数据,而是在故障发生时快速定位问题、在故障发生前提前预警——质量永远胜过数量。
汤不热吧