Data Driven Realtime Rule Engine в Wargaming: аналіз даних. Частина 2

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

Блок RAW Data Collection описаний у першій статті і являє собою набір з standalone-адаптерів.
В основі таких двох лежить паралельна потокова обробка даних. В якості фреймворку використовується Spark Streaming. Чому саме він? Було вирішено, що варто використовувати єдиний дистрибутив Hadoop – Cloudera, який з коробки включає в себе Spark, HBase і Kafka. До того ж у компанії на той момент вже була експертиза по Spark.

Raw Data Transformer

На вхід підсистеми WG Hub ми отримуємо масу інформації від різних джерел даних, однак не вся вона готова до прямого використання і вимагає певної трансформації. Для перетворення сирих даних використовується модуль RDT (Raw Data Transformer), в якому зібрана вся бізнес-логіка інтеграції джерел даних. На виході ми отримуємо вже стандартизоване повідомлення, яке являє собою деякий іменоване подія з набором атрибутів. Воно записується у Kafka у вигляді сериализованного Java-об'єкта. На вході RDT обробляє кількість topic дорівнює кількості джерел даних, на виході отримуємо один topic з потоком різних подій, партиционированый з кодом гравця. Це гарантує, що при подальшій обробці дані конкретного гравця обробляються тільки одним executor, закріпленим за партицией (при використанні Spark Streaming directStream).

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

Rule Engine

Основним завданням цього модуля є надання користувачеві можливості створювати у системі правил, які, реагуючи на події в шині даних і маючи в своєму розпорядженні деякі накопичені історичні дані про гравця, на підставі заданої користувачем логіки будуть видавати нотифікації кінцеву систему. Основу для Rule Engine вибирали досить довго, поки не зупинилися на Drools. Чому саме він:

  • це Java, що передбачає менше проблем з інтеграцією
  • в комплекті є не саме зручне, але все ж GUI для створення правил
  • компонент KieScanner, що дозволяє оновлювати правила без рестарту програми
  • можливість використання Drools у вигляді бібліотеки без необхідності встановлювати додаткові сервіси
  • досить велике співтовариство
В якості сховища історичної інформації по гравцю використовується HBase. NoSQL-сховище тут відмінно підходить, оскільки вся обробка ведеться за номером гравця, а HBase добре справляється з балансуванням навантаження і шардингом даних між регіонами. Кращий відгук ми отримуємо, якщо майже всі дані поміщаються в blockCache.

Схематично робота BRE виглядає наступним чином:



Drools поширює правила як зібраний JAR-файл, тому на першому етапі ми встановили локальний Maven і налаштували проект в Workbench на деплой в репозиторій через секцію distributionManagement в pom.xml.

При старті Spark-програми в кожному executor запускається як окремий процес Drools KieScanner, який періодично перевіряє в Maven артефакт з правилами. Версія для перевірки артефакту встановлена в LATEST, що дозволяє в разі появи нових правил довантажити їх в поточний запущений код.

При надходженні нових подій у Kafka, BRE бере пачку в обробку і для кожного гравця з HBase вичитує блок історичних даних. Далі події разом з даними гравця передаються в Drools StatelessKieSession, де вони перевіряються на відповідність поточним завантаженим правилами. У результаті список спрацьованих правил записується у Kafka. Саме на його основі формуються підказки і пропозиції користувачеві в ігровому клієнта.

DDRRE: оптимізуємо і вдосконалюємо

Серіалізація історичних даних для зберігання в HBase. На перших етапах реалізації ми використовували Jackson JSON, в результаті чого один і той же POJO використовувався у двох місцях (в workbench при написанні правил і в Jackson). Це дуже сильно обмежувало нас в оптимізації формату зберігання і змушувало використовувати занадто складні анотації Jackson. Тоді ми вирішили відокремити бізнес-опис об'єкта від об'єкта зберігання. В якості останнього використовується клас, згенерований за protobuf-схемою. В результаті POJO, використовуваний в workbench, має человекочитаемую структуру, ясні найменування і є як би «проксі» до protobuf-об'єкту.

Оптимізація запитів в HBase. Під час тестової експлуатації сервісу було помічено, що в силу специфіки гри, в пачку обробки часто потрапляють кілька подій від одного і того ж облікового запису. Так як звернення до HBase є самою ресурсномісткою операцією, ми вирішили попередньо групувати облікові записи в пачці по ідентифікатору і вичитувати історичні дані один раз на всю групу. Дана оптимізація дозволила зменшити запити до HBase в 3-5 разів.

Оптимізації Data Locality. У нашому кластері машини поєднують в собі одночасно Kafka, HBase і Spark. Так як процес обробки починається з читання Kafka, то і locality ведеться за лідеру читається партіціі. Проте якщо розглянути весь процес обробки, то стає ясно, що обсяг даних, читається з HBase, значно перевищує обсяг вхідних даних подій. Отже, і пересилання цих даних по мережі забирає більше ресурсів. Для оптимізації процесу після читання даних з Kafka ми додали додатковий shuffle, який перегруповує дані по HBase region і по ньому ж виставляє locality. В результаті ми отримали значне скорочення мережевого трафіку, а також виграш у продуктивності, за рахунок того, що кожний окремий Spark task звертається лише до одного конкретного HBase region, а не до всіх, як було раніше.

Оптимізація ресурсів, використовуваних Spark. В боротьбі за час обробки ми також зменшили spark.locality.wait, так як при більшій кількості оброблюваних партіцій і меншій кількості executor, очікування locality було набагато більше, ніж час обробки.


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

В плани по розширенню DDRRE створення Rule as a service – спеціальної системи, за допомогою якої стане можливим викликати спрацьовування правил не за рахунок ігрового події, а за запитом від зовнішнього сервісу через API. Це дозволить відповідати на запити виду: «Який рейтинг у цього гравця?», «До якого сегменту належить?», «Який товар для нього краще підходить?» і т. п.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.