Аптымізацыя нагрузкі на Highload-праекце з дапамогай ElasticSearch

Прывітанне, Хабр! Мяне клічуць Максім Васільеў, я працую аналітыкам і мэнэджэрам праектаў у FINCH. Сёння я хацеў бы расказаць, як з дапамогай ElasticSearch, мы змаглі апрацаваць 15 запытаў за 6 хвілін і аптымізаваць штодзённыя нагрузкі на сайце аднаго з нашых кліентаў. На жаль, давядзецца абысціся без імёнаў, бо ў нас NDA, спадзяемся, што змест артыкула ад гэтага не пацерпіць. Let`s go.

Як уладкованы праект

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

Аптымізацыя нагрузкі на Highload-праекце з дапамогай ElasticSearch

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

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

Кароткая перадгісторыя

Першапачаткова ў якасці адзінага сховішчы дадзеных мы выкарыстоўвалі PostgreSQL. Яго стандартныя для СКБД перавагі: наяўнасць транзакцый, развітая мова выбаркі даных, шырокі інструментарый для інтэграцыі; у спалучэнні з добрай прадукцыйнасцю даволі доўга задавальнялі нашы патрэбы.

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

Для разумення, гадавая колькасць сеансаў у 2017 годзе толькі на дэсктопным сайце - 131 млн. За 2018 - 125 млн. 2019 зноў 130 млн. Дадайце туды яшчэ 100-200 млн ад мабільнай версіі сайта і мабільнага прыкладання, і вы атрымаеце каласальную колькасць запытаў.

З ростам праекта, Postgres перастаў спраўляцца з нагрузкай, мы не паспявалі – з'явілася вялікая колькасць разнастайных запытаў, пад якія мы не змаглі стварыць дастатковую колькасць індэксаў.

Мы разумелі, што ёсць неабходнасць у іншых сховішчах дадзеных, якія б забяспечылі наш запатрабаванні і знялі нагрузку з PostgreSQL. У якасці магчымых варыянтаў разглядалі Elasticsearch і MongoDB. Апошні прайграваў па наступных пунктах:

  1. Павольная хуткасць індэксацыі з ростам аб'ёму даных у індэксах. У Elastic хуткасць не залежыць ад аб'ёму дадзеных.
  2. Няма паўнатэкставага пошуку

Так мы абралі для сябе Elastic і падрыхтаваліся да пераходу.

Пераход на Elastic

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

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

Калі казаць па арганізацыю, то ў Postgres у нас ляжыць крыніца дадзеных як па карце, так і па навінах, а ў Elastic робяцца Snapshot'ы ад арыгінальных дадзеных. Справа ў тым, што першапачаткова Postgres не спраўляўся з пошукам па ўсіх крытэрыях. Мала таго, што было шмат індэксаў, яны маглі яшчэ і перасякацца, таму планавальнік Postgres губляўся і не разумеў які індэкс яму выкарыстоўваць.

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

3. Потым мы перанеслі апрацоўку транзакцый. Карыстальнікі могуць купляць пэўны тавар на сайце і ўдзельнічаць у розыгрышы прызоў. Пасля такіх пакупак, мы апрацоўваем вялікую колькасць дадзеных, асабліва ў выходныя і святы. Для параўнання, калі ў звычайныя дні колькасць пакупак складае недзе 1,5-2 млн, то ў святы лічба можа дасягаць 53 млн.

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

перыядычнасць

Цяпер абнаўленні настроены падзейна, па наступных умовах:

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

Тут яшчэ раз варта сказаць аб плюсах Elastic. У Postgres падчас адпраўкі запыту, трэба чакаць пакуль ён сумленна апрацуе ўсе запісы. У Elastic можна адправіць 10 тыс. запісаў, і адразу пачаць працаваць, не чакаючы, пакуль запісы разыдуцца па ўсіх Shards. Вядома, нейкі Shard ці Replica могуць не ўбачыць дадзеныя адразу, але вельмі хутка ўсё будзе даступна.

Спосабы інтэграцыі

Ёсць 2 спосабу інтэграцыі з Elastic:

  1. Праз натыўны кліент па TCP. Натыўны драйвер паступова вымірае: яго перастаюць падтрымліваць, на ім вельмі няёмкі сінтаксіс. Таму мы яго практычна не выкарыстоўваем і стараемся поўнасцю адмовіцца ад яго.
  2. Праз HTTP інтэрфейс, у якім можна выкарыстоўваць як JSON запыты, так і сінтаксіс Lucene. Апошняе - тэкставы рухавічок, які выкарыстоўвае Elastic. У такім варыянце мы атрымліваем магчымасць Batch праз JSON-запыты па HTTP. Менавіта гэты варыянт мы імкнемся выкарыстоўваць.

Дзякуючы HTTP-інтэрфейсу мы можам выкарыстоўваць бібліятэкі, якія даюць асінхронную рэалізацыю HTTP кліента. Мы можам выкарыстоўваць перавагу Batch і асінхроннага API, што ў выніку дае высокую прадукцыйнасць, якая вельмі дапамагла ў дні буйной акцыі (пра гэта ніжэй)

Трохі лічбаў для параўнання:

  • Захаванне карыстальнікаў тых, хто атрымаў прызы ў Postgres у 20 патокаў без груповак: 460713 запісаў за 42 секунды
  • Elastic + рэактыўны кліент на 10 патокаў + batch на 1000 элементаў: 596749 запісаў за 11 секунд
  • Elastic + рэактыўны кліент на 10 патокаў + batch на 1000 элементаў: 23801684 запісаў за 4 хвіліны

Цяпер мы напісалі менеджэр запытаў па HTTP, які будуе JSON, як Batch/не Batch і адпраўляе праз любы HTTP кліент па-за залежнасцю ад бібліятэкі. Гэтак жа можна выбіраць сінхронна ці асінхронна адпраўляць запыты.

У некаторых інтэграцыях мы ўсё яшчэ выкарыстоўваем афіцыйны transport client, але гэта толькі пытанне найблізкага рэфактарынгу. Пры гэтым для апрацоўкі выкарыстоўваецца ўласны кліент, пабудаваны на базе Spring WebClient.

Аптымізацыя нагрузкі на Highload-праекце з дапамогай ElasticSearch

Вялікая акцыя

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

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

У пачатку 2019 года мы вырашылі, што трэба ElasticSearch. Цэлы год мы арганізоўвалі апрацоўку атрымоўваных дадзеных у Elastic і іх выдачу ў api мабільнага прыкладання і сайта. У выніку на наступны год падчас акцыі мы апрацавалі. 15 131 783 запісаў за 6 хвілін.

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

Заключэнне/высновы

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

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

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

⌘⌘⌘

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

Крыніца: habr.com

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