Links#
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/available-metrics.html
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html
https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/1. Alert Standard#
| Severity | Alert | Metric | Namespace | Statistic | Period | Definition | Evaluation | Alarm After | Why Monitor |
|---|---|---|---|---|---|---|---|---|---|
| P0 | Service unavailable | DesiredTaskCount - RunningTaskCount + probe_success |
ECS/ContainerInsights + blackbox |
metric math + min | 60s | task_gap > 0 and /health failed |
3/3 datapoints and for 3m |
~3m | 同时证明调度层和用户视角都异常,应立即处理 |
| P1 | Running task too low | DesiredTaskCount - RunningTaskCount |
ECS/ContainerInsights |
metric math | 60s | > 0 |
5/5 datapoints |
~5m | 发现部署失败、任务崩溃、容量不足或镜像启动失败 |
| P1 | HTTP 5xx high | http_requests_total |
app metrics | rate | 5m | 5xx_rate >= 5% |
for 5m |
~5m | 直接反映用户请求失败和发布/依赖问题 |
| P1 | P95 latency high | http_request_duration_seconds_bucket |
app metrics | p95 | 5m | p95 >= 1s or > 2 * 1h avg |
for 10m |
~10m | 发现用户体验下降、依赖慢或服务饱和 |
| P2 | CPU high | CPUUtilization |
AWS/ECS |
Average |
60s | >= 80% |
15/15 datapoints |
~15m | 提前发现容量不足和自动扩缩容风险 |
| P2 | Memory high | MemoryUtilization |
AWS/ECS |
Average |
60s | >= 85% |
15/15 datapoints |
~15m | 防止 OOM kill、重启循环和性能抖动 |
| P2 | Event loop lag high | nodejs_eventloop_lag_seconds_bucket |
app metrics | p95 | 5m | >= 0.2s |
for 10m |
~10m | 发现同步阻塞、CPU 密集代码或 GC 压力 |
| P2 | Heap pressure | nodejs_heap_size_used_bytes / nodejs_heap_size_total_bytes |
app metrics | ratio | 5m | >= 85% |
for 10m |
~10m | 提前发现内存泄漏和 GC 频繁导致的延迟 |
Evaluation rule:
Period 是每个 datapoint 的统计窗口,不是告警持续时间。
Alarm After 约等于 Period * EvaluationPeriods;应用指标的 `for` 直接表示持续时间。
rate/histogram window 是计算窗口,不等于告警 for。明显升高 的统一定义:
current_5m > absolute_threshold
and
current_5m > 2 * avg_over_time(metric[1h])
for 10m2. CloudWatch Metrics#
| Metric | Meaning | Why Monitor | Namespace | Statistic | Period |
|---|---|---|---|---|---|
| CPUUtilization | ECS service/task 的 CPU 使用率 | 判断计算资源是否饱和和扩容是否需要触发 | AWS/ECS | Average | 60s |
| MemoryUtilization | ECS service/task 的内存使用率 | 判断 OOM、内存泄漏和任务重启风险 | AWS/ECS | Average | 60s |
| RunningTaskCount | 当前处于运行状态的 task 数 | 判断服务实际容量是否达到期望 | ECS/ContainerInsights or AWS/ECS if enabled | Average | 60s |
| DesiredTaskCount | ECS service 期望运行的 task 数 | 与 RunningTaskCount 对比发现调度或启动失败 | ECS/ContainerInsights or AWS/ECS if enabled | Average | 60s |
查询 running task 是否低于 desired task:
[
{
"Id": "running",
"MetricStat": {
"Metric": {
"Namespace": "ECS/ContainerInsights",
"MetricName": "RunningTaskCount",
"Dimensions": [
{ "Name": "ClusterName", "Value": "prod-cluster" },
{ "Name": "ServiceName", "Value": "api" }
]
},
"Period": 60,
"Stat": "Average"
},
"ReturnData": false
},
{
"Id": "desired",
"MetricStat": {
"Metric": {
"Namespace": "ECS/ContainerInsights",
"MetricName": "DesiredTaskCount",
"Dimensions": [
{ "Name": "ClusterName", "Value": "prod-cluster" },
{ "Name": "ServiceName", "Value": "api" }
]
},
"Period": 60,
"Stat": "Average"
},
"ReturnData": false
},
{
"Id": "task_gap",
"Expression": "desired-running",
"Label": "desired minus running",
"ReturnData": true
}
]aws cloudwatch get-metric-data \
--start-time 2026-06-02T00:00:00Z \
--end-time 2026-06-02T01:00:00Z \
--metric-data-queries file://ecs-running-vs-desired.jsonCloudWatch Alarm 条件:
metric math id: task_gap
comparison: GreaterThanThreshold
threshold: 0
evaluation_periods: 5
datapoints_to_alarm: 5
period: 60
severity: P13. PromQL#
YACE metric 名称先用下面的查询确认:
# 用正则先找出当前 YACE 暴露出来的 ECS metric 名称。
# 这里不是告警表达式,只是落地前确认 metric name 和 label name。
{__name__=~"aws_ecs_.*(running|desired|cpu|memory).*"}具体 PromQL:
# running task 小于 desired task,表示 ECS 想要的任务数没有全部跑起来。
# 这个一般是 deployment 卡住、镜像拉取失败、健康检查失败、容量不足。
aws_ecs_running_task_count_average{cluster_name="prod-cluster", service_name="api"}
< aws_ecs_desired_task_count_average{cluster_name="prod-cluster", service_name="api"}# ECS service 平均 CPU 使用率超过 80%。
# 适合做 P2 容量风险,不建议单独作为 P1 可用性告警。
aws_ecs_cpu_utilization_average{cluster_name="prod-cluster", service_name="api"} >= 80# ECS service 平均内存使用率超过 85%。
# Fargate / container 内存打满通常会导致 OOM kill,所以阈值比 CPU 更敏感。
aws_ecs_memory_utilization_average{cluster_name="prod-cluster", service_name="api"} >= 85Node.js 应用指标:
# 计算 5 分钟内 HTTP 5xx 错误率:
# 分子 = 5xx 请求速率
# 分母 = 全部请求速率
# 乘以 100 = 百分比
# 结果 >= 5 表示 5xx 错误率达到 5%。
100 *
sum(rate(http_requests_total{service="api",status=~"5.."}[5m]))
/
sum(rate(http_requests_total{service="api"}[5m]))
>= 5# 计算 HTTP 请求耗时的 p95:
# http_request_duration_seconds_bucket 是 Prometheus histogram bucket
# rate(...[5m]) 取最近 5 分钟每个 bucket 的增长速率
# sum by (le) 保留 bucket 边界 le,再把不同 instance 的 bucket 合并
# histogram_quantile(0.95, ...) 根据 bucket 估算 p95
# 结果单位是 seconds,>= 1 表示 p95 请求耗时超过 1 秒。
histogram_quantile(
0.95,
sum by (le) (rate(http_request_duration_seconds_bucket{service="api"}[5m]))
) >= 1# 计算 Node.js event loop lag 的 p95:
# event loop lag 高说明 JS 主线程被 CPU、同步代码或 GC 阻塞
# 结果单位是 seconds,>= 0.2 表示 p95 lag 超过 200ms。
histogram_quantile(
0.95,
sum by (le) (rate(nodejs_eventloop_lag_seconds_bucket{service="api"}[5m]))
) >= 0.2# 计算 V8 heap 使用率:
# used bytes / total bytes = heap 使用比例
# >= 0.85 表示 heap 已经用了 85%,需要排查内存泄漏或调大内存。
nodejs_heap_size_used_bytes{service="api"}
/
nodejs_heap_size_total_bytes{service="api"}
>= 0.854. vmalert Rules#
groups:
- name: ecs-nodejs.rules
rules:
- alert: ECSServiceRunningTaskTooLow
# desired > running 时触发,表示 ECS service 没有达到期望任务数。
expr: aws_ecs_running_task_count_average < aws_ecs_desired_task_count_average
for: 5m
labels:
severity: P1
component: ecs
annotations:
summary: "ECS running task count is below desired count"
- alert: NodeJSHigh5xxRate
# 5xx rate = 5xx 请求速率 / 总请求速率 * 100。
# by (service) 是为了每个服务单独计算,不把多个服务混在一起。
expr: |
100 * sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service) >= 5
for: 5m
labels:
severity: P1
component: app
annotations:
summary: "Node.js HTTP 5xx rate is >= 5%"
- alert: NodeJSHighP95Latency
# 从 histogram bucket 计算每个 service 的 p95 延迟,单位 seconds。
expr: |
histogram_quantile(0.95, sum by (service, le) (rate(http_request_duration_seconds_bucket[5m]))) >= 1
for: 10m
labels:
severity: P1
component: app
annotations:
summary: "Node.js HTTP p95 latency is >= 1s"