Nem visz rá a lélek, hogy ez a címet magyarul akarjam leírni… De miért is érdekes a zero downtime egy NoSQL megoldás kapcsán. A héten került megrendezésre a HOUG nevű szakmai konferencia Siófokon, ami a hazai Oracle felhasználók éves nagy konferenciája, ahol megannyi sales fókuszú előadás mellett bőven akadt szakmai előadás is, melyek egy része bőségesen adott gondolkodnivalót nekem is. Az egyik előadáson lőttem az alábbi ábrát (remélem nem kövez meg senki amiért nyúlom…):
Szóval három kimelet kihívás. Ezek közül amivel ebben a postban szerenték foglalkozni, az a harmadik: a rendelkezésre állás. Az ábrán is szerepel a bűvös öt-kilences (99.999%) rendelkezésre állás, ami ugye annyit jelent, hogy az adott rendszer illetve alkalmazás éves szinten maximum 5 percet állhat. Ez ugye a mai közösségi világ és “digitális felfordulás” (igen… ezt a kifejezést is most lőttem, de nagyon tetszik) által vezérelt világ MINIMÁLIS elvárása a magas rendelkezésre állásra.
Az nem lehet kérdés, hogy infrastrukturális szempontból képtelenség egy alkalmazásnak 99.999%-os rendelkezésre állást biztosítani, aki ezt vállalja, az hazudik. Erre egy alkalmazás csak akkor képes, ha ezt ALKALMAZÁS szinten oldják meg. Az Elasticsearch esetén annak tervezéséből fakadóan adott a zero downtime működés, hiszen minden cluster beállítást lehet élő cluster esetén konfigurálni, a cluster elemek tetszőlegesen hozzáadhatók és elvehetők menet közben. Két olyan esemény értelmezhető, ahol viszont jogosan felvetődhet a zero downtime sérülése, ezek: reindex során az új index elérése alkalmazásból, továbbá logikusan az ES cluster nodejainak verzióváltása:
Reindex kezelése index aliasokkal
A reindexing esemény akkor következik be, ha egy meglévő index mappingjét akarjuk módosítani. Itt nyilván nem arról beszélünk amikor egy új mezőt vagy új index típust akarunk beszúrni, hanem arról, amikor egy meglévő mezőt vagy akár objektum struktúrát (pl. nested object esetén) akarunk úgy módosítani, hogy az kihat a meglévő adatokra. Ennél is hétköznapibb eset, amikor pl egy meglévő fieldet szeretnél analizáltról nem analizáltra (vagy fordítva) rakni, függően attól, hogy annak tartalmát full text search vagy teljes mintaillesztéses kereséssel szeretnénk értelmezni. Itt a zero downtime nem is feltétlenül az ES szempontjából releváns, hanem sokkal inkább az ES-t használó alkalmazás szempontjából. Hiszen, ha változik az index struktúra, akkor változik az index neve és ezáltaltal az alkalmazásnak is le kell tudnia kezelni a változást. Ennek a kezelésére hozták létre az index alias (_alias, _aliases) támogatást.
Ehhez persze illik felkészülni erre már az alkalmazás és az ES indexek tervezésekor. Érdemes az indexeket annak mappingja alapján verziózni (pl a nevének a végén: _vX jelöléssel), továbbá fixen létrehozni hozzá egy _alias taget. Ezt követően törekeni kell arra, hogy az alkalmazásból mindig az aliasra hivatkozzunk, soha ne magára az eredeti indexre.
[commercial_break]Amit ezzel nyerünk az az, hogy reindexing során (amikor pl változik a mapping), akkor elemi (atomic) szinten tudjuk módositan úgy az indexet, hogy az alkalamzás ebből semmit ne vegyen észre és kiesés se történjen. Konkrét példa:
POST /_aliases { "actions": [ { "remove": { "index": "my_index_v1", "alias": "my_index" }}, { "add": { "index": "my_index_v2", "alias": "my_index" }} ] }
Ez az utasítás garantálja, hogy a meglévő my_index_v1-ről úgy váltjuk át a my_index_v2-re a meglévő “my_index” aliast, hogy ebből az azt használó alkalmazások semmit nem érzékelnek, mivel a művelet elemi, nem megszakítható műveleten keresztül hajtódik végre.
ES cluster verzióváltás
Na ez már egy sokkal érdekesebb téma. Úgy upgradelni egy ES cluster nodejainak verzióját, hogy közben a clustert nem állítjuk le… Ez önmagában zordul hangozhat, de koránt sem az. Az ES-t úgy tervezék, hogy ezt meg lehessen csinálni. Ez alól kivételt jelent a főverzió váltás (1.X->2.X, 2.X->5.X), bár arra is vannak trükkök, hogy ezen főverzió váltásokat is meg lehessen úszni kiesésmentesen, de itt érdemesebb inkább scheduled downtime-ot alkalmazni, hiszen ilyenkor újra kell indexelni mindent. Ezekhez a főverzió váltásokhoz az elasticsearch csapata biztosít migrációs eszközöket: https://github.com/elastic/elasticsearch-migration
Amikor nem főverzió váltásról beszélünk, hanem pl 5.1-ről 5.2 vagy 5.X váltásról, akkor viszont koránt sem kell aggódnunk. Egy konkrétumra viszont érdemes nagyon figyelni, ez pedig a Deprecation Logging. Ez egy nagyon okos kis funkciója az ES-nek, aminek az eredménye közvetlenül a cluster log könyvtárában jön létre. Lényegében azt naplózza, hogy milyen olyan funkciókat használunk az ES-ben, ami egyébként már kivezetésre van ítélve és a soron következő verziókban akár meg is szűnik. Ha ez a logunk üres, akkor mehet a zero downtime upgrade. Ennek folyamata: nodeonként leállíjuk a clustert (green health esetén!!!), majd upgrade, majd elindít és mehetünk is a következő nodera.
Egy konkrét példa a menet közbeni upgradere:
root@ip-172-30-0-45 elk]# curl -XGET "http://172.30.0.45:9200/_cat/nodes?v&h=v"
5.2.2
5.2.2
5.1.2
Látható, hogy a nodeok közül kettő már 5.2.2-es verzión van, miközben az egyik még 5.1.2-es. Amire viszont érdemes figyelni, hogy az upgrade során a nodeokat egyrészt le kell állítani (ez ugye csak a green health esetén javasolt), másrészt viszont beállítástól függően az upgrade során elindulhat az index rebalance/rerouting ami feleslegesen terhelheti az egész ES clustert, ami akár performancia gondokat is okozhat az ugprade alatt. Éppen ezért érdemes a node upgradek ideje alatt kikapcsolni a reroutingot:
curl -X PUT http://hostname:9200/_cluster/settings -d
'{"transient":{"cluster.routing.allocation.disable_allocation": true}}'
A sikeres és teljeskörű upgrade után (amikor a master node is már az új verzión van, akkor egyszerűen csak “false”-ra kell állítni a fentebbi transient cluster settinget amivel újra engedélyezzük a shard allokációt a clusteren belül.