Пошук на швидкості 1 ТБ/с

TL;DR: Чотири роки тому я залишив Google з ідеєю нового інструменту для моніторингу серверів. Ідея полягала в тому, щоб об'єднати в одну службу зазвичай ізольовані функції збору та аналізу логів, збору метрик, оповіщень та панелі моніторингу. Один із принципів — сервіс має бути дійсно швидким, Забезпечуючи девопсам легку, інтерактивну, приємну роботу. Це вимагає обробки наборів даних по кілька гігабайт за частки секунди, не виходячи за межі бюджету. Існуючі інструменти для роботи з логами часто повільні та незграбні, тому ми зіткнулися з гарним завданням: грамотно розробити інструмент, щоб дати користувачам нові відчуття від роботи.

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

Сила старої школи

Аналіз логів зазвичай починається з пошуку: знайти всі повідомлення, які відповідають деякому шаблону. У Scalyr це десятки чи сотні гігабайт логів із багатьох серверів. Сучасні підходи, як правило, припускають побудову якоїсь складної структури даних, яка оптимізована для пошуку. Я, звичайно, бачив таке в Google, де вони досить добрі в таких речах. Але ми зупинилися на більш грубому підході: лінійне сканування ліг. І це спрацювало — ми забезпечуємо інтерфейс з пошуком набагато швидше, ніж у конкурентів (див. анімацію в кінці).

Ключовим осяянням стало те, що сучасні процесори справді дуже швидкі у простих, прямолінійних операціях. Це легко упустити у складних, багатошарових системах, які залежать від швидкості I/O та мережевих операцій, а такі системи сьогодні дуже поширені. Таким чином, ми розробили дизайн, який мінімізує кількість шарів та зайвого сміття. З кількома процесорами та серверами паралельно швидкість пошуку досягає 1 ТБ на секунду.

Ключові висновки цієї статті:

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

(У цій статті описується пошук даних у пам'яті. У більшості випадків, коли користувач виконує пошук по логах, сервери Scalyr вже кешували їх. У наступній статті обговоримо пошук по некешованих логах. ресурсами).

Метод грубої сили

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

Я використовував такий підхід у Google, і він добре працював. Але в Scalyr ми шукаємо у логах байт за байтом.

Чому? З абстрактної алгоритмічної точки зору індекси ключових слів набагато ефективніші, ніж грубий пошук. Однак, ми не продаємо алгоритми, ми продаємо продуктивність. І продуктивність — це алгоритми, а й системна інженерія. Ми повинні враховувати все: обсяг даних, тип пошуку, доступне обладнання та програмний контекст. Ми вирішили, що для нашої конкретної проблеми варіант на зразок grep підходить краще, ніж індекс.

Індекси - це добре, але у них є обмеження. Одне слово легко знайти. А ось пошук повідомлень з кількома словами, такими як 'googlebot' та '404' - вже набагато складніше. Пошук фрази на кшталт 'uncaught exception' вимагає громіздкішого індексу, який реєструє не тільки всі повідомлення з цим словом, але й конкретне розташування слова.

Справжня проблема виникає, коли ви шукаєте не слова. Припустимо, ви хочете подивитися, скільки трафіку надходить від ботів. Перша думка - пошук у логах за словом 'bot'. Так ви знайдете деякі боти: Googlebot, Bingbot та багато інших. Але тут 'bot' – це не слово, а його частина. Якщо шукати 'bot' в індексі, ми не знайдемо повідомлень зі словом 'Googlebot'. Якщо перевіряти кожне слово в індексі і потім сканувати індекс за знайденими ключовими словами, пошук дуже сповільниться. В результаті деякі програми для роботи з логами не дозволяють пошук частинами слова або (у кращому випадку) дозволяють використовувати спеціальний синтаксис з нижчою продуктивністю. Ми хочемо цього уникнути.

Ще одна проблема – пунктуація. Бажаєте знайти всі запити від 50.168.29.7? Що щодо налагодження логів, що містять [error]? Індекси зазвичай пропускають пунктуацію.

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

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

Індекси ключових слів також займають багато місця, а сховище – основна стаття витрат у системі керування логами.

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

Груба сила працює, якщо у вас є груба проблема (і багато сили)

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

Спочатку в нашому коді для пошуку був досить великий внутрішній цикл. Ми зберігаємо повідомлення на сторінках 4K; кожна сторінка містить деякі повідомлення (у UTF-8) та метадані для кожного повідомлення. Метадані — це структура, в якій закодовано довжину значення, внутрішній ID повідомлення та інші поля. Цикл пошуку виглядав так:

Пошук на швидкості 1 ТБ/с

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

(Ви можете запитати, чому ми зберігаємо повідомлення в такому форматі зі сторінками по 4K, текстом і метаданими, а не працюємо з логами безпосередньо. Є багато причин, які зводяться до того, що внутрішньо двигун Scalyr більше схожий на розподілену базу даних, ніж на файлову систему Текстовий пошук часто поєднується з фільтрами в стилі СУБД на полях після парсингу логів.Ми можемо одночасно шукати по багатьох тисячах логів одночасно, і прості текстові файли не підходять для нашого транзакційного, реплікованого, розподіленого управління даними).

Спочатку здавалося, що такий код не дуже підходить для оптимізації під метод грубої сили. «Справжня робота» в String.indexOf() навіть не домінувала у профілі CPU. Тобто оптимізація цього методу не принесла б істотного ефекту.

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

Пошук на швидкості 1 ТБ/с

Така версія працює безпосередньо на поданні raw byte[] і шукає всі повідомлення відразу на всій сторінці 4K.

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

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

Наша реалізація вимагає для кожного пошуку створення пошукової таблиці 64K, але це нісенітниця в порівнянні з гігабайтами даних, в яких ми шукаємо. Внутрішній цикл обробляє кілька гігабайт на секунду на одному ядрі. На практиці стабільна продуктивність складає близько 1,25 ГБ на секунду на кожному ядрі, і є потенціал для покращення. Можна усунути деякі накладні витрати поза межами внутрішнього циклу, і ми плануємо поекспериментувати з внутрішнім циклом на C замість Java.

Застосовуємо силу

Ми обговорили, що пошук по логах можна реалізувати грубо, але скільки сили у нас є? Чимало.

1 ядро: при правильному використанні одне ядро ​​сучасного процесора досить потужне саме собою.

8 ядер: в даний час ми працюємо на серверах Amazon hi1.4xlarge та i2.4xlarge SSD, на кожному з яких 8 ядер (16 потоків). Як згадувалося вище, зазвичай ці ядра зайняті фоновими операціями. Коли користувач виконує пошук, фонові операції призупиняються, звільняючи всі 8 ядер для пошуку. Пошук зазвичай завершується за секунду, після чого фонова робота відновлюється (програма-регулятор гарантує, що шквал пошукових запитів не завадить важливій фоновій роботі).

16 ядер: для надійності ми організуємо сервери за групами master/slave. У кожного майстра підпорядкований один сервер SSD і один EBS. Якщо головний сервер падає, сервер на SSD негайно займає його місце. Майже весь час master і slave працюють нормально, тому кожен блок даних доступний для пошуку на двох різних серверах (у підлеглого сервера EBS слабкий процесор, тому ми його не розглядаємо). Ділимо завдання між ними, так що у нас доступні загалом 16 ядер.

Багато ядер: у найближчому майбутньому ми розподілимо дані по серверам таким чином, щоб усі вони брали участь у обробці кожного нетривіального запиту. Працюватиме кожне ядро. [Примітка: ми реалізували план та підвищили швидкість пошуку до 1 ТБ/с, див. примітку наприкінці статті].

Простота забезпечує надійність

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

Індекс ключових слів іноді видає неймовірно швидкий результат, а інших випадках немає. Припустимо, у вас 50 ГБ логів, в яких термін customer_5987235982 зустрічається рівно три рази. Пошук за цим терміном рахує безпосередньо з індексу три розташування та завершиться миттєво. Але складний пошук з знаками підстановки може сканувати тисячі ключових слів і зайняти багато часу.

З іншого боку, пошук методом грубої сили для будь-якого запиту виконується більш-менш однаковою швидкістю. Пошук довгих слів є кращим, але навіть пошук одного символу відбувається досить швидко.

Простота методу грубої сили означає, що його продуктивність близька до теоретичного максимуму. Тут менше варіантів для непередбаченого навантаження дисків, конфлікту при блокуваннях, погоні вказівника та тисяч інших причин для збоїв. Я просто подивився на запити, зроблені користувачами Scalyr минулого тижня на нашому самому завантаженому сервері. Було 14 000 запитів. Рівно вісім із них зайняли більше однієї секунди; 99% виконано в межах 111 мілісекунд (якщо ви не використовували інструменти аналізу логів, повірте: це швидко).

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

Пошук по логах у дії

Ось невелика анімація, яка показує пошук Scalyr у дії. Ми маємо демо-аккаунт, куди ми імпортуємо кожну подію в кожному публічному репозиторії Github. У цій демонстрації я вивчаю дані протягом тижня: приблизно 600 МБ необроблених логів.

Відео записано у прямому ефірі, без спеціальної підготовки, на моєму робочому столі (близько 5000 кілометрів від сервера). Продуктивність, яку ви побачите, багато в чому зобов'язана оптимізації веб-клієнта, а також швидкому та надійному бекенду. Щоразу, коли виникає пауза без індикатора 'loading', це я роблю паузу, щоб ви встигли прочитати, що я збираюся натиснути.

Пошук на швидкості 1 ТБ/с

На закінчення

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

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

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

Виправлення: заголовок та текст змінилися з «Пошук на швидкості 20 ГБ на секунду» на «Пошук на швидкості 1 ТБ на секунду», щоб відобразити збільшення продуктивності за останні кілька років. Це збільшення швидкості в першу чергу пов'язане зі зміною типу та кількості серверів EC2, які ми сьогодні піднімаємо для обслуговування клієнтської бази, що зросла. Найближчим часом очікуються зміни, які забезпечать ще одне різке підвищення ефективності роботи, і ми з нетерпінням чекаємо, коли з'явиться можливість розповісти про це.

Джерело: habr.com

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