1. Find the noisy alarms
Alarm state changes over 30 days:
aws cloudwatch describe-alarm-history --history-item-type StateUpdate \
--start-date "$(date -u -d '-30 days' +%FT%TZ)" --max-items 5000 \
--query 'AlarmHistoryItems[].AlarmName' --output text | tr '\t' '\n' | sort | uniq -c | sort -rn | head -25
For each top alarm: how many times did it go to ALARM, and how many times did someone do something?
2. Evaluation settings
| Problem | Fix |
|---|---|
| Fires on single spikes | DatapointsToAlarm M of N (e.g. 3 of 5 one-minute periods) |
| Flaps around the threshold | Longer period or wider gap; separate warning vs critical alarms |
| ALARM on gaps (instance stopped, no traffic at night) | TreatMissingData: notBreaching or ignore, deliberately chosen per alarm |
| Percent metrics on tiny volumes (1 error in 2 requests = 50%) | Add a minimum-volume condition via metric math |
Metric math example: error rate only when there's real traffic:
[
{"Id": "e", "MetricStat": {"Metric": {"Namespace": "AWS/ApplicationELB", "MetricName": "HTTPCode_Target_5XX_Count",
"Dimensions": [{"Name": "LoadBalancer", "Value": "app/web-alb/50dc6c495c0c9188"}]}, "Period": 60, "Stat": "Sum"}, "ReturnData": false},
{"Id": "r", "MetricStat": {"Metric": {"Namespace": "AWS/ApplicationELB", "MetricName": "RequestCount",
"Dimensions": [{"Name": "LoadBalancer", "Value": "app/web-alb/50dc6c495c0c9188"}]}, "Period": 60, "Stat": "Sum"}, "ReturnData": false},
{"Id": "rate", "Expression": "IF(r > 100, 100 * e / r, 0)", "Label": "5xx rate when > 100 req/min", "ReturnData": true}
]
3. Anomaly detection for patterned metrics
For metrics with daily/weekly cycles (requests, latency, queue depth), a static threshold is either too tight at peak or too loose at night. An anomaly detection band follows the pattern:
aws cloudwatch put-metric-alarm --alarm-name web-requests-anomaly \
--comparison-operator LessThanLowerOrGreaterThanUpperThreshold --evaluation-periods 5 --datapoints-to-alarm 3 \
--threshold-metric-id ad1 --treat-missing-data ignore \
--metrics '[{"Id":"m1","ReturnData":true,"MetricStat":{"Metric":{"Namespace":"AWS/ApplicationELB","MetricName":"RequestCount","Dimensions":[{"Name":"LoadBalancer","Value":"app/web-alb/50dc6c495c0c9188"}]},"Period":300,"Stat":"Sum"}},
{"Id":"ad1","Expression":"ANOMALY_DETECTION_BAND(m1, 3)","Label":"band"}]'
The model needs history (about two weeks for good bands). Exclude known abnormal periods (incidents, migrations) from training.
4. Composite alarms
Page on a combination that means real trouble, keep the inputs as non-paging:
aws cloudwatch put-composite-alarm --alarm-name orders-service-degraded \
--alarm-rule 'ALARM("orders-5xx-rate") AND (ALARM("orders-latency-p99") OR ALARM("orders-healthy-hosts-low"))' \
--alarm-actions arn:aws:sns:eu-west-1:123456789012:oncall-page
Use the ActionsSuppressor option to silence a composite while a parent alarm (e.g. "region network issue" or "maintenance mode") is in ALARM, so dependent alarms don't flood during a known event.
5. Route by severity
| Severity | Route |
|---|---|
| Critical (customer impact) | Page (Incident Manager / paging tool) |
| Warning | Team chat + ticket |
| Info | Dashboard only (no alarm action) |
Every paging alarm has an owner and a runbook link in its description.
6. Symptom first
Prefer user-facing signals (error rate, latency, synthetic canary failures, queue age) for paging, and keep cause metrics (CPU, memory) as warnings or dashboard context.
7. Review monthly
Top flapping alarms, % of pages acted on, and alarms without owners. Delete or downgrade what nobody acts on, after confirming a symptom alarm covers it.
Tip
CloudWatch charges per alarm metric (and anomaly detection alarms count as several). Consolidating noisy per-instance alarms into a few composite or metric-math alarms often lowers cost too.
Checklist
- Flapping alarms and action rate measured
- M-of-N and missing-data treatment set deliberately
- Minimum-volume conditions on rate alarms
- Anomaly detection on patterned metrics
- Composite alarms page; inputs don't; suppressors for known events
- Severity routing, owners and runbooks