ELK: Több Elasticsearch [ES] node futtatása egy hoston

Aki ismeri az Elasticsearch [ES] filozófiáját, az pontosan tudja, hogy alap esetben semmi érteme nincs annak, hogy egy hoston több nodeot futtassunk, hiszen mi is az ES esszenciája: Végy egy halom középkategóriás, olcsón fenntartható gépet, majd minden különösebb technológiai tudás nélkül rakd fel rájuk az ES-t, kapcsold öket egy clusterbe és jöhet a fun. Ha pedig mégsem jön, mert ez így nem elég hatékony, akkor optimalizáld a shardok eloszlását, rakj hozzá a clusterhez még néhány gépet és ezen egyszerű eszközökkel lényegében bármikor tudod skálázni a clustert.

Azonban nagyvállalati környezetben előfordul, hogy középkategóriás olcsó gépek helyett komolyabb vasak kerülnek a kijelölésre. Ilyenkor meg kell tudni találni az ésszerű középutat. Egy önálló ES node kapcsán van néhány olyan technikai függőség, ami meghatározza, hogy maximum mennyi erőforrást tud optimálisan használni. Ezen függőségek közül a leginkább fontos talán a heap size:

  • Az elasticsearch technológiailag java virtuális gépben fut, aminek a heap kezelése erősen kihathat az ES működésére. Technológiai adottság, hogy 32Gb heap size alatt a JVM compressed object pointer (compressed oops) technológiát használ a heap kezelésére, ez felett már nem lehet használni ezt az opciót, ami jelentősen rontja a JVM hatékonyságát.


Amennyiben van egy vagy több nagy gépünk, ami tetemes mennyiségű memóriával (128Gb+), gyors (lehetőleg független) diszkekkel és jelentős mennyiségű szabad CPU idővel rendelkezik, akkor megadatik a lehetőség, hogy egy hoston több ES nodeot futtassunk. Ehhez azonban még néhány előfeltétel:

  • A nodeonkénti maximális heap méret nem haladhatja meg a 32Gb-ot. (https://wikis.oracle.com/display/HotSpotInternals/CompressedOops)
  • A nagy host szabad memóriájának lehetőleg legalább a fele maradjon szabadon, hogy azt a Lucene motor tudja használni a fileok cachelésére. Ez nagyon fontos az ES performanciája szempontjából.
  • Fontos, hogy amennyiben több node fut egy hoston, akkor azok nem versenyezzenek az erőforrásokért. Ezek közül a legfontosabb a disk. Az összes futó node fizikailag elkülönített path.data diszkeken dolgozzon. Mivel az ES garantálja a magas szintű adatbiztonságot ezért maximum raid0 diszk fürtözések használata javasolt a magas rendelkezésre állás érdekében.
  • Az ES indulásakor automatikusan detektálja az összes CPU-t és ezeket használja is. Egy hoston futó több node esetében ez azt eredményezheti, hogy a nodeok versenyeznek a CPU magokért, amivel összességében romolhat a keresési teljesítmény. Érdemes ezért a threadpool finomhangolásnál megadni a nodeonkénti maximális CPU core számot, amivel az adott node gazdálkodhat. A node megállapításának gyártói alapelve: #CPU/#nodes, de érdemes figyelembe venni, hogy az adott hoston milyen egyéb erőforrás igényes szolgáltatások futnak. Amennyiben van ilyen, akkor érdemes a threadpool/processors értéket csökkenteni. (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-threadpool.html#processors)
  • Egy hoston történő több node futtatása esetén el kell kerülni, hogy ugyanazon shard primary és replikája, illetve replikái ugyanarra a fizikai hostra kerüljenek. Az ehhez szükséges ellenőrzés kikényszeríthető a rack_id-val, vagy a settingcluster.routing.allocation.same_shard.host konfigurációs paraméter true-ra állításával.

Alábbiakban bemutatok egy konkrét implementációt az egy hoston történő két node futtatására. Ezt egy AWS (Amazon EC2 cloud) gépen végeztem, de a gyakorlatban bármilyen más RPM alapú disztribúción (RedHat, Centos) lényegi módosítás nélkül végrehajtható és egyéb Linux disztribúciókra is könnyedén átültethető.

Egy hoston történő több node futtatásához nincs szükség több futtatható bináris környezet létrehozásához, csak az elasticsearch konfigurációs filejaiban kell elszeparálni az egyes nodeok paramétereit és külön futtatni azokat. Ehhez a következőkre lesz szükség. Létre kell hozni egy könyvtár struktúrát az alábbiaknak megfelelően: (minta, úgy csinálod ahogy akarod)

  • /elk/node1
  • /elk/node1/config
  • /elk/node1/log
  • /elk/node1/data
  • /elk/node2
  • /elk/node2/config
  • /elk/node2/log
  • /elk/node2/data

Lehetőség szerint már itt a tervezésnél érdemes figyelembe venni, hogy a két data könyvtár különböző mountpointon legyen. SAN esetén ez lehetőleg legyen más multipathon keresztüli, akár más SAN végpontú diszk.
A meglévő /etc/elasticsearch könyvtár tartalmát át kell másolni a két node config könyvtárába.
Létre kell hozni mindkét node könyvtárban a minimális elasticsearch.yml filet. Ennek tartalma alább.
Node1 esetén:

cluster.name: es-test1
node.name: bigmachine1-node-1
node.attr.rack_id: r1
path.data: /elk/node1/data
path.logs: /elk/node1/log
bootstrap.memory_lock: true
network.host: 127.0.0.1
http.port: 9200
discovery.zen.ping.unicast.hosts: [“127.0.0.1”] discovery.zen.minimum_master_nodes: 2
gateway.recover_after_nodes: 2
cluster.routing.allocation.awareness.attributes: rack_id
cluster.routing.allocation.same_shard.host: true

Node2 esetén:

cluster.name: es-test1
node.name: bigmachine1-node-2
node.attr.rack_id: r1
path.data: /elk/node2/data
path.logs: /elk/node2/log
bootstrap.memory_lock: true
network.host: 127.0.0.1
http.port: 9201
discovery.zen.ping.unicast.hosts: [“127.0.0.1”]
discovery.zen.minimum_master_nodes: 2
gateway.recover_after_nodes: 2
cluster.routing.allocation.awareness.attributes: rack_id
cluster.routing.allocation.same_shard.host: true

Az egy hoston belüli két node indításához le kell másolni a /etc/init.d/elasticsearch wrappert két példányban elasticseach-node1 és elasticsearch-node2 néven ugyanabban a könyvtárban. A két fileban a következőket kell módosítani: CONF_DIR=”/elk/nodeX/config” pidfile=”$PID_DIR/${prog}-nodeX.pid” Ezt követően az első node indítható: /etc/init.d/elasticsearch-node1 start Sikeres indítás esetén ellenőrizendő:
[root@ip init.d]# ps xfa|grep elastic
4300 pts/0 S+ 0:00 \_ grep --color=auto elastic
4117 ? Sl 0:10 /usr/lib/jvm/jre/bin/java -Xms250m -Xmx250m -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -server -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -Djdk.io.permissionsUseCanonicalPath=true -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j.skipJansi=true -XX:+HeapDumpOnOutOfMemoryError -Des.path.home=/usr/share/elasticsearch -cp /usr/share/elasticsearch/lib/elasticsearch-5.1.2.jar:/usr/share/elasticsearch/lib/* org.elasticsearch.bootstrap.Elasticsearch -p /var/run/elasticsearch/elasticsearch-node1.pid -d -Edefault.path.logs=/var/log/elasticsearch-Edefault.path.data=/var/lib/elasticsearch-Edefault.path.conf=/elk/node1/config

 
Ellenőrzés:
curl -XGET “http://localhost:9200/_search?pretty=true&q=*:*”
Erre eredményként ezt kell kapni:
“type” : “cluster_block_exception”,
“reason” : “blocked by: [SERVICE_UNAVAILABLE/1/state not recovered / initialized];”
Az exception oka, hogy jelenleg még csak egy node fut, holott a minimum master node beállítás legalább két aktív nodeot követ meg. Ennek kezelésére lehet indítani a második node-ot:
/etc/init.d/elasticsearch-node2 start
Ennek hatására a következő üzenetnek kell megjelennie, a node1 logjában:

[2017-03-04T08:34:34,392][INFO ][o.e.c.s.ClusterService ] [bigmachine1-node-1] new_master {bigmachine1-node-1}{2EUWX0KmQzWO3F_sTw64PA}{g5iuPt8_RV6Obtj5dhel4Q}{127.0.0.1}{127.0.0.1:9300}{rack=r1}, added {{bigmachine1-node-2}{rgvnf7MOSpKFKUgPhPUQAg}{i9JzciilSkKdTl1e8pS1zA}{127.0.0.1}{127.0.0.1:9301}{rack=r1},}, reason: zen-disco-elected-as-master ([1] nodes joined)[{bigmachine1-node-2}{rgvnf7MOSpKFKUgPhPUQAg}{i9JzciilSkKdTl1e8pS1zA}{127.0.0.1}{127.0.0.1:9301}{rack=r1}] [2017-03-04T08:34:34,566][INFO ][o.e.g.GatewayService ] [bigmachine1-node-1] recovered [0] indices into cluster_state

commercial break...

Az üzenet szerint a második node elindult és a két node közösen már “recovered” állapotba helyezte a clustert. A korábbi curl query már nem ad hibát és ekkor már a cluster health is lekérhető:

[root@ip init.d]# curl -XGET "http://localhost:9200/_cluster/health?pretty=true"
{
"cluster_name" : "es-test1",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 0,
"active_shards" : 0,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}

Nodeok állapotának lekérése:

[root@ip init.d]# curl -XGET "http://localhost:9200/_cat/nodes?pretty=true&v"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 34 93 5 0.00 0.03 0.00 mdi * bigmachine1-node-1
127.0.0.1 24 93 5 0.00 0.03 0.00 mdi - bigmachine1-node-2

Annak vizsgálata érdekében, hogy működik az egy gépen belüli shard allocation védelem (tehát hogy ne kerülhessen ugyanannak a gépnek két nodejára ugyanannak az indexnek a primary és replica shardja), hozzunk létre egy teszt indexet:

[root@ip config]# curl -XPUT "http://localhost:9200/testidx/testtype/001" -d '{"a":1}'
{"_index":"testidx","_type":"testtype","_id":"001","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true}

A parancs hatására létrejött az index és elhelyezésre került a dokumentum. Látszik viszont, hogy csak 1 nodeon sikerült a művelet. Az eredményről pontosabban győződhetünk meg az alábbi paranccsal:

[root@ip-172-30-0-45 config]# curl -XGET "http://localhost:9200/_cat/shards?pretty=true&v"
index shard prirep state docs store ip node
testidx 2 p STARTED 0 130b 127.0.0.1 bigmachine1-node-1
testidx 2 r UNASSIGNED
testidx 4 p STARTED 1 3.1kb 127.0.0.1 bigmachine1-node-1
testidx 4 r UNASSIGNED
testidx 1 p STARTED 0 130b 127.0.0.1 bigmachine1-node-2
testidx 1 r UNASSIGNED
testidx 3 p STARTED 0 130b 127.0.0.1 bigmachine1-node-2
testidx 3 r UNASSIGNED
testidx 0 p STARTED 0 130b 127.0.0.1 bigmachine1-node-1
testidx 0 r UNASSIGNED

Látható, hogy létrejött az alapértelmezett 5:1-es shard allokációs szabálynak megfelelően 5 primary shard a “testidx” indexből, melyek vegyesen kerültek allokálásra a cluster két nodeján. Regisztrálásra került továbbá 5 “r” replika shard is, ezek azonban nincsennek allokálva, hiszen a szabályrendszer szerint ugyanazon fizikai gépen futó nodeokon nem lehet létrehozni ugyanannak az indexnek a primary és replika shardját. Az UNASSIGNED státusz azonnal megszűnik amint a clusterbe becsatlakoznak olyan nodeok amelyek nem ugyanezen a fizikai szerveren találhatók. Ennek megtörténtéig a cluster állapota viszont “yellow”-ra vált, hiszen a cluster nem tudja biztosítani az indexek magas rendelkezésre állását:

[root@ip-172-30-0-45 config]# curl -XGET "http://localhost:9200/_cluster/health?pretty=true"
{
"cluster_name" : "es-test1",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 5,
"active_shards" : 5,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 5,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 50.0
}

***FONTOS: A konfigurációban jelenleg két olyan rész is található ami azt hivatott biztosítani, hogy ne kerülhessen fizikailag egy gépre ugyanazon index primary és replica shardja, ez pedig egyrészt a rack_id és az ehhez kapcsolódó cluster allocation awareness, másrészt pedig az “allocation.same_shard.host” cluster parancs, ami azt hivatott biztosítani, hogy az elasticsearch az induláskor meggyőződjön arról, hogy az adott gépen fizikailag fut-e másik node.
Az utóbbi beállítás szigorú szabály ami miatt unallocatedbe kerülnek a replica shardok.
Ezzel szemben az előbbi (rack_id és awareness) viszont egy sokkal gyengébb szabály ami csak annyit eredményez, hogy a cluster, ha teheti, akkor nem allokál primary és replica shardot ugyanabba a rack_id-ba. Utóbbi beállítás csak fizikalilag közös gépen futtatott nodeok esetén működik, előbbi (allocation.same_shard) viszont akár logikailag összefüggő (pl. egy adott hoston futó VM-ekben futó elasticsearch) esetén is biztosítja ezt a védelmet, azonban csak abban az esetben ha erre lehetősége is van. Tehát áll rendelkezésre olyan alternatíva a cluster routing servicenek amikor a replikákat elhelyezheti egy másik rack_id-val rendelkező cluster nodeon vagy nodeokon.

Bookmark the permalink.

Szólj hozzá: