Прывітанне, Хабр! Мяне клічуць Максім Васільеў, я працую аналітыкам і мэнэджэрам праектаў у FINCH. Сёння я хацеў бы расказаць, як з дапамогай ElasticSearch, мы змаглі апрацаваць 15 запытаў за 6 хвілін і аптымізаваць штодзённыя нагрузкі на сайце аднаго з нашых кліентаў. На жаль, давядзецца абысціся без імёнаў, бо ў нас NDA, спадзяемся, што змест артыкула ад гэтага не пацерпіць. Let`s go.
Як уладкованы праект
На нашым бэкендзе мы ствараем сэрвісы, якія забяспечваюць працаздольнасць сайтаў і мабільнага прыкладання нашага кліента. Агульную структуру можна ўбачыць на схеме:
У працэсе працы мы апрацоўваем вялікую колькасць транзакцый: пакупак, выплат, аперацый з балансамі карыстальнікаў, па якіх захоўваем шмат логаў, а таксама імпартуем і экспартуем гэтыя дадзеныя ў знешнія сістэмы.
Таксама ідуць і зваротныя працэсы, калі мы атрымліваем дадзеныя ад кліента і перадаем іх карыстальнікам. Апроч гэтага яшчэ існуюць працэсы па працы з плацяжамі і бонуснымі праграмамі.
Кароткая перадгісторыя
Першапачаткова ў якасці адзінага сховішчы дадзеных мы выкарыстоўвалі PostgreSQL. Яго стандартныя для СКБД перавагі: наяўнасць транзакцый, развітая мова выбаркі даных, шырокі інструментарый для інтэграцыі; у спалучэнні з добрай прадукцыйнасцю даволі доўга задавальнялі нашы патрэбы.
Мы захоўвалі ў Postgres абсалютна ўсе дадзеныя: ад транзакцый да навін. Але колькасць карыстальнікаў расла, а разам з ім і колькасць запытаў.
Для разумення, гадавая колькасць сеансаў у 2017 годзе толькі на дэсктопным сайце - 131 млн. За 2018 - 125 млн. 2019 зноў 130 млн. Дадайце туды яшчэ 100-200 млн ад мабільнай версіі сайта і мабільнага прыкладання, і вы атрымаеце каласальную колькасць запытаў.
З ростам праекта, Postgres перастаў спраўляцца з нагрузкай, мы не паспявалі – з'явілася вялікая колькасць разнастайных запытаў, пад якія мы не змаглі стварыць дастатковую колькасць індэксаў.
Мы разумелі, што ёсць неабходнасць у іншых сховішчах дадзеных, якія б забяспечылі наш запатрабаванні і знялі нагрузку з PostgreSQL. У якасці магчымых варыянтаў разглядалі Elasticsearch і MongoDB. Апошні прайграваў па наступных пунктах:
- Павольная хуткасць індэксацыі з ростам аб'ёму даных у індэксах. У Elastic хуткасць не залежыць ад аб'ёму дадзеных.
- Няма паўнатэкставага пошуку
Так мы абралі для сябе Elastic і падрыхтаваліся да пераходу.
Пераход на Elastic
1. Мы пачалі пераход з сэрвісу пошуку кропак продажаў. У нашага кліента сумарна ёсць каля 70 000 кропак продажаў, і пры гэтым патрабуецца некалькі тыпаў пошуку на сайце і ў дадатку:
- Тэкставы пошук па назве населенага пункта
- Геапашук у зададзеным радыусе ад нейкай кропкі. Напрыклад, калі карыстач жадае ўбачыць якія кропкі продажаў бліжэй за ўсё да яго хаты.
- Пошук па зададзеным квадраце - карыстач акрэслівае квадрат на карце, і яму паказваюцца ўсе кропкі ў гэтым радыусе.
- Пошук па дадатковых фільтрах. Кропкі продажаў адрозніваюцца сябар ад сябра па асартыменце
Калі казаць па арганізацыю, то ў Postgres у нас ляжыць крыніца дадзеных як па карце, так і па навінах, а ў Elastic робяцца Snapshot'ы ад арыгінальных дадзеных. Справа ў тым, што першапачаткова Postgres не спраўляўся з пошукам па ўсіх крытэрыях. Мала таго, што было шмат індэксаў, яны маглі яшчэ і перасякацца, таму планавальнік Postgres губляўся і не разумеў які індэкс яму выкарыстоўваць.
2. Наступны на чарзе быў раздзел навін. На сайце кожны дзень з'яўляюцца публікацыі, каб карыстач не згубіўся ў струмені інфармацыі, дадзеныя трэба сартаваць перад выдачай. Для гэтага і патрэбен пошук: на сайце можна шукаць па тэкставым супадзенні, а заадно падлучаць дадатковыя фільтры, бо яны таксама зроблены праз Elastic.
3. Потым мы перанеслі апрацоўку транзакцый. Карыстальнікі могуць купляць пэўны тавар на сайце і ўдзельнічаць у розыгрышы прызоў. Пасля такіх пакупак, мы апрацоўваем вялікую колькасць дадзеных, асабліва ў выходныя і святы. Для параўнання, калі ў звычайныя дні колькасць пакупак складае недзе 1,5-2 млн, то ў святы лічба можа дасягаць 53 млн.
Пры гэтым дадзеныя трэба апрацаваць за мінімальны час - карыстальнікі не любяць чакаць выніку некалькі дзён. Праз Postgres такіх тэрмінаў ніяк не даможашся - мы часта атрымлівалі блакаванні, і пакуль мы апрацоўвалі ўсе запыты, карыстачы не маглі праверыць атрымалі яны прызы ці не. Гэта не вельмі прыемна для бізнэсу, таму мы перанеслі апрацоўку ў Elasticsearch.
перыядычнасць
Цяпер абнаўленні настроены падзейна, па наступных умовах:
- Кропкі продажаў. Як толькі да нас прыходзяць дадзеныя са знешняй крыніцы, мы адразу ж запускаем абнаўленне.
- Навіны. Як толькі на сайце рэдагуюць якую-небудзь навіну, яна аўтаматычна адпраўляецца ў Elastic.
Тут яшчэ раз варта сказаць аб плюсах Elastic. У Postgres падчас адпраўкі запыту, трэба чакаць пакуль ён сумленна апрацуе ўсе запісы. У Elastic можна адправіць 10 тыс. запісаў, і адразу пачаць працаваць, не чакаючы, пакуль запісы разыдуцца па ўсіх Shards. Вядома, нейкі Shard ці Replica могуць не ўбачыць дадзеныя адразу, але вельмі хутка ўсё будзе даступна.
Спосабы інтэграцыі
Ёсць 2 спосабу інтэграцыі з Elastic:
- Праз натыўны кліент па TCP. Натыўны драйвер паступова вымірае: яго перастаюць падтрымліваць, на ім вельмі няёмкі сінтаксіс. Таму мы яго практычна не выкарыстоўваем і стараемся поўнасцю адмовіцца ад яго.
- Праз 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, так як у гэты час мы працуем з дзясяткамі мільёнаў карыстальнікаў адначасова.
Звычайна пікі нагрузак бываюць у святочныя дні, але гэтая акцыя - зусім іншы ўзровень. Пазалетась у дзень акцыі мы прадалі 27 адзінак тавару. Дадзеныя апрацоўваліся больш за паўгадзіны, што выклікала нязручнасць у карыстальнікаў. Карыстальнікі атрымалі прызы за ўдзел, але стала зразумела, што працэс трэба паскараць.
У пачатку 2019 года мы вырашылі, што трэба ElasticSearch. Цэлы год мы арганізоўвалі апрацоўку атрымоўваных дадзеных у Elastic і іх выдачу ў api мабільнага прыкладання і сайта. У выніку на наступны год падчас акцыі мы апрацавалі. 15 131 783 запісаў за 6 хвілін.
Паколькі жадаючых набыць тавар і ўдзельнічаць у розыгрышы прызоў у акцыях у нас вельмі шмат, то гэта часовая мера. Цяпер мы адпраўляем актуальную інфармацыю ў Elastic, але ў далейшым плануем архіўную інфармацыю за мінулыя месяцы пераносіць у Postgres, як перманентнае сховішча. Каб не засмечваць індэкс Elastic, які таксама мае свае абмежаванні.
Заключэнне/высновы
На дадзены момант мы перанеслі на Elastic усе сэрвісы, якія хацелі і на гэтым пакуль зрабілі паўзу. Цяпер мы па-над асноўным персістэнтным сховішчам у Postgres будуем індэкс у Elastic, які прымае на сябе карыстацкую нагрузку.
У далейшым мы плануем пераносіць сэрвісы, калі мы разумеем, што запыт дадзеных становіцца занадта шматстайным і шукаецца па неабмежаванай колькасці калонак. Гэта ўжо задача не для Postgres.
Калі нам будзе патрэбен паўнатэкставы пошук у функцыянале або калі ў нас з'явіцца шмат разнастайных крытэрыяў пошуку, то мы ўжо ведаем, што гэта трэба перакладаць у Elastic.
⌘⌘⌘
Дзякуй, што прачыталі. Калі ў вас у кампаніі таксама выкарыстоўваюцца ElasticSearch і ёсць уласныя кейсы рэалізацыі, то раскажыце. Будзе цікава даведацца як у іншых 🙂
Крыніца: habr.com