Die Beobachtbarkeit (Observability) moderner Systeme ist eine zentrale Herausforderung im DevOps-Umfeld. OpenSearch bietet leistungsfähige Werkzeuge, um die drei Säulen der Observability - Logs, Metriken und Traces - zu erfassen, zu analysieren und zu visualisieren. In diesem Kapitel lernen Sie, wie Sie diese Werkzeuge effektiv einsetzen können.
Observability geht über einfaches Monitoring hinaus. Während Monitoring uns sagt, OB etwas nicht funktioniert, hilft uns Observability zu verstehen, WARUM etwas nicht funktioniert. Dies erreichen wir durch die Integration von:
Logs sind oft der erste Anlaufpunkt bei der Fehlersuche. OpenSearch bietet leistungsfähige Funktionen zur Log-Verarbeitung.
PUT _ingest/pipeline/log_enrichment
{
"description": "Verarbeitet und strukturiert Anwendungslogs",
"processors": [
{
"grok": {
"field": "message",
"patterns": [
"%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \\[%{DATA:service}\\] %{DATA:trace_id} - %{GREEDYDATA:message_body}"
]
}
},
{
"date": {
"field": "timestamp",
"formats": ["ISO8601"]
}
},
{
"set": {
"field": "environment",
"value": "{{log_environment}}"
}
},
{
"script": {
"lang": "painless",
"source": """
if (ctx.level == 'ERROR') {
ctx.alert_level = 'high';
} else if (ctx.level == 'WARN') {
ctx.alert_level = 'medium';
} else {
ctx.alert_level = 'low';
}
"""
}
}
]
}
Diese Pipeline:
PUT _index_template/logs_template
{
"index_patterns": ["logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "logs_policy",
"index.routing.allocation.include.data_type": "hot"
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"service": { "type": "keyword" },
"level": { "type": "keyword" },
"trace_id": { "type": "keyword" },
"message_body": { "type": "text" },
"environment": { "type": "keyword" },
"alert_level": { "type": "keyword" },
"metadata": {
"type": "object",
"dynamic": true
}
}
}
}
}
Metriken geben uns quantitative Einblicke in den Systemzustand. OpenSearch kann verschiedene Metriken-Formate verarbeiten und visualisieren.
PUT /metrics-template
{
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"host": { "type": "keyword" },
"service": { "type": "keyword" },
"metric_name": { "type": "keyword" },
"metric_value": { "type": "float" },
"unit": { "type": "keyword" },
"tags": { "type": "keyword" }
}
},
"settings": {
"index.routing.allocation.include.data_type": "warm",
"index.refresh_interval": "30s"
}
}
Metriken-Visualisierungen in OpenSearch Dashboards erstellen wir mit der OpenSearch Query DSL:
GET metrics-*/_search
{
"size": 0,
"query": {
"bool": {
"must": [
{
"range": {
"timestamp": {
"gte": "now-1h",
"lte": "now"
}
}
},
{
"term": {
"service": "web-frontend"
}
}
]
}
},
"aggs": {
"response_times": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1m"
},
"aggs": {
"avg_response": {
"avg": {
"field": "metric_value"
}
},
"response_percentiles": {
"percentiles": {
"field": "metric_value",
"percents": [50, 90, 99]
}
}
}
}
}
}
Verteiltes Tracing hilft uns, den Weg einer Anfrage durch verschiedene Microservices zu verfolgen.
PUT traces-template
{
"mappings": {
"properties": {
"trace_id": { "type": "keyword" },
"span_id": { "type": "keyword" },
"parent_span_id": { "type": "keyword" },
"service": { "type": "keyword" },
"operation": { "type": "keyword" },
"start_time": { "type": "date_nanos" },
"duration": { "type": "long" },
"status": { "type": "keyword" },
"tags": {
"type": "nested",
"properties": {
"key": { "type": "keyword" },
"value": { "type": "keyword" }
}
}
}
}
}
Trace-Analyse mit der OpenSearch DSL:
GET traces-*/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"status": "error"
}
},
{
"range": {
"duration": {
"gte": "1000000" // 1 Sekunde in Mikrosekunden
}
}
}
]
}
},
"aggs": {
"services": {
"terms": {
"field": "service",
"size": 10
},
"aggs": {
"avg_duration": {
"avg": {
"field": "duration"
}
}
}
}
}
}
Die wahre Stärke von OpenSearch liegt in der Fähigkeit, Logs, Metriken und Traces zu korrelieren.
POST _plugins/_dashboards/api/saved_objects/visualization
{
"attributes": {
"title": "Service Health Overview",
"visualizationType": "metrics",
"params": {
"type": "timeseries",
"series": [
{
"id": "errors",
"metrics": [
{
"id": "count",
"type": "count"
}
],
"split_mode": "terms",
"terms_field": "service",
"terms_size": 10
}
],
"annotations": [
{
"fields": "message",
"template": "{{message}}",
"id": "error_logs",
"index_pattern": "logs-*",
"query_string": "level:ERROR"
}
]
}
}
}
Ein effektives Observability-System benötigt automatische Benachrichtigungen bei Problemen.
PUT _plugins/_alerting/monitors/service_health
{
"type": "monitor",
"name": "Service Health Monitor",
"enabled": true,
"schedule": {
"period": {
"interval": 1,
"unit": "MINUTES"
}
},
"inputs": [
{
"search": {
"indices": ["metrics-*"],
"query": {
"bool": {
"must": [
{
"range": {
"timestamp": {
"gte": "now-5m",
"lte": "now"
}
}
},
{
"term": {
"metric_name": "error_rate"
}
}
]
}
}
}
}
],
"triggers": [
{
"name": "Error Rate Alert",
"severity": "High",
"condition": {
"script": {
"source": "ctx.results[0].hits.hits.stream().map(hit -> hit._source.metric_value).average().orElse(0) > 0.05"
}
},
"actions": [
{
"name": "Notify Team",
"destination_id": "slack_team_channel",
"message_template": {
"source": "Error rate exceeded threshold: {{ctx.results.0.hits.hits.0._source.metric_value}}"
}
}
]
}
]
}
Bei der Implementierung von Observability sollten Sie beachten: