Кластар Elasticsearch на 200 ТБ+

Кластар Elasticsearch на 200 ТБ+

З Elasticsearch сутыкаюцца многія. Але што адбываецца, калі хочаш з яго дапамогай захоўваць логі "ў асабліва буйным аб'ёме"? Ды яшчэ і бязбольна перажываць адмову любога з некалькіх дата-цэнтраў? Які варта рабіць архітэктуру, і на якія падводныя камяні натыкнешся?

Мы ў Аднакласніках вырашылі пры дапамозе elasticsearch вырашыць пытанне лог-мэнэджменту, а зараз дзелімся з Хабрам досведам: і пра архітэктуру, і пра падводныя камяні.

Я - Пётр Зайцаў, працую сістэмным адміністратарам у Аднакласніках. Да гэтага таксама быў адмінам, працаваў з Manticore Search, Sphinx search, Elasticsearch. Магчыма, калі з'явіцца яшчэ які-небудзь …search, верагодна буду працаваць і з ім. Таксама ўдзельнічаю ў шэрагу апенсорсных праектаў на добраахвотнай аснове.

Калі я прыйшоў у Аднакласнікі, то неабдумана сказаў на сумоўі, што ўмею працаваць з Elasticsearch. Пасля таго, як асвоіўся і парабіў нейкія просценькія задачы, мне падарылі вялікую задачу па рэфармаванні сістэмы лог-мэнэджменту, якая існавала на той момант.

Патрабаванні

Патрабаванні да сістэмы былі сфармуляваны наступным чынам:

  • У якасці фронтэнда павінен быў выкарыстоўвацца Graylog. Таму што ў кампаніі ўжо быў досвед выкарыстання гэтага прадукта, праграмісты і тэстыравальнікі яго ведалі, ён ім быў звыклы і зручны.
  • Аб'ём дадзеных: у сярэднім 50-80 тысяч паведамленняў у секунду, але калі нешта ламаецца, то трафік нічым не абмежаваны, гэта можа быць 2-3 мільёны радкоў у секунду.
  • Абмеркаваўшы з заказчыкамі патрабаванні па хуткасці апрацоўкі пошукавых запытаў, мы зразумелі, што тыповы патэрн выкарыстання падобнай сістэмы такі: людзі шукаюць логі свайго дадатку за апошнія два дні і не хочуць чакаць выніку на сфармуляваны запыт больш за секунду.
  • Адміны настойвалі на тым, каб сістэма пры неабходнасці лёгка маштабавалася, не патрабуючы ад іх глыбокай увагі ў тое, як яна ўладкованая.
  • Каб адзіная задача па абслугоўванні, якая гэтым сістэмам патрабавалася перыядычна - гэта мяняць нейкае жалеза.
  • Акрамя таго, у Аднакласніках ёсць выдатная тэхнічная традыцыя: любы сэрвіс, які мы запускаем, павінен перажываць адмову дата-цэнтра (раптоўная, незапланаваная і абсалютна ў любы час).

Апошняе патрабаванне ў рэалізацыі гэтага праекта далося нам найбольшай крывёй, пра што я яшчэ раскажу падрабязней.

Серада

Мы працуем на чатырох дата-цэнтрах, пры гэтым дата-ноды Elasticsearch могуць размяшчацца толькі ў трох (па шэрагу нетэхнічных прычын).

У гэтых чатырох дата-цэнтрах знаходзяцца прыкладна 18 тысяч розных крыніц логаў - жалязякі, кантэйнеры, віртуальныя машыны.

Важная асаблівасць: запуск кластара адбываецца ў кантэйнерах Падман не на фізічных машынах, а на уласным хмарным прадукце one-cloud. Кантэйнерам гарантуецца 2 ядры, аналагічных 2.0Ghz v4 з магчымасцю ўтылізацыі астатніх ядраў, у выпадку іх прастою.

Іншымі словамі:

Кластар Elasticsearch на 200 ТБ+

Тапалогія

Агульны выгляд рашэння мне першапачаткова бачыўся наступным чынам:

  • 3/4 VIP стаяць за А-рэкордам дамена Graylog, гэта адрас, на які адсылаюцца логі.
  • кожны VIP уяўляе з сябе балансавальнік LVS.
  • Пасля яго логі трапляюць на батарэю Graylog, частка дадзеных ідзе ў фармаце GELF, частка ў фармаце syslog.
  • Далей усё гэта вялікімі батча пішацца ў батарэю з каардынатараў Elasticsearch.
  • А яны, у сваю чаргу, дасылаюць запыты на запіс і чытанне на рэлевантныя дата-ноды.

Кластар Elasticsearch на 200 ТБ+

тэрміналогія

Магчыма, не ўсе падрабязна разбіраюцца ў тэрміналогіі, таму хацелася б крыху спыніцца на ёй.

У Elasticsearch ёсць некалькі тыпаў нод – master, coordinator, data node. Ёсць яшчэ два іншых тыпу для розных пераўтварэнняў логаў і сувязі розных кластараў паміж сабой, але мы выкарыстоўвалі толькі пералічаныя.

Майстар
Пінг ўсё прысутныя ў кластары ноды, падтрымлівае актуальную карту кластара і распаўсюджвае яе паміж нодамі, апрацоўвае падзейную логіку, займаецца рознага роду cluster wide housekeeping.

каардынатар
Выконвае адну-адзіную задачу: прымае запыты ад кліентаў на чытанне ці запіс і маршрутызуе гэты трафік. У выпадку, калі запыт на запіс, хутчэй за ўсё, ён спытае master, у які шард рэлевантнага азначніка яму гэта пакласці, і перанакіруе запыт далей.

Data node
Захоўвае дадзеныя, выконвае, якія прылятаюць з-за, пошукавыя запыты і аперацыі над размешчанымі на ёй шардамі.

Шэралог
Гэта нешта накшталт сплаву Kibana з Logstash у ELK-стэке. Graylog сумяшчае ў сабе і UI і канвеер па апрацоўцы логаў. Пад капотам у Graylog працуюць Kafka і Zookeeper, якія забяспечваюць складнасць Graylog як кластара. Graylog умее кэшаваць логі (Kafka) на выпадак недаступнасці Elasticsearch і паўтараць няўдалыя запыты на чытанне і запіс, групаваць і маркіраваць па задаваных правілах логі. Як і Logstash, Graylog мае функцыянальнасць па мадыфікацыі радкоў перад запісам у Elasticsearch.

Акрамя таго, у Graylog ёсць убудаваны service discovery, які дазваляе на аснове адной даступнай ноды Elasticsearch атрымаць усю карту кластара і адфільтраваць яе па вызначаным тэгу, што дае магчымасць накіроўваць запыты на пэўныя кантэйнеры.

Візуальна гэта выглядае прыкладна так:

Кластар Elasticsearch на 200 ТБ+

Гэта скрыншот з канкрэтнага інстансу. Тут мы па пошукавым запыце выбудоўваем гістаграму, выводзім рэлевантныя радкі.

Індэксы

Вяртаючыся да архітэктуры сістэмы, я б жадаў падрабязней спыніцца на тым, як мы будавалі мадэль азначнікаў, каб усё гэта працавала карэктна.

На прыведзенай раней схеме гэта самы ніжні ўзровень: Elasticsearch data nodes.

Індэкс – гэта вялікая віртуальная сутнасць, якая складаецца з шардаў Elasticsearch. Сам па сабе кожны з шардаў з'яўляецца ні чым іншым, як Lucene index. А кожны Lucene index, у сваю чаргу, складаецца і аднаго ці больш сегментаў.

Кластар Elasticsearch на 200 ТБ+

Пры праектаванні мы меркавалі, што для забеспячэння патрабавання па хуткасці чытання на вялікім аб'ёме дадзеных нам неабходна раўнамерна «размазаць» гэтыя дадзеныя па дата-нодам.

Гэта вылілася ў тое, што колькасць шардаў на індэкс (з рэплікамі) у нас павінна быць строга роўнай колькасці дата-нод. Па-першае, для таго, каб забяспечыць replication factor, роўны двум (гэта значыць мы можам страціць палову кластара). А, па-другое, для таго, каб запыты на чытанне і запіс апрацоўваць, прынамсі, на палове кластара.

Час захоўвання мы вызначылі спачатку як 30 дзён.

Размеркаванне шардаў можна прадставіць графічна наступным чынам:

Кластар Elasticsearch на 200 ТБ+

Увесь цёмна-шэры прастакутнік цалкам - гэта індэкс. Левы чырвоны квадрат у ім - гэта primary-шард, першы ў індэксе. А блакітны квадрат - гэта replica-шард. Яны знаходзяцца ў розных дата-цэнтрах.

Калі мы дадаем яшчэ адзін шард, ён пападае ў трэці дата-цэнтр. І, нарэшце, мы атрымліваем вось такую ​​структуру, якая забяспечвае магчымасць страты ДЦ без страты кансістэнтнасці дадзеных:

Кластар Elasticsearch на 200 ТБ+

Ратацыю індэксаў, г.зн. стварэнне новага азначніка і выдаленне найболей старога, мы зрабілі роўнай 48 гадзін (па патэрне выкарыстання азначніка: па апошніх 48 гадзінам шукаюць часцей за ўсё).

Такі інтэрвал ратацыі індэксаў звязаны з наступнымі прычынамі:

Калі на пэўную дата-ноду прылятае пошукавы запыт, то, з пункта гледжання перформансу выгодней, калі апытваецца адзін шард, калі яго памер супастаўны з памерам хіпа ноды. Гэта дазваляе трымаць "гарачую" частку індэкса ў хіпе і хутка да яе звяртацца. Калі "гарачых частак" становіцца шмат, то дэградуе хуткасць пошуку па індэксе.

Калі нода пачынае выконваць пошукавы запыт на адным шардзе, яна вылучае кол-ць тредов, роўнае колькасці гіпертрэдынгавых ядраў фізічнай машыны. Калі пошукавы запыт закранае вялікую колькасць шардоў, то колькасць трэдаў расце прапарцыйна. Гэта дрэнна адбіваецца на хуткасці пошуку і негатыўна адбіваецца на індэксацыі новых дадзеных.

Каб забяспечыць неабходны latency пошуку, мы вырашылі выкарыстоўваць SSD. Для хуткай апрацоўкі запытаў машыны, на якіх размяшчаліся гэтыя кантэйнеры, павінны былі валодаць сама меней 56 ядрамі. Лічба ў 56 абраная як умоўна-дастатковая велічыня, якая вызначае колькасць трэдаў, якія будзе спараджаць Elasticsearch падчас працы. У Elasitcsearch шматлікія параметры thread pool напроста залежаць ад колькасці даступных ядраў, што ў сваю чаргу прама ўплывае на неабходнае кол-во нод у кластары па прынцыпе "менш ядраў - больш нод".

У выніку ў нас атрымалася, што ў сярэднім шард важыць недзе 20 гігабайт, і на 1 індэкс прыпадае 360 шардаў. Адпаведна, калі мы іх раціруем раз на 48 гадзін, то ў нас іх 15 штук. Кожны індэкс месціць у сябе дадзеныя за 2 дні.

Схемы запісу і чытання даных

Давайце разбяромся, як у гэтай сістэме запісваюцца дадзеныя.

Дапушчальны, у нас з Graylog прылятае ў каардынатар нейкі запыт. Напрыклад, мы хочам праіндэксаваць 2-3 тысячы радкоў.

Каардынатар, атрымаўшы ад Graylog запыт, апытвае майстар: "У запыце на індэксацыю ў нас быў канкрэтна паказаны індэкс, але ў які шард гэта пісаць – не пазначана".

Master адказвае: "Запішы гэтую інфармацыю ў шард нумар 71", пасля чаго яна накіроўваецца непасрэдна ў рэлевантную дата-ноду, дзе знаходзіцца primary-shard нумар 71.

Пасля гэтага лог транзакцый рэплікуецца на replica-shard, які знаходзіцца ўжо ў іншым дата-цэнтры.

Кластар Elasticsearch на 200 ТБ+

З Graylog у каардынатар прылятае пошукавы запыт. Каардынатар перанакіроўвае яго па азначніку, пры гэтым Elasticsearch па прынцыпе round-robin размяркоўвае запыты паміж primary-shard і replica-shard.

Кластар Elasticsearch на 200 ТБ+

Ноды ў колькасці 180 штук адказваюць нераўнамерна, і, пакуль яны адказваюць, каардынатар збірае інфармацыю, якую ў яго ўжо "выплюнулі" хутчэйшыя дата-ноды. Пасля гэтага, калі альбо ўся інфармацыя прыйшла, альбо па запыце дасягнуць таймаўт, аддае ўсё непасрэдна кліенту.

Уся гэтая сістэма ў сярэднім адпрацоўвае пошукавыя запыты па апошніх 48 гадзінах за 300-400ms, выняткоўваючы тыя запыты, якія з leading wildcard.

«Кветачкі» з Elasticsearch: настройка Java

Кластар Elasticsearch на 200 ТБ+

Каб усё гэта зарабіла так, як мы першапачаткова хацелі, мы вельмі доўга адладжвалі самыя разнастайныя рэчы ў кластары.

Першая частка выяўленых праблем была звязана з тым, як у Elasticsearch па дэфолце праднастроена Java.

Праблема першая
Мы назіралі вельмі вялікую колькасць паведамленняў аб тым, што ў нас на ўзроўні Lucene, калі запушчаны background job'ы, мерджы сегментаў Lucene завяршаюцца з памылкай. Пры гэтым у логах было бачна, што гэта OutOfMemoryError-памылка. Па тэлеметрыі мы бачылі, што хіп вольны, і не было зразумела, чаму гэтая аперацыя падае.

Высветлілася, што Мерджы Lucene-індэксаў адбываюцца па-за хіпам. А кантэйнеры даволі жорстка абмежаваны па спажываных рэсурсах. У гэтыя рэсурсы залазіў толькі хіп (значэнне heap.size было прыкладна роўна RAM), а нейкія off-heap аперацыі валіліся з памылкай алакацыі памяці, калі па нейкім чынніку не ўкладваліся ў тыя ~500MB, што заставаліся да ліміту.

Фікс быў даволі трывіяльным: даступны для кантэйнера аб'ём RAM павялічылі, пасля чаго забыліся аб тым, што такія праблемы ў нас увогуле былі.

Праблема другая
Дні праз 4-5 пасля запуску кластара мы заўважылі, што дата-ноды пачынаюць перыядычна вывальвацца з кластара і заходзіць у яго секунд праз 10-20.

Калі палезлі разбірацца, высветлілася, што гэтая самая off-heap памяць у Elasticsearch не кантралюецца практычна ніяк. Калі мы кантэйнеру падалі больш памяці, мы атрымалі магчымасць напаўняць direct buffer pools рознай інфармацыяй, і яна чысцілася толькі пасля таго, як запускаўся explicit GC са боку Elasticsearch.

У шэрагу выпадкаў гэтая аперацыя адбывалася даволі доўга, і за гэты час кластар паспяваў пазначыць гэтую ноду як ужо якая выйшла. Гэтая праблема добра апісана вось тут.

Рашэнне было наступным: мы абмежавалі Java магчымасць выкарыстоўваць асноўную частку памяці па-за хіпам пад гэтыя аперацыі. Мы лімітавалі яе да 16 гігабайт (-XX: MaxDirectMemorySize = 16g), дамогшыся таго, што explicit GC выклікаўся значна часцей, а адпрацоўваў значна хутчэй, перастаўшы тым самым дэстабілізаваць кластар.

Праблема трэцяя
Калі вы думаеце, што праблемы з «нодамі, якія пакідаюць кластар у самы непрадбачаны момант» на гэтым скончыліся, вы памыляецеся.

Калі мы канфігуравалі працу з індэксамі, мы спынілі свой выбар на mmapfs, каб скараціць час пошуку па свежых шардах з вялікай сегментаванасцю. Гэта было даволі грубіянскай памылкай, таму што пры выкарыстанні mmapfs файл маппится ў аператыўную памяць, а далей мы працуем ужо з mapped-файлам. З-за гэтага атрымліваецца, што пры спробе GC спыніць трэды ў дадатку мы вельмі доўга ідзем у safepoint, і па дарозе да яго дадатак перастае адказваць на запыты майстра аб тым, ці жывое яно. Адпаведна, master лічыць, што нода ў нас больш у кластары не прысутнічае. Пасля гэтага праз секунд 5-10 адпрацоўвае garbage collector, нода ажывае, зноў заходзіць у кластар і пачынае ініцыялізацыю шардаў. Усё гэта моцна нагадвала "прадакшэн, які мы заслужылі" і не падыходзіла для чаго-небудзь сур'ёзнага.

Каб пазбавіцца ад такіх паводзін, мы перш перайшлі на стандартны niofs, а пасля, калі з пятых версій Elastic адміграваць на шостыя, паспрабавалі hybridfs, дзе дадзеная праблема не прайгравалася. Падрабязней пра тыпы стрэсджа можна пачытаць тут.

Праблема чацвёртая
Потым была яшчэ вельмі цікавая праблема, якую мы лячылі рэкордна доўга. Мы лавілі яе 2-3 месяцы, таму што быў абсалютна незразумелы яе патэрн.

Часам у нас каардынатары сыходзілі ў Full GC, звычайна недзе пасля абеду, і адтуль ужо не вярталіся. Пры гэтым пры лагаванні затрымкі GC гэта выглядала так: у нас усё ідзе добра, добра, добра, а потым раз – і ўсё рэзка дрэнна.

Спачатку мы думалі, што ў нас ёсць злы юзэр, які запускае нейкі запыт, які выбівае каардынатар з працоўнага рэжыму. Вельмі доўга лагіравалі запыты, спрабуючы высветліць, што адбываецца.

У выніку высветлілася, што ў той момант, калі які-небудзь карыстач запускае велізарны запыт, і ён пападае на нейкі пэўны каардынатар Elasticsearch, некаторыя ноды адказваюць даўжэй, чым астатнія.

І той час, пакуль каардынатар чакае адказу ўсіх нод, ён збірае ў сабе вынікі, дасланыя з ужо адказалі нод. Для GC гэта азначае, што ў нас вельмі хутка мяняецца патэрн выкарыстання хіпа. І той GC, які мы выкарыстоўвалі, з гэтай задачай не спраўляўся.

Адзіны фікс, які мы знайшлі для таго, каб змяніць паводзіны кластара ў такой сітуацыі - міграцыя на JDK13 і выкарыстанне зборшчыка смецця Shenandoah. Гэта вырашыла праблему, каардынатары ў нас падаць перасталі.

На гэтым праблемы з Java скончыліся і пачаліся праблемы з прапускной здольнасцю.

Ягадкі з Elasticsearch: прапускная здольнасць

Кластар Elasticsearch на 200 ТБ+

Праблемы з прапускной здольнасцю азначаюць, што наш кластар працуе стабільна, але на піках кол-ва індэксуюцца дакументаў і ў момант манеўраў прадукцыйнасць недастатковая.

Першы сустрэты сімптом: пры нейкіх «выбухах» на прадакшэне, калі рэзка генеруецца вельмі вялікая колькасць логаў, у Graylog пачынае часта мільгаць памылка індэксацыі es_rejected_execution.

Гэта адбывалася з-за таго, што thread_pool.write.queue на адной дата-нодзе да моманту, як Elasticsearch здолее апрацаваць запыт на індэксацыю і закінуць інфармацыю ў шард на дыск, па дэфолце ўмее кэшаваць толькі 200 запытаў. І ў дакументацыі Elasticsearch аб гэтым параметры гаворыцца вельмі мала. Указваецца толькі лімітавае колькасць тредов і дэфолтны памер.

Зразумела, мы пайшлі круціць гэтае значэнне і высветлілі наступнае: менавіта ў нашым сетапе даволі добра кэшуецца да 300 запытаў, а большае значэнне багата тым, што мы зноў ляцім у Full GC.

Акрамя таго, паколькі гэта пачкі паведамленняў, якія прылятаюць у рамках аднаго запыту, то трэба было яшчэ падкруціць Graylog для таго, каб ён пісаў не часта і дробнымі батчамі, а велізарнымі батчамі або раз у 3 секунды, калі батч усё яшчэ не поўны. У такім выпадку атрымліваецца, што інфармацыя, якую мы ў Elasticsearch пішам, становіцца даступнай не праз дзве секунды, а праз пяць (што нас суцэль уладкоўвае), але памяншаецца колькасць ретраев, якія прыходзіцца зрабіць, каб прапіхнуць вялікі пачак інфармацыі.

Гэта асабліва важна ў тыя моманты, калі ў нас нешта дзесьці ўпала і люта пра гэта паведамляе, каб не атрымліваць цалкам заспамлены Elastic, а праз нейкі час - непрацаздольныя з-за буфераў ноды Graylog, якія забіліся.

Акрамя таго, калі ў нас адбываліся гэтыя самыя выбухі на прадакшэне, у нас прыходзілі скаргі ад праграмістаў і тэсціроўшчыкаў: у той момант, калі ім вельмі патрэбныя гэтыя логі, яны выдаюцца ім вельмі марудна.

Пачалі разбірацца. З аднаго боку, было зразумела, што і пошукавыя запыты, і запыты на індэксацыю адпрацоўваюць, па сутнасці, на адных і тых жа фізічных машынах, і так ці інакш пэўныя прасадкі будуць.

Але гэта можна было часткова абыйсці за рахунак таго, што ў шостых версіях Elasticsearch з'явіўся алгарытм, які дазваляе размяркоўваць запыты паміж рэлевантнымі дата-нодамі не па выпадковым прынцыпе round-robin (кантэйнер, які займаецца індэксацыяй і трымае primary-shard, можа быць вельмі заняты, там не будзе магчымасці адказаць хутка), а накіраваць гэты запыт на менш загружаны кантэйнер з replica-shard, які адкажа значна хутчэй. Іншымі словамі, мы дашлі да use_adaptive_replica_selection: true.

Карціна чытання пачынае выглядаць так:

Кластар Elasticsearch на 200 ТБ+

Пераход на гэты алгарытм дазволіў прыкметна палепшыць query time у тыя моманты, калі ў нас ішоў вялікі струмень логаў на запіс.

Нарэшце, асноўная праблема заключалася ў бязбольным вывядзенні дата-цэнтра.

Чаго мы хацелі ад кластара адразу пасля страты сувязі з адным ДЦ:

  • Калі ў нас у які адваліўся дата-цэнтры знаходзіцца бягучы master, то ён будзе пераабраны і пераедзе як роля на іншую ноду ў іншым ДЦ.
  • Майстар хутка выкіне з кластара ўсе недаступныя ноды.
  • На аснове пакінутых ён зразумее: у страціўшымся дата-цэнтры ў нас былі вось такія primary-шарды, хутка задумаецца кампліментарныя replica-шарды ў пакінутых дата-цэнтрах, і ў нас працягнецца індэксацыя дадзеных.
  • У выніку гэтага ў нас будзе плаўна дэградаваць прапускная здольнасць кластара на запіс і чытанне, аднак у цэлым усё будзе працаваць хоць і марудна, але стабільна.

Як высветлілася, хацелі мы чагосьці вось такога:

Кластар Elasticsearch на 200 ТБ+

А атрымалі наступнае:

Кластар Elasticsearch на 200 ТБ+

Як так атрымалася?

У момант падзення дата-цэнтра ў нас вузкім месцам стаў майстар.

Чаму?

Справа ў тым, што ў майстры ёсць TaskBatcher, які адказвае за распаўсюджванне ў кластары пэўных задач, івэнтаў. Любое выйсце ноды, любое пасоўванне шарда з replica ў primary, любая задача на стварэнне дзесьці нейкага шарда – усё гэта пападае перш у TaskBatcher, дзе апрацоўваецца паслядоўна і ў адзін струмень.

У момант вываду аднаго дата-цэнтра атрымлівалася, што ўсе дата-ноды ў тых, хто выжыў, дата-цэнтрах лічылі сваім абавязкам паведаміць майстру «у нас згубіліся такія-то шарды і вось такія дата-ноды».

Пры гэтым дата-ноды, якія выжылі, засылалі ўсю гэтую інфармацыю бягучаму майстру і спрабавалі дачакацца пацверджання, што ён яе прыняў. Гэтага яны не чакалі, бо майстар атрымліваў задачы хутчэй, чым паспеў адказваць. Ноды па таймаўце паўтаралі запыты, а майстар у гэты час ужо нават не спрабаваў адказваць на іх, а быў цалкам паглынуты задачай сартавання запытаў па прыярытэтнасці.

У тэрмінальным выглядзе атрымлівалася, што дата-ноды спамілі майстры да таго, што ён сыходзіў у full GC. Пасля гэтага ў нас роля майстра пераязджала на нейкую наступную ноду, з ёй адбывалася абсалютна тое ж самае, і ў выніку кластар развальваўся цалкам.

Мы рабілі вымярэнні, і да версіі 6.4.0, дзе гэта было пафікшана, нам было дастаткова вывесці адначасова вывесці ўсяго толькі 10 дата-нод з 360 для таго, каб цалкам пакласці кластар.

Выглядала гэта прыкладна вось так:

Кластар Elasticsearch на 200 ТБ+

Пасля версіі 6.4.0, дзе паправілі гэты стрэмны баг, дата-ноды перасталі забіваць майстра. Але "разумнейшы" ён ад гэтага не стаў. А менавіта: калі мы выводзім 2, 3 ці 10 (любая колькасць, адрозная ад адзінкі) дата-нод, майстар атрымлівае нейкае першае паведамленне, якое кажа, што нода А выйшла, і спрабуе распавесці пра гэтую наду B, наду C, нодзе D.

І на бягучы момант з гэтым можна змагацца толькі ўстаноўкай тайм-аўту на спробы камусьці пра нешта расказаць, роўныя дзесьці 20-30 секундам, і такім чынам кіраваць хуткасцю вываду дата-цэнтра з кластара.

У прынцыпе, гэта ўкладваецца ў тыя патрабаванні, якія першапачаткова былі прад'яўлены да канчатковага прадукта ў рамках праекта, але з пункту гледжання "чыстай навукі" гэта баг. Які, дарэчы, быў паспяхова пафіксаваны распрацоўшчыкамі ў версіі 7.2.

Прычым, калі нейкая дата-нода выходзіла, атрымлівалася, што распаўсюдзіць інфармацыю аб яе выхадзе важней, чым расказаць усяму кластару, што на ёй знаходзіліся вось такія primary-shard (каб задумаць replica-shard у іншым дата-цэнтры ў primary, і ў іх можна было пісаць інфармацыю).

Таму, калі ўжо ўсё "адгрымела", якія выйшлі дата-ноды не маркіруюцца як stale неадкладна. Адпаведна, мы вымушаныя чакаць, калі адтаймаўцяцца ўсе пінгі да тых, хто выйшаў дата-нод і толькі пасля гэтага наш кластар пачынае распавядаць аб тым, што там, там і там трэба працягнуць запіс інфармацыі. Больш падрабязна можна пачытаць пра гэта тут.

У выніку аперацыя вываду дата-цэнтра ў нас сёння займае каля 5 хвілін за гадзіну пік. Для такой вялікай і непаваротлівай махіны гэта даволі добры вынік.

У выніку мы прыйшлі да наступнага рашэння:

  • У нас 360 дата-нод з дыскамі на 700 гігабайт.
  • 60 каардынатараў для роўтынгу трафіку па гэтых самых дата-нодах.
  • 40 майстроў, якія ў нас засталіся як нейкая спадчына з часоў версій да 6.4.0 - каб перажыць выснову дата-цэнтра, мы маральна былі гатовыя страціць некалькі машын, каб гарантавана нават пры горшым сцэнары мець кворум майстроў
  • Любыя спробы сумяшчэння роляў на адным кантэйнеры ў нас упіраліся ў тое, што рана ці позна нода ламалася пад нагрузкай.
  • Ва ўсім кластары выкарыстоўваецца heap.size, роўны 31 гігабайту: усе спробы паменшыць памер прыводзілі да таго, што на цяжкіх пошукавых запытах з leading wildcard альбо забіваў нейкія ноды, альбо прыбіваўся circuit breaker у самім Elasticsearch.
  • Акрамя таго, для забеспячэння прадукцыйнасці пошуку мы імкнуліся трымаць колькасць аб'ектаў у кластары мінімальна магчымым, каб апрацоўваць як мага менш падзей у самым вузкім месцы, якое ў нас атрымалася ў майстры.

Напрыканцы аб маніторынгу

Каб усё гэта працавала так, як задумвалася, мы маніторым наступнае:

  • Кожная дата-нода паведамляе ў наша воблака, што яна ёсць, і на ёй знаходзяцца вось такія шарды. Калі мы недзе нешта тушым, кластар праз 2-3 секунды рапартуе, што ў цэнтры А мы патушылі ноду 2, 3, і 4 — гэта азначае, што ў іншых дата-цэнтрах мы ні ў якім разе не можам тушыць тыя. ноды, на якіх засталіся шарды ў адзіным экзэмпляры.
  • Ведаючы характар ​​паводзінаў майстра, мы вельмі ўважліва глядзім на колькасць pending-задач. Таму што нават адна якая завісла задача, калі своечасова не адтаймаўціцца, тэарэтычна ў нейкай экстранай сітуацыі здольная стаць тым чыннікам, па якой у нас не адпрацуе, дапушчальны, прамоўшэн replica-шарда ў primary, з-за чаго ўстане індэксацыя.
  • Таксама мы вельмі пільна глядзім на затрымкі garbage collector, таму што ў нас з гэтым ужо былі вялікія складанасці пры аптымізацыі.
  • Рэджэкты па трэдах, каб разумець загадзя, дзе знаходзіцца «бутэлькавае горла».
  • Ну і стандартныя метрыкі, тыпу heap, RAM і I/O.

Пры пабудове маніторынгу абавязкова трэба ўлічваць асаблівасці Thread Pool у Elasticsearch. Дакументацыя Elasticsearch апісвае магчымасці налады і дэфолтныя значэння для пошуку, індэксацыі, але цалкам замоўчвае аб thread_pool.management.Гэтыя трэды апрацоўваюць, у прыватнасці, запыты тыпу _cat/shards і іншыя аналагічныя, якія зручна выкарыстоўваць пры напісанні маніторынгу. Чым больш кластар, тым больш такіх запытаў выконваецца ў адзінку часу, а вышэйзгаданы thread_pool.management мала таго, што не прадстаўлены ў афіцыйнай дакументацыі, дык яшчэ і лімітаваны па дэфолце 5 трэдамі, што вельмі хутка утылізуецца, пасля чаго маніторынг перастае працаваць карэктна.

Што хочацца сказаць напрыканцы: у нас атрымалася! Мы здолелі даць нашым праграмістам і распрацоўшчыкам інструмент, які практычна ў любой сітуацыі здольны хутка і дакладна прадаставіць інфармацыю аб тым, што адбываецца на прадакшэне.

Так, гэта атрымалася даволі складана, але, тым не менш, нашы жаданні ўдалося абкласці ва ўжо існуючыя прадукты, якія пры гэтым не прыйшлося патчыць і перапісваць пад сябе.

Кластар Elasticsearch на 200 ТБ+

Крыніца: habr.com

Дадаць каментар