Empfohlenes Minimalsetup für den sinnvollen Einsatz eines Elastic Stack Systems

Hierbei soll ein Hauptaugenmerk auf "sinnvoll" liegen, ohne aber dabei den Punkt der Verfügbarkeit und der Betriebssicherheit zu ignorieren.
Sicherlich werden sehr große Setups mit einer Vielzahl von EPS und/oder großen Datenmengen andere Anforderungen haben; für den Großteil der Einsatzbereiche wird dieses Setup aber ausreichen.

Abzusichern sind folgende Aspekte:
- Entgegennahme der Nachrichten per Syslog und/oder Filebeat und Logbeat
- Senden der Nachrichten von Logstash zu Elasticsearch
- Speichern der Daten in Elasticsearch

Alles andere, wie z.B. Kibana, das IMHO sicher wichtig ist, aber nicht wichtig genug, als dass man hier über technische Maßnahmen nachdenken sollte, findet hier keine gesonderte Beachtung.
Auch hier kommt es wieder auf das konkrete Einsatzszenario an. Meist wird es aber vollends genügen, Kibana mit auf jeder der beiden Logstash Systeme zu installieren.

Entgegennahme der Nachrichten per Syslog und/oder Filebeat und Logbeat

Bei diesem Punkt kommt es darauf an, ob neben Filebeat/Logbeat, auch noch Nachrichten per Syslog o.ä. entgegengenommen werden sollen. Ist dies der Fall, so gibt es fast keinen Weg, der ohne einem Loadbalancer, der vor die Logstash Nodes gesetzt wird, vorbeikommt.
Filebeat und Logbeat bieten die Möglichkeit mehrere Logstash Targets zu konfigurieren; für Syslog, speziell UDP, ist mir kein derartiges Verfahren bekannt.
Damit der Loadbalancer keinen Single-point-of-failure darstellt, muss dieser ebenfalls höher verfügbar ausgelegt werden. Der Einsatz von zwei HAProxy Nodes, die mittels keepalive (VRRP) gekoppelt sind, und sich eine IP teilen, wäre eine stabile Möglichkeit.
Das Ziel für alle Syslog und, wenn gewünscht, auch Beats-Nachrichten, ist dabei die Cluster-IP des HAProxy Clusters. Wichtig ist zu beachten, dass es bei Ausfall einer Node, für die Dauer der Umschaltung auf die zweite Node, zu Ausfällen in der Logannahme bei Syslog kommt- Datenverlust!
Auch hier bieten Filebeat und Logbeat einen Vorteil: Diese puffern die Nachrichten ist das Zielsystem nicht verfügbar.

Senden der Nachrichten von Logstash zu Elasticsearch

Logstash beherrscht im Standard bereits Loadbalancing beim Senden von Daten an Elasticsearch.

Aus der Dokumentation des Elasticsearch output- Plugins von logstash:
"...
hosts
Value type is uri
Default value is [//127.0.0.1]
Sets the host(s) of the remote instance. If given an array it will load balance requests across the hosts specified in the hosts parameter.
..."

Der betreffende Abschnitt einer Logstash Konfiguration würde bei zwei Elasticsearch Servern damit in etwa so aussehen:

output {
    elasticsearch {
        hosts => ["1.2.3.4:9200", "1.2.3.5:9200"]
    }
}

Gilt es dabei auch noch einen Benutzer und ein Kennwort zu spezifizieren:

output {
    elasticsearch {
        hosts    => ["1.2.3.4:9200", "1.2.3.5:9200"]
        user     => loguser
        password => absolutgeheim
    }
}

Äquivalent dazu erfolgt die Spezifikation wenn http(s) als Transport verwendet werden soll. Dies ist nach Elastic die bevorzugte Variante:
hosts => ["https://1.2.3.4", "https://1.2.3.5"]

Auf Grund des Aufbaus von Logstash, der garantiert, dass Logevents nur einmal gesendet werden, und bei Ausfall eines Elasticsearch Servers die Events automatisch zum/zu den verbleibenden System(en) gesendet werde, ist damit der Punkt "Höhere Verfügbarkeit" zwischen Logstash und Elasticsearch geregelt.

Speichern der Daten in Elasticsearch

Die Daten selbst werden in sogenannten Indizes abgelegt, die widerum mehrere sog. Shards enthalten können. In der Standardkonfiguration sind fünf Shards pro Index voreingestellt. Diese Shards können, je nach Anforderung an die Verfügbarkeit, repliziert werden. Hier ist im Standard ein Wert von 1 Replika eingetragen, was bedeutet, dass die Daten in einem primären Shard und einem Replika- Shard abgelegt werden.
Sind zwei Elasticsearch Data-Nodes vorhanden, so werden die Daten also identisch auf beiden vorgehalten. Im Grunde würde dies unseren Anforderungen bereits genügen, wenn es da nicht das "Problem" der Split-Brain-Situation gäbe. Eine Node-Majority ist bei zwei Nodes nun mal nicht zu realisieren. Deswegen sollte man ein Minimum von drei Master-Capable Nodes einsetzen.

Zwischenstand

Für ein sinnvolles Setup sind sieben Maschinen notwendig:

1. zwei Loadbalaner Nodes zur Verteilung der Nachrichten auf die Logstash Nodes
2. zwei Logstash Nodes um den Ausfall einer Node kompensieren zu können
3. drei Elasticsearch Nodes im Master-Capable/Data Node Modus für die Betriebssicherheit des Clusters und damit der Datenablage

1. minimale Hardwareanforderungen
2. mittlere Hardwareanforderungen
3. erhöhte Hardwareanforderungen

Die Konfiguration des Loadbalancers und der Elastic Stack Programme sollte dabei durch eine Orchestrationlösung wie z.B. Puppet, Ansible oder Chef erfolgen. Dies ermöglicht eine konsistente Konfiguration und bietet durch das zusätzliche Vorhalten der Konfigurationen einen Pluspunkt für die Datensicherheit und die Wiederherstellung im Desasterfall.

Ich habe die gesamte Zeit bewusst das Wort Hochverfügbarkeit vermieden. Meines Erachtens wird dieses Wort meist viel zu leichtfertig verwendet und suggeriert eine teilweise nicht vorhandene Sicherheit. Hochverfügbarkeit beginnt weit vorher! Hierzu zählt z.B. auch die Standortwahl und die Konzeption des Serverraumes/ Rechenzentrums und bedingt z.B. auch Punkte wie technische und organisatorische Massnahmen für den Zutritts- und Zugriffsschutz. Hochverfügbarkeit ist nicht alleine die Tatsache, dass die Server 99,99xxxx Prozent funktionieren!

Elasticsearch Hardwareanforderungen

Wie jedes System hat auch Elasticsearch Anforderungen an die Hardware, die für einen performanten und sicheren Betrieb erfüllt sein müssen. Hierzu zählen Anforderungen an die CPU, den Hauptspeicher und das Plattensystem.

CPU
Jede aktuelle Mehrkern CPU (ok, vielleicht nicht unbedingt der Klasse eines Intel ATOM Prozessors) reicht im Großteil der Fälle vollkommen für den Einsatz mit Elasticsearch aus.


RAM
Maschinen mit Speichergrößen zwischen 16 und 64 GB sind ideal, wobei 64 GB RAM auf Grund des 31 GB Heaplimits das Optimum darstellen.

Diskdrives
HDD Redundanzen (RAID) sind für die Laufwerke, auf denen die Daten abgelegt werden, unnötig. Die Redundanz im Cluster wird durch die über die Datanodes verteilten Shards realisiert.
RAID 0 kann zur Erhöhung der I/O Geschwindigkeit eingesetzt werden. Als Diskdrives sind entweder schnell drehende Platten (15k RPM) oder SSDs zu bevorzugen.
Wenn SSDs zum Einsatz kommen, sollte der I/O Scheduler umgestellt werden; dieser sollte dann bevorzugt auf deadline gestellt werden.
Dies kann z.B. durch eine UDEV Rule gesetzt werden, die nur "nicht drehende" Laufwerke berücksichtigt. Hierzu legt man unter /etc/udev/rules.d eine neue Datei (z.B. 66-ssd-scheduler.rules) an. Diese Datei muss dann den folgenden Inhalt haben:

ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0",ATTR{queue/scheduler}="deadline"

Um zu prüfen ob das System nicht-rotierende Laufwerke richtig erkennt, kann man sich folgenden Einzeilers bedienen:

# for disk in /sys/block/sd?/queue/rotational; do printf "$disk is "; cat $disk; done

/sys/block/sda/queue/rotational is 1
/sys/block/sdb/queue/rotational is 0

Die Ausgabe zeigt, dass sda eine normale, rotierende Festplatte ist, und sdb ein SSD Drive.

Sind diese Hardwarevoraussetzungen geschaffen, bzw. angepasst und ist das System fertig installiert (DNS, NTP...) geht es, nach der Installation von Elasticsearch, an die Anpassung der Umgebung. Die Installation werde ich hier nicht beschreiben; dazu gibt es viele gute und sehr gute Artikel im Netz.
Selbstverständlich kann man Elasticsearch auch nach der, vor allem in der Windows-Welt oft praktizierten WWF (Weiter, Weiter, Fertigstellen) Methode installieren- allerdings verschenkt man unglaublich viele Ressourcen und erhält ein lediglich teilweise stabiles System. Sinnvoller ist vorher den Kopf einzuschalten und elementare Anpassungen vorzunehmen.

Elasticsearch Systemeinstellungen

v6.2
Damit das System mit möglichst wenig Latenzen auf Anfragen reagieren kann müssen einige Parameter im Betriebssystem angepasst werden. Die aufgeführten Pfade stammen aus einem Ubuntu 16 System und können bei anderen Distributionen variieren.

Lucene arbeitet mit 4k Blöcken. Somit sollte die Datenpartition auch mit 4k Blöcken formatiert werden um optimale Performance zu erhalten.
Im Beispiel ist die Datenpartition /dev/mapper/vg1-data4, die an /data4 gemountet werden soll.

root@c4:~# mkfs.ext4 -b 4096 /dev/mapper/vg1-data4

Prüfen kann man die Formatierung mit:
root@c4:~# dumpe2fs /dev/mapper/vg1-data4 | grep 'Block size:'
dumpe2fs 1.42.9 (4-Feb-2014)
Block size:               4096

Das Filesystem, das die Daten aufnimmt, sollte dann mit noatime und nodiratime gemountet werden, z.B. in der /etc/fstab
/dev/mapper/vg1-data4    /data4  ext4     noatime,nodiratime        0       2

/usr/lib/systemd/system/elasticsearch.service
LimitMEMLOCK=infinity

/etc/security/limits.conf
elasticsearch   soft    memlock         unlimited
elasticsearch   hard    memlock         unlimited

root            soft    memlock         unlimited
root            hard    memlock         unlimited

elasticsearch   soft    nofile          65535
elasticsearch   hard    nofile          65535

/etc/pam.d/common-session
session required        pam_limits.so

/etc/pam.d/common-session-noninteractive
session required        pam_limits.so

/etc/sysctl.conf
vm.swappiness=1
net.core.somaxconn=65535
vm.max_map_count=262144
fs.file-max=518144

/etc/elasticsearch/jvm.options
-Xms31g (50% des RAMs aber nicht mehr als 31 GB)
-Xmx31g (50% des RAMs aber nicht mehr als 31 GB)

/etc/elasticsearch/elasticsearch.yml
bootstrap.memory_lock: true

Nach all diesen Änderungen sollte ein Neustart des Systems erfolgen um sicherzustellen, dass alle Parameter auch wirklich sauber übernommen werden.

Kontrollieren kann man den Erfolg der Umstellung mit

curl http:\\localhost:9200\_nodes?filter_path=**.mlockall\?pretty

Die Ausgabe sollte für die entsprechende Node in etwa so aussehen:
{
  "nodes" : {
    "RNSUoecqABCCnhuWIDVuXw" : {
      "process" : {
        "mlockall" : false
      }
    }
  }
}

Das Ergebnis ist ein sauberes, rudimentär optimiertes Elasticsearch System für die üblichsten Anwendungsfälle.