49 Best Practices

Der erfolgreiche Betrieb von OpenSearch erfordert mehr als nur technisches Wissen - es braucht Erfahrung und ein tiefes Verständnis dafür, wie verschiedene Systemkomponenten zusammenwirken. In diesem Kapitel behandeln wir umfassende Best Practices, die Ihnen helfen, zuverlässige, leistungsfähige und wartbare OpenSearch-Deployments aufzubauen und zu betreiben.

49.1 Architekturelle Designprinzipien

Die Grundlage eines erfolgreichen OpenSearch-Deployments liegt in seiner Architektur. Denken Sie beim Design eines OpenSearch-Clusters wie bei der Stadtplanung - Sie müssen aktuelle Anforderungen berücksichtigen und gleichzeitig für zukünftiges Wachstum planen, Ressourcen effizient nutzen und Flexibilität für Veränderungen bewahren.

49.1.1 Clustergrößenbestimmung

Beginnen wir mit einer der grundlegendsten Entscheidungen: der richtigen Dimensionierung Ihres Clusters. Hier ein Beispiel für eine gut dimensionierte Cluster-Konfiguration:

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.disk.threshold_enabled": true,
    "cluster.routing.allocation.disk.watermark.low": "85%",
    "cluster.routing.allocation.disk.watermark.high": "90%",
    "cluster.routing.allocation.disk.watermark.flood_stage": "95%",
    "cluster.routing.allocation.awareness.attributes": "zone",
    "cluster.routing.allocation.balance.shard": 0.7,
    "cluster.routing.allocation.balance.index": 0.6
  }
}

Diese Einstellungen spiegeln wichtige Prinzipien wider:

Für die Berechnung der Ressourcenanforderungen können Sie folgende Formel verwenden:

def berechne_cluster_ressourcen(taegliches_datenvolumen_gb, aufbewahrungstage, replikationsfaktor):
    """
    Berechnet die erforderlichen Cluster-Ressourcen basierend auf Datenvolumen und Aufbewahrung.
    
    Parameter:
        taegliches_datenvolumen_gb: Tägliche Datenaufnahme in GB
        aufbewahrungstage: Anzahl der Tage zur Datenaufbewahrung
        replikationsfaktor: Anzahl der Replikate + 1
        
    Rückgabe:
        Dictionary mit Ressourcenanforderungen
    """
    # Berechne Gesamtspeicherbedarf
    gesamtspeicher_gb = taegliches_datenvolumen_gb * aufbewahrungstage * replikationsfaktor
    
    # 20% Puffer für Overhead und Wachstum
    gesamtspeicher_mit_puffer = gesamtspeicher_gb * 1.2
    
    # Berechne Anzahl der Shards (Ziel: ~30GB pro Shard)
    empfohlene_shards = math.ceil(gesamtspeicher_gb / 30)
    
    # Berechne Mindestanzahl an Knoten
    min_knoten = math.ceil(empfohlene_shards / 25)  # Max 25 Shards pro Knoten
    
    return {
        "gesamtspeicher_gb": gesamtspeicher_mit_puffer,
        "empfohlene_shards": empfohlene_shards,
        "mindest_knoten": min_knoten,
        "empfohlene_knoten": min_knoten + 2  # Puffer für Redundanz
    }

49.1.2 Index-Design-Muster

Ein gutes Index-Design ist entscheidend für langfristigen Erfolg. Hier ein Beispiel für ein gut strukturiertes Index-Template:

PUT _index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": "{{ knoten * 2 }}",
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy",
      "index.mapping.total_fields.limit": 1000,
      "index.refresh_interval": "30s",
      "index.translog.durability": "async",
      "index.translog.sync_interval": "5s"
    },
    "mappings": {
      "dynamic_templates": [
        {
          "strings_als_keywords": {
            "match_mapping_type": "string",
            "mapping": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      ],
      "properties": {
        "@timestamp": { "type": "date" },
        "nachricht": { 
          "type": "text",
          "norms": false
        },
        "level": { "type": "keyword" }
      }
    }
  }
}

Dieses Template verkörpert mehrere wichtige Prinzipien:

49.2 Datenverwaltungs-Best-Practices

Eine effektive Datenverwaltung in OpenSearch erfordert sorgfältige Überlegungen zum Datenfluss, von der Aufnahme bis zur Archivierung.

49.2.1 Optimierung der Datenaufnahme

Hier ein Beispiel einer optimierten Ingestion-Pipeline:

PUT _ingest/pipeline/logs_pipeline
{
  "description": "Optimierte Log-Verarbeitungspipeline",
  "processors": [
    {
      "date": {
        "field": "timestamp",
        "formats": ["ISO8601", "UNIX"],
        "target_field": "@timestamp"
      }
    },
    {
      "script": {
        "source": """
          // Normalisierung der Log-Level
          def level = ctx.level.toLowerCase();
          if (level.contains('warn')) {
              ctx.level = 'warnung';
          } else if (level.contains('err')) {
              ctx.level = 'fehler';
          } else if (level.contains('info')) {
              ctx.level = 'info';
          } else {
              ctx.level = 'unbekannt';
          }
        """
      }
    },
    {
      "set": {
        "field": "_meta.eingangszeit",
        "value": "{{_ingest.timestamp}}"
      }
    }
  ]
}

49.2.2 Index-Lifecycle-Management implementieren

Eine gut durchdachte ILM-Policy hilft bei der Verwaltung von Daten über ihren gesamten Lebenszyklus:

PUT _ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "1d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "2d",
        "actions": {
          "forcemerge": {
            "max_num_segments": 1
          },
          "allocate": {
            "require": {
              "data": "warm"
            }
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "require": {
              "data": "cold"
            }
          },
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

49.3 Performance-Optimierungs-Best-Practices

Performance-Optimierung in OpenSearch bedeutet, Ressourcen effektiv zu verstehen und zu verwalten.

49.3.1 Speicherverwaltung

Hier ein Beispiel optimierter JVM-Einstellungen:

# jvm.options
-Xms31g
-Xmx31g
-XX:+UseG1GC
-XX:G1ReservePercent=25
-XX:InitiatingHeapOccupancyPercent=75
-XX:+ParallelRefProcEnabled
-XX:MaxGCPauseMillis=200
-XX:+ExplicitGCInvokesConcurrent

Diese Einstellungen spiegeln wichtige Prinzipien wider:

49.3.2 Abfrageoptimierung

Hier sind Beispiele für Abfrageoptimierungsmuster:

GET /logs-*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "@timestamp": {
              "gte": "now-1h"
            }
          }
        },
        {
          "term": {
            "level": "fehler"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "nachricht": {
              "query": "verbindung verweigert",
              "boost": 2
            }
          }
        }
      ],
      "minimum_should_match": 0
    }
  },
  "_source": ["@timestamp", "nachricht", "level"],
  "sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ]
}

Diese Abfrage demonstriert mehrere Optimierungsprinzipien:

49.4 Sicherheits-Best-Practices

Sicherheit in OpenSearch erfordert einen umfassenden Ansatz, der alle Aspekte Ihres Deployments berücksichtigt.

49.4.1 Authentifizierung und Autorisierung

Hier ein Beispiel einer gut strukturierten Rollenkonfiguration:

PUT _plugins/_security/api/roles/logs_leser
{
  "cluster_permissions": [
    "cluster:monitor/health"
  ],
  "index_permissions": [
    {
      "index_patterns": ["logs-*"],
      "allowed_actions": [
        "read",
        "search"
      ],
      "field_level_security": {
        "grant": ["@timestamp", "nachricht", "level", "host"],
        "except": ["_source.passwort", "_source.kreditkarte"]
      }
    }
  ]
}

49.4.2 Netzwerksicherheit

Implementieren Sie sichere Kommunikationseinstellungen:

# opensearch.yml
plugins.security.ssl.transport.enabled: true
plugins.security.ssl.transport.pemcert_filepath: certs/node.pem
plugins.security.ssl.transport.pemkey_filepath: certs/node-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/ca.pem
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: certs/node.pem
plugins.security.ssl.http.pemkey_filepath: certs/node-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: certs/ca.pem

49.5 Überwachungs- und Wartungs-Best-Practices

Effektive Überwachung und Wartung gewährleisten die langfristige Zuverlässigkeit Ihres OpenSearch-Deployments.

49.5.1 Monitoring

Ein Beispiel für ein umfassendes Monitoring-System:

PUT _plugins/_alerting/monitors/cluster_gesundheit
{
  "type": "monitor",
  "name": "Cluster-Gesundheitsmonitor",
  "enabled": true,
  "schedule": {
    "period": {
      "interval": 1,
      "unit": "MINUTES"
    }
  },
  "inputs": [
    {
      "search": {
        "indices": [".monitoring-opensearch-*"],
        "query": {
          "bool": {
            "must": [
              {
                "range": {
                    "@timestamp": {
                    "gte": "now-5m"
                  }
                }
              }
            ]
          }
        }
      }
    }
  ],
  "triggers": [
    {
      "name": "Cluster-Gesundheitsalarm",
      "severity": "Hoch",
      "condition": {
        "script": {
          "source": """
            def maxHeapNutzung = 85.0;
            def maxCpuNutzung = 90.0;
            
            return ctx.results[0].hits.hits.any(hit -> {
              def stats = hit._source;
              return stats.jvm.mem.heap_used_percent > maxHeapNutzung ||
                     stats.os.cpu.percent > maxCpuNutzung;
            });
          """
        }
      }
    }
  ]
}