UA RU
logo
Досвід      27/01/2022

Як оновити дані в базі, щоб 25 млн користувачів нічого не помітили: досвід додатку для знайомств

Андрей Годяцкий BLOG

Senior Software Engineer PHP в Appflame

Привіт! Мене звати Андрій Годяцький і я працюю Senior Software Engineer PHP в українській продуктовій IT-компанії Appflame. У цій статті я хочу розповісти про два кейси реіндексу/ремапінгу або, як заведено в SQL, міграції:

  1. перший — з 20% просадкою за продуктовими метриками, чому він виник і з якими проблемами ми зіштовхнулися;
  2. другий — як нам вдалося зробити реіндекс під навантаженням без просадок й пришвидшити сам процес удвічі.  

Стаття буде цікава тим, хто працює з ElasticSearch та базами користувачів під великим навантаженням, де дуже важлива актуальність інформації та її постійне оновлення. А також тим, у кого є необхідність мати стабільну робочу базу без просадок/даунтаймів/зупинок, щоб можна було зробити бажану структуру індексу в процесі роботи без жодних відображень на клієнтській частині. 

Перша практика і проблеми, що виникли

В цій статті я розповідатиму про два кейси реіндексу в нашому додатку для знайомств Hily. Він налічує близько 25 мільйонів користувачів у світі й працює на ринках Tier 1Сюди входять країни з високою купівельною спроможністю. Вони характеризується найбільшими виплатами, високою конкуренцією та найдорожчим трафіком.. У нас досить складні запити на ElasticSearch для того, щоб алгоритм зміг підібрати максимально релевантних один одному користувачів, і відповідно є велике навантаження на базу. З графіку нижче видно, що у піках у нас виконується 4000 операцій за секунду. 

Графік навантаження на базу

Графік навантаження на базу

В певний момент виникла продуктова необхідність змінити структуру даних однієї секції та певних типів даних в ній. Для вирішення цих завдань нам потрібно було зробити реіндекс.   

Під час запуску першого реіндексу нам потрібно було зупинити всі наші воркери, які постачали дані в ElasticSearch, оновлювали їх та записували туди нову інформацію. Через це ми зіштовхнулися з такими проблемами: 

  • якщо існуючий користувач оновлював свою інформацію, його score не змінювався й алгоритм не перелаштовувався на пошук/підбирання релевантних користувачів відповідно до нової інформації;  
  • нові користувачі не з’являлися у базі й не отримували бажаної активності (їх профілі не показувалися іншим користувачам тощо);
  • активність концентрувалася на певних користувачах і не розподілялася на інших; 
  • Практичний інтенсивний курс з дизайну - Design Booster від Powercode academy.
    Навчіться дизайну з нуля за 3 місяці і заробляйте перші $1000, навіть якщо ви не маєте креативного мислення, смаку або вміння малювати. Отримайте практичні навички, необхідні для успішної кар'єри в дизайні.
    Зарееструватися
  • з’явився ризик обриву операції й виникнення неконсистентних даних. 

В результаті такої операції, ми отримали просадку близько 20% практично по всіх продуктових метриках, виросли дублікати дій (івент, який повторювався декілька разів через те, що тимчасово не оновлювалися дані в ElasticSearch), з’явився ризик втратити деяких користувачів — користувач зайшов, не побачив релевантних юзерів, не отримав бажаної активності, вийшов і видалив додаток.

Була ще одна проблема: ми не знали, скільки часу нам потрібно буде, щоб зробити реіндекс на проді. На проді у нас велика база — близько 25 мільйонів користувачів, а на стейджіТестове середовище маленька — 3 мільйони. 

Якщо на стейджі ми запустили реіндекс і він відбувся за п’ять хвилин, то на проді цей процес зайняв близько двох годин!

Ми не могли просто взяти й стопнути його, тому що б тоді у нас вийшли одні індекси биті з уже переробленою структурою, а інші — зі старою структурою. У нас була б каша, яку потрібно було б «розхльобувати» повторним запуском операції реіндексу. 

Коли завершився процес реіндексу, всі воркери знову почали працювати й дані почали оновлюватися. Але ці дві години залишилися з просадкою. З часом всі процеси відновилися й протягом декількох годин ми наздогнали всі метрики по користувачах.     

Після того, як у нас відбулася просадка, постало питання: як нам у майбутньому робити реіндекс без просадок?      

Вирішення складностей крок за кроком та другий реіндекс

Ми знайшли для себе таке рішення: створити копію індексу з новою структуроюДалі — новий індекс і перелити в нього всі дані з початкового індексу зі старою структуроюДалі — старий індекс при цьому дублювати всі операції CUDcreate, update, delete у новий індекс. Після завершення процесу реіндексу весь трафік в моменті переключити зі старого індексу на новий. 

Я написав скрипт, який займався всім цим процесом: створив новий індекс та команди для ElasticSearch, який мав переливати дані зі старого індексу в новий, паралельно змінюючи/оновлюючи їх структуру відповідно до продуктових потреб. 

Онлайн- курс Java developer від Mate academy.
Якщо ви не можете навчатись повний день, обирайте курс Java developer з гнучким графіком! Ви зможете опанувати нову професію та отримати нову роботу!
Отримати знижку на курс

Таким чином ми отримували дані зі старого індексу в новому та з новою структурою. Але що робити з даними, які прилітали у старий індекс, але вже були переміщені операцією реіндексу? На розв’язання такої задачі прийшло рішення дублювання операцій CUD у новий індекс. Така схема дозволила нам працювати без зупинки воркерів на CUD й дозволила зберегти максимальну актуальність даних у процесі реіндексу.

Коли ElasticSearch закінчив процес перелиття даних зі старого індексу в новий, то ми отримали абсолютно валідні дані в обох версіях й нічого не втратили. В цей момент ми виконали команду переключення alias. Система почала працювати з новим індексом і всі запити CRUDcreate, read, update, delete вже йшли сюди. 

Якщо раніше під час першого реіндексу операції «оновити/вставити/видалити» були призупинені та взагалі не відбулися (відбувалося тільки отримання даних), то у процесі з новим індексом всі операції виконувались під час процесу реіндексу. 

Для нових та існуючих користувачів все працювало так як потрібно. Якщо під час реіндексу існуючий користувач отримав активність, змінював свої дані — алгоритм отримував всю інформацію й враховував її.  

Таким чином під час другого реіндексу ми змогли зберегти актуальність даних та релевантність видачі користувачів.

Та ми вирішили піти далі й подумали: як ми можемо оптимізувати швидкість процесу реіндексу?

В ElasticSearch є можливість конфігурувати (Slicing), скільки процесів реіндексу він запустить для того, щоб переливати дані зі старого індексу в новий. Ми нарізали більше процесів, завдяки чому швидкість збільшилася й перелиття даних відбулося не за дві години, а за годину.

Як уникнути конфлікту версій? 

В ElasticSearch є таке поняття як версії документа. Наприклад, якщо користувач зареєструвався в нашому додатку, створюється документ з версією 1. Цей документ містить всю інформацію, яку ввів користувач (ім’я, вік, вподобання тощо). Якщо цей же користувач оновив або додав інформацію, створюється документ з версією 2, 3 і т.д. 

Онлайн курс з промт інжинірингу та ефективної роботи з ШІ від Powercode academy.
Курс-інтенсив для отримання навичок роботи з ChatGPT та іншими інструментами ШІ для професійних та особистих задач, котрі допоможуть як новачку, так і професіоналу.
Записатися на курс

В момент переливання (реіндексу) ми могли зіштовхнутися з конфліктом версій — це коли ElasticSearch намагається вставити документ старішої версії (наприклад, 4), а в базі вже існує нова версія (5). Це  може відбутися тоді, коли ми дублюємо всі процеси в новий індекс. 

Оскільки конфлікт версій обриває процес реіндексу, викидаючи помилку, то нам варто уникати таких випадків, так як процес потрібно буде починати знову.

Для вирішення цього питання ми переключили опцію ​​conflicts у значення proceed, що дає змогу продовжити процес без переривання, ігноруючи цей конфлікт. Для нас ігнорування ніяким чином не відобразилось на актуальності даних, так як новіший документ мав всю необхідну актуальну інформацію.

Коли ми перелили всі дані зі старого індексу в новий й повністю переключилися в роботі на нього, старий індекс залишився неактивним.

Ми перевірили, щоб продуктові метрики були в нормі, щоб не було жодних просадок після перелиття і жодних проблем із новим індексом, після чого видалили старий індекс.  

Перемикатись назад на старий індекс і відповідно зберігати його є сенс тільки тоді, коли операція реіндексу не відбулася, і цей процес обірвався з якоїсь технічної причини.           

Моніторинг

До початку і в процесі другого реіндексу ми слідкували за:

  • продуктовими метриками; 
  • моніторами по нашому залізі (як працюють наші сервери, чи все окей у них по процесору, пам’яті тощо); 
  • Психологічний профорієнтаційний тест для IT-фахівців від Hillel IT School.
    Пройдіть психологічний профорієнтаційний тест для IT-фахівців щоб дізнатися ваші сильні сторони, вподобання і інтереси і з'ясувати, яка IT-спеціальність вам підходить.
    Пройти тест
  • моніторами по самій машині ElasticSearch (як вони навантажені, як почувають себе ноди, як взагалі живе цей кластер). 

Наша бекенд-команда слідкувала за цими моніторами в момент реіндексу, щоб у випадку виникнення проблеми вимкнути процес реіндексу, зрозуміти, що це за проблема, та швидко пофіксити її. Монітори дуже допомагають нам жити й тримати наш додаток у нормальному робочому режимі. 

Тестове середовище

Наші девопси підняли окремий сервер, де вони розгорнули ElasticSearch з усією базою. Це було повністю налаштоване тестове середовище схоже на наш бекенд на проді, той, на якому в нас зараз працює додаток. 

Я написав скрипти, які навантажували ElasticSearch, імітуючи операції CRUD подібні проду на наше тестове середовище. Таким чином ми створили навантаження схоже із продакшен-середовищем.

В цей час під цим навантаженням я запустив процес реіндексу. Він виконався, і ми змогли побачити, що все окей. На цьому етапі ми ще спіймали пару нюансів і помилок, які пофіксили. Це тестове середовище дало нам гарне розуміння, що ми можемо їхати на продакшен, що у нас все добре пройшло.

Я не можу сказати, що це звичний для нас підхід, ми такі операції робимо доволі рідко. Це не дешеве задоволення — потрібно на певний час орендувати великі, потужні сервери й розгорнути та налаштувати там середовище. Але саме завдяки такому тестуванню можна зрозуміти, яку оптимізацію отримаєш на продакшені, зловити пару неявних багів і переконатись, що можна їхати на прод, адже система працює чітко навіть під навантаженням. 

Тут ключовий момент під навантаженням. Річ у тім, що на своїх локальних комп’ютерах і навіть на звичайних тестових середовищах ми не можемо створити таке сильне навантаження — вони не мають стільки потужності, щоб витримувати такі важкі умови. До цього я не чув і не бачив, щоб у компаніях створювали окреме середовище для тестування під навантаженням. Це був класний досвід.  

Запуск на проді та результати

Ми запускали скрипт у час, коли у нас найменше завантаження на наших серверах: для нас це 12 година дня за київським часом. Коли відбувався другий реіндекс було дуже класно бачити в порівнянні з першим разом, що всі бізнесові метрики йдуть рівненько, що наші користувачі використовують додаток, не помічаючи, що в нас щось відбувається, що для них все виглядає так само як і раніше.

Ну і процес відбувся вдвічі швидше: ми зробили реіндекс за годину, при цьому ніяких просадок метрик не отримали. Все було тихо, класно, чисто. 

Основи Web дизайну від Hillel IT School.
Цей онлайн-курс з основ веб-дизайну дозволить вам опанувати мистецтво створення ефективних та привабливих інтерфейсів для вебсайтів і застосунків. Ви оволодієте ключовими принципами UX/UI дизайну, створюватимете дизайн-макети та прототипи, розроблятимете адаптивні інтерфейси для різних пристроїв, готуючись до професійної кар'єри в галузі веб-дизайну.
Дізнатися більше

Три головні поради

Зараз, порівнюючи перший і другий реіндекс, я міг би поділитися декількома порадами.

Не робити те, що не потрібно

Якщо перед вами постала складна задача, це ще не означає що цей виклик потрібно прийняти. Можливо, є інші, простіші рішення, а можливо цей складний шлях взагалі надуманий, непотрібний і не зробивши цей крок ви геть нічого не втратите й навпаки заощадите купу ресурсів. Ваші витрачені зусилля мають бути виправдані отриманим результатом. Переконаний, що це стосується всього — вас особисто чи бізнесу в якому ви працюєте.

Тестувати все, що тестується

Буває так, що покриття тестами (smoke, acceptance, unit, integration, manual, automation тощо) — недостатнє, і реальну картинку можна побачити лише під навантаженням подібному реальному середовищу.

Дуже круто, якщо є можливість зробити тестове середовище наближене до проду й на ньому поганяти складні операції. Не проводити тест і вирішувати помилки після їх прояву на проді часто виходить в рази дорожче. 

Зупинитися, подумати й декілька разів програти ситуацію ще до того, як вона відбудеться

Дуже ймовірно що у вас з’явиться простіше рішення або зникне необхідність виконання такої задачі, бо знайдеться інше рішення. У такому випадку ви дослухаєтеся до нашої першої поради 🙂 Також ви зможете врахувати конфлікт версій, подумати, як можна оптимізувати швидкість реіндексу і що ще можна зробити ефективніше.


Поділіться, будь ласка, своїм досвідом: як ви робите реіндекс? Також було б цікаво дізнатися, як ви проводите тестування навантажених систем і складних операцій до того, як залити код в прод. Чи є у вас тестове середовище і як ви розумієте, що все пройде окей?

Якщо ви знайшли помилку, будь ласка, виділіть фрагмент тексту та натисніть Ctrl+Enter.

Онлайн-курс "B2B-продажі" від Laba.
Розробіть ефективну стратегію B2B-продажів за 11 занять: від воронки до партнерської програми.Лектор курсу — засновник консалтингової компанії, який має 15 років досвіду в продажах.
Дізнатись більше

Цей матеріал – не редакційний, це – особиста думка його автора. Редакція може не поділяти цю думку.

Найбільш обговорювані статті

Топ текстів

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: