PHP Java, або In-memory кластер тепер і для PHP розробників, SavePearlHarbor

Ще одна копія хабора

Головне меню

Навігація за записами

PHP + Java, або In-memory кластер тепер і для PHP розробників

кластер
PHP + Java. Зображення взято звідси

Більшість IMDG написано на Java і підтримують API для Java, C++, C#, причому API для веб мов програмування (Python, Ruby, PHP) не підтримується, а протокол для написання клієнтів дуже обмежений. Саме цей факт я і вважаю основним гальмом для проникнення IMDG у маси – відсутність підтримки наймасовіших мов.

Так як виробники IMDG поки не надають підтримку веб-мов, то веб-програмісти не мають можливостей по такому ж легкому масштабуванню додатків, які є у серверних Java розробників. Тому я вирішив зробити щось подібне самостійно і викласти в open source, взявши як двигун open source IMDG JBoss Infinispan (компанія JBoss, що належить Red Hat, досить добре відома в колі java розробників). Мій проект називаєтьсяSproot Grid, поки доступний тільки для PHP, але якщо у спільноти буде інтерес, то зроблю і інтеграцію з Ruby та Python.

У цій статті я ще раз розповім про in-memory data grid і про те, як конфігурувати, запускати та використовувати Sproot Grid.

Навіщо потрібний IMDG?

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

1) Кешуванняплюси:

  • висока швидкість доступу до даних

  • дуже рідко зустрічаються справжні кластерні рішення, переважно користувачеві самому доводиться займатися розподілом даних по серверах, а при доступі до данихвизначати сервер, у якому лежать ці дані. Рівномірності заповненості всіх вузлів кластера у такій системі досягти складно
  • вимагає компромісу між актуальністю даних та швидкістю доступу, т.к. дані в кеші можуть застаріти, а видаляти старі дані з кешу з наступним кешуванням нових - це додаткові затримки та навантаження на систему
  • Зазвичай дані кешуються над вигляді доменних об'єктів, які у додатку, а вигляді BLOB чи рядків, тобто. при використанні даних, отриманих з кешу, потрібно спочатку сформулювати необхідні об'єкти

2) NoSQL рішенняплюси:

  • гарна горизонтальна масштабованість

  • не така висока швидкість отримання результатів у разі використання диска
  • практично неможливо забезпечити роботу внутрішньокорпоративного софту, орієнтованого на роботу з конкретною реляційною БД

IMDG поєднує переваги обох підходів і при цьому має низку переваг перед згаданими вище рішеннями:

  1. гарна горизонтальна масштабованість
  2. висока швидкість доступу
  3. справжня кластеризація (класти дані можна на будь-який вузол, запитувати дані можна також на будь-якому вузлі кластера), автоматичне балансування даних між вузлами
  4. кластер знає про всі поля об'єкта, отже можна шукати об'єкти не тільки за ключами, але й значеннями полів
  5. є можливість створювати індекси по полях або їх комбінації
  6. при використанні механізмів read-through і write-behind (або write-through) дані синхронізуватимуться з БД, що дозволить іншим додаткам (або іншим модулям додатку) продовжувати користуватися традиційною БД (MySQL або Mongo - неважливо)
  7. З використанням схеми роботи з попереднього пункту зникає проблема актуалізації даних у кеші, т.к. вони завжди там будуть такі самі, як і в БД

Розглянемо ближче ці 2 цікаві механізми: read-through і write-behind (write-through)

read-through
write-behind (write-through)

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

  1. Користувач робить викликcache.put(key, value), об'єкт 'value' зберігається в кеші за ключом 'key'
  2. У кластері спрацьовує обробник цієї події, відбувається складання sql-запиту для запису даних у БД та його виконання
  3. Управління повертається користувачеві

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

Якщо ж одночасна запис БД не є критичним умовою, тоді можна використовувати більш популярний механізм write-behind , він дозволяє організувати відкладений запис БД (будь-який інший сторадж). Приблизно так:

  1. Користувач робить викликcache.put(key, value), об'єкт 'value' зберігається в кеші за ключом 'key'
  2. Управління повертається користувачеві
  3. Через деякий час (конфігурується користувачем) спрацьовує обробник подіїзапису в кеш
  4. Оброблювач збирає всю пачку об'єктів, які були змінені з часу попереднього спрацювання оброблювача
  5. Пачка вирушає до БД на запис

При використанні write-behind операція запису істотно прискорюється, тому що користувач не чекає, поки апдейт дійде до БД, а просто кладе дані в кеш, а всі апдейти одного і того ж об'єкта будуть злиті в один результуючий апдейт, при цьому запис в БД відбувається пачками, що теж позитивно б'є по завантаженні сервера БД, Таким чином можна налаштувати свій IMDG те щоб кожні 3 секунди (чи 2 хв, чи 50 мс) все оновлення даних асинхронно відправлялися до бази.

Що з цього є у Sproot Grid?

У першій версії вирішив не реалізовувати відразу все, що розповів вище, т.к. це забрало б багато часу, а мені хотілося б якнайшвидше отримати фідбек від користувачів. Отже, що доступно в Sproot Grid 1.0.0:

  1. Горизонтальна масштабованість та чесна кластеризація з балансуванням кількості даних між вузлами кластера
  2. Можливість зберігання як вбудованих типів PHP, так і доменних об'єктів
  3. Можливість побудови індексу по полю та пошуку за цим індексом

Getting Started

Спочатку вам треба завантажити дистрибутив звідси та розпакувати його.

Встановлення необхідного ПЗ

Так як JBoss Infinispan - це Java додаток, то необхідно було вибрати спосіб взаємодії між Java та PHP. Як така сполучна ланка був обраний Apache Thrift (протокол був розроблений для серіалізації та транспорту між вузлами в Cassandra), тому для того, щоб Sproot Grid міг працювати на вашій системі необхідно встановити таке:

  • Java
  • Thrift - установка вproduction не потрібно, установка потрібна лише на девелоперській машині (подробиці у пункті Генерація коду). При депло в production вам потрібно тільки скопіювати .php файли бібліотеки Thrift і java бібліотеку у форматі .jar
  • PHP (якщо ще не встановлено)

Інструкції зі встановлення розташовані на wiki проекту

Конфігурація

Файл конфігурації повинен знаходитися в $deploymentFolder/sproot-grid/config/definition.xml, де deploymentFolder — це шлях до директорії, в якій ви розпакували дистрибутив

Як можна помітити з конфігурації, для кожного типу об'єктів ми можемо прописати ім'я кеша (а можемо не прописувати, якщо не хочемо зберігати такі об'єкти в окремому кеші). Cache - це хеш-таблиця, розподілена за кластером, в кластері може бути скільки завгодно кешів. В одному кеші можуть зберігатися лише об'єкти того самого типу. Всі кеші повинні бути описані в секції. У конфігурації є окрема секція для опису структури кластера і список кешів, які зберігатимуться в ньому.

— опис типів, які зберігатимуться у вашому кластері. Можна використовувати як вбудовані типи PHP, так і кастомні. Як можна помітити, для кожного типу об'єктів ми можемо прописати ім'я кеша (а можемо і не прописувати, якщо не хочемо зберігати такі об'єкти в окремому кеші)

Генерація коду для інтеграції з вашим додатком

Для ефективної роботи кластеру необхідно згенерувати код, специфічний для вашої програми (вашої доменної моделі) і скомпілювати його Java частину, оскільки це працює швидше, ніж доступ до об'єктів через reflection. Щоб згенерувати та скомпілювати весь необхідний код, треба:

, де $deploymentFolder це той каталог, в який ви розпакували дистрибутив Генерацію кодунеобхідно робити лише у разі зміни опису доменної моделі, тобто. якщо ваша модель стабільна, то цю операцію вам доведеться зробити лише один раз, після цього згенеровані php вихідники можна зберігати в репозиторії коду, а частина java буде скомпільована в бібліотеку. Тобто. не треба нічого генерувати по 10 разів перед тим, як задеплоїти вашу програму, це робиться тільки 1 раз на етапі розробки. Після закінчення виконання генерації коду, скопіюйте папку з .php файлами з $deploymentFolder/sproot-grid/php/org у корінь вашої програми

, де nodeId — значення атрибута id секції в конфігураційному файлі, memorySize — кількість пам'яті (у Мб або Гб), які ви хочете виділити вузлу

Використання всередині програми

На кроці генерації коду ви отримали все необхідне інтеграції з вашим додатком. Залишилось тільки скопіювати цей код у свою програму, для цього скопіюйте все з папки $deploymentFolder/sproot-grid/php в корінь своєї програми Все! Тепер можете використовувати кластер зі своєї програми.

Опис API можете знайти тут, але якщо коротко, то API зараз такий:

  • get($cacheName, $key)
  • getAll($cacheName, array $keys)
  • cacheSize($cacheName)
  • cacheKeySet($cacheName)
  • containsKey($cacheName, $key)
  • search($cacheName, $fieldName, $searchWord)
  • remove($cacheName, $key)
  • removeAll($cacheName, array $keys)
  • put($cacheName, $key, $domainObject)
  • putAll($cacheName, array $domainObjects)
  • clearCache($cacheName)