Як зазирнути в очі Кассандрі і не втратити при цьому дані, стабільність та віру в NoSQL

Як зазирнути в очі Кассандрі і не втратити при цьому дані, стабільність та віру в NoSQL

Кажуть, у житті все варто спробувати бодай раз. І якщо ви звикли працювати з реляційними СУБД, то познайомитися практично з NoSQL варто в першу чергу хоча б для загального розвитку. Зараз через бурхливий розвиток цієї технології дуже багато суперечливих думок і гарячих суперечок на цю тему, що особливо підігріває інтерес.
Якщо вникнути у суть усіх цих суперечок, можна побачити, що вони виникають через неправильного підходу. Ті, хто використовує NoSQL бази саме там, де вони потрібні, задоволені та одержують від даного рішення всі його плюси. А експериментатори, які сподіваються на цю технологію як панацею там, де вона не застосовна зовсім, відчувають розчарування, втративши сильні сторони реляційних баз без придбання вагомих вигод.

Я розповім про наш досвід впровадження рішення, заснованого на СУБД Cassandra: з чим довелося зіткнутися, як викручувалися зі скрутних ситуацій, чи вдалося нам отримати виграш від використання NoSQL і де довелося вкласти додаткові зусилля/кошти.
Вихідне завдання - це побудова системи, що записує дзвінки в якесь сховище.

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

Як зазирнути в очі Кассандрі і не втратити при цьому дані, стабільність та віру в NoSQL

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

Отже, ось що нам подарував досвід

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

Кассандра не підстрахує там, де Oracle рятував своїми констрейнтами. І якщо автор програми заздалегідь цього не зрозумів, то дубль, що прилетів, для Кассандри анітрохи не гірший за оригінал. Раз прийшов, то вставимо.

Безкоштовна Кассандра «зі коробки» різко не сподобалася ІБ: логування дій користувачів немає, розмежування прав теж. Інформація про дзвінки відноситься до персональних даних, а це означає, що всі спроби як-небудь її запитати/змінити, повинні журналуватися з можливістю подальшого аудиту. Також потрібно усвідомлювати необхідність розділяти права за різними рівнями для різних користувачів. Простий інженер експлуатації та суперадмін, який вільно може видалити весь keyspace – це різні ролі, різна відповідальність, компетенція. Без такого розмежування прав доступу цінність і цілісність даних відразу під питанням швидше, ніж за рівні консистентності ANY.

Ми не врахували, що за дзвінками потрібна як серйозна аналітика, так і періодичні вибірки за різними умовами. Так як обрані записи потім передбачається видаляти і перезаписувати (у рамках завдання ми повинні підтримувати процес актуалізації даних при даних, що неправильно надійшли до нас в контур даних), то Кассандра нам тут не товариш. Кассандра, як скарбничка - у неї зручно складати, але в ній не вийде рахувати.

Зіткнулися з проблемою перенесення даних до тестових зон (5 нід у тесті проти 20 у промі). Дамп у такому разі використати не вийде.

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

Таймаути під час вставки. Кассандра у записі прекрасна, але іноді вхідний потік може її суттєво спантеличити. Таке відбувається, коли програма починає ганяти по колу кілька записів, які не вдається вставити з будь-якої причини. І нам потрібний буде цілком собі справжній ДБА, який стежитиме за gc.log, логі system і debug на предмет slow query, метрики на compaction pending.

Декілька датацентрів у кластері. Звідки читати та куди писати?
Можливо, поділити на читання та на запис? І якщо так, то ближче до додатка має бути ДЦ для запису чи читання? І чи не вийде ми справжній split brain, якщо невірно виберемо рівень узгодженості? Дуже багато питань, багато незвіданих налаштувань, можливостей, які хочеться покрутити.

Як ми вирішували

Щоб нода не просідала, відключили SWAP. І тепер при нестачі пам'яті нода повинна лягти, а не плодити великі паузи.

Отже, на логіку у БД ми більше не сподіваємось. Розробники програми переучуються і починають активно підстрахуватися у своєму коді. Ідеальний чіткий поділ зберігання та обробки даних.

Купували підтримку від DataStax. Коробкову Кассандру вже перестали розробляти (останній коміт у лютому 2018 року). Водночас, Datastax пропонує відмінний сервіс та велику кількість доопрацьованих та адаптованих під існуючі ІС рішень.

Ще хочу наголосити, що Кассандра не дуже зручна для запитів на вибірку. Зрозуміло, CQL – великий крок назустріч користувачам (проти Trift). Але якщо у вас є цілі відділи, які звикли до таких зручних джойнів, вільної фільтрації по будь-якому полю та можливостям оптимізації запиту, і ці відділи працюють над тим, щоб закривати претензії та аварії, то рішення на Кассандрі, бачиться їм ворожим та дурним. І ми почали вирішувати питання, як нашим колегам робити вибірки.

Розглядали два варіанти. У першому варіанті пишемо виклики не тільки в С *, але і в архівну БД Oracle. Тільки на відміну від C* у цій БД зберігаються дзвінки лише за поточний місяць (достатня глибина зберігання дзвінків для кейсів перетарифікації). Тут відразу бачилася наступна проблема: якщо писати синхронно, ми втрачаємо всі плюси С*, пов'язані з швидкою вставкою, якщо асинхронно - немає гарантії того, що всі потрібні виклики взагалі потрапили в Oracle. Плюс був один, але великий: для експлуатації залишається той самий звичний PL/SQL Developer, тобто практично реалізуємо патерн «Фасад». Альтернативний варіант. Реалізуємо механізм, який вивантажує виклики з C*, тягне якісь дані для збагачення з відповідних таблиць у Oracle, джойніть отримані вибірки і видає нам отриманий результат, який потім якось використовуємо (відкочуємо, переповторюємо, аналізуємо, захоплюємося). Мінуси: процес виходить досить багатокроковим, крім того, відсутній інтерфейс для співробітників експлуатації.

У результаті зупинилися все ж таки на другому варіанті. Для вибірок із різних банок використовували Apache Spark. Суть механізму звелася до Java-коду, який за вказаними ключами (абонент, час здійснення виклику – ключі розділу) витягує дані з C*, а також потрібні дані для збагачення будь-якої іншої БД. Після чого джойніть їх у своїй пам'яті і виводить результат у результуючу таблицю. Над спарком намалювали веб-мордочку і вийшло цілком придатним для експлуатації.

Як зазирнути в очі Кассандрі і не втратити при цьому дані, стабільність та віру в NoSQL

При вирішенні завдання з оновленням даних пром-тест знову розглядали кілька способів розв'язання. Як перенесення через Sstloader, так і варіант з розбиттям кластера в тестовій зоні на дві частини, кожна з яких поперемінно входить в один кластер із промовським, запитуючи таким чином від нього. При оновленні тесту планувалося змінювати їх місцями: та частина, яка працювала в тесті, очищується та вводиться в пром, а інша починає працювати з даними окремо. Однак, подумавши ще раз, ми раціональніше оцінили ті дані, які варто переносити, і зрозуміли, що самі по собі виклики – неконсистентна сутність для тестів, що швидко генерується у разі потреби, і саме промовський набір даних не має цінності для перенесення в тест. Є кілька об'єктів-накопичувачів, які варто переносити, але це буквально пара таблиць, причому не дуже важких. Тому нам Як рішення знову прийшов на допомогу Spark, за допомогою якого ми написали і почали активно використовувати скрипт перенесення даних між таблицями пром-тест.

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

Для забезпечення безперервної доступності Кассандри потрібен дба і не лише він. Усі, хто працює з додатком, повинні розуміти, де і як дивитися поточну ситуацію та як вчасно діагностувати проблеми. Для цього ми активно використовуємо DataStax OpsCenter (Адміністрування та моніторинг робочих навантажень), системні метрики Cassandra Driver (кількість таймаутів на запис у C*, кількість таймаутів на читання з C*, максимальна latency і т. д.), моніторимо роботу самого додатка, що працює з Кассандрою.

Коли задумалися над попереднім питанням, то зрозуміли, де в нас може бути основний ризик. Це форми відображення даних, які виводять дані з декількох незалежних один від одного запитів до сховища. Таким чином, ми можемо отримати досить неузгоджену інформацію. Але ця проблема була б так само актуальна і у випадку, якби ми працювали лише з одним датацентром. Так що найрозумніше тут - це, звичайно, робити батчеву функцію читання даних на сторонньому додатку, яка забезпечить отримання даних у єдиний період часу. Що стосується поділу на читання та запис у плані продуктивності, то тут нас зупинив ризик того, що при певній втраті коннекту між ДЦ, ми можемо отримати два абсолютно неузгоджені між собою кластери.

У результаті, на даний момент зупинилися лише на рівні узгодженості для запису EACH_QUORUM, читання – LOCAL_QUORUM

Короткі враження та висновки

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

Якщо з ходу, то скоринг даних для програм типу «Плати, коли зручно» (вантажимо в С* інформацію, розрахунок на скриптах Spark), облік претензійки з агрегацією за напрямами, зберігання ролей та обчислення за рольовою матрицею прав доступу користувачів.

Як бачимо, репертуар широкий та різноманітний. І якщо вибирати табір прихильників/противників NoSQL, то ми приєднаємося до прихильників, оскільки свої плюси отримали, і саме там, де й очікували.

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

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

Наприклад, вчасно відстежувати оновлення самої Кассандри, тому що досить багато проблем, які ми отримали, вже були відомі та керувалися.

Не саджати і саму БД, і Спарк на ті самі ноди (або суворо розділяти за кількістю допустимого використання ресурсів), оскільки Спарк може з'їсти ВП більше, ніж потрібно, і ми швидко отримаємо проблему номер 1 з нашого списку.

Прокачувати моніторинг та компетенцію експлуатації ще на етапі тестування проекту. Спочатку враховувати по максимуму всіх потенційних споживачів нашого рішення, Тому що саме від цього залежатиме в результаті структура БД.

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

Непогано Одночасно передбачити навішування TTL та чищення застарілих даних.

При розвантаженні даних з Кассандри логіка програми повинна працювати за принципом FETCH, щоб не всі рядки завантажувалися на згадку за один раз, а вибиралися пачками.

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

Якщо ми працюємо з критичною інформацією (такі як дані для проведення білінгу, розрахунок заборгованості абонента), то варто також приділити увагу інструментам, які дозволять знизити ризики, що виникають через особливості СУБД. Наприклад, використовувати утиліту nodesync (Datastax), виробивши оптимальну стратегію її використання, щоб заради консистентності не сформувати надмірне навантаження на Кассандру та використовувати її лише для певних таблиць у певний період.

Що ж, за півроку життя, з Кассандрою? Загалом невирішених проблем немає. Серйозних аварій та втрати даних ми теж не допустили. Так, довелося подумати над компенсацією деяких проблем, що раніше не виникали, але в результаті це не сильно затьмарило наше архітектурне рішення. Якщо ви хочете і не боїтеся пробувати щось нове, і при цьому не хочете розчаруватися, то приготуйтеся до того, що безкоштовного нічого не буває. Розбиратися, вникати в документацію та збирати свої індивідуальні граблі доведеться більше, ніж у старому legacy рішенні, і ніяка теорія не підкаже заздалегідь, які саме граблі чекають саме на вас.

Джерело: habr.com

Додати коментар або відгук