Сірванець confirm php. Фільтрування та перевірка даних PHP. Часті помилки. Паралельні та послідовні обчислення

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

Вступ. Часто до мене звертаються клієнти, у яких встановлені самописні CMS або модулі, написані веб-програмістами-початківцями, які не розуміють, що потрібно для захисту даних і часто копіюють функції фільтрації, не замислюючись про те, як вони працюють і що саме потрібно з ними робити.

Тут я постараюся описати якомога детальніше часті помилки при фільтрації даних у PHP скрипті і дати прості поради як правильно виконати фільтрацію даних.

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

Розбір польотів. Фільтрація. Помилка №1 Для числових змінних використовується така перевірка:
$number = $_GET["input_number"]; if (intval($number)) ( ... виконуємо SQL запит ... )
Чому вона призведе до ін'єкції SQL? Справа в тому, що користувач може вказати в змінній значення input_number:
1"+UNION+SELECT
У разі перевірка буде успішно пройдено, т.к. функція intval отримує ціле значення змінної, тобто. 1, але в змінній $number нічого не змінилося, тому весь шкідливий код буде передано в SQL запит.
Правильна фільтрація:
$number = intval($_GET["input_number"]); if ($number) ( ... виконуємо SQL запит ... )
Звичайно, умова може змінюватися, наприклад, якщо вам потрібно отримати тільки певний діапазон:
if ($number >= 32 AND $number dir = MAIN_DIR . "/template/" . $config["skin"];
У цьому випадку можна змінити значення змінної $_COOKIE["skin"] і викликати помилку, в результаті якої ви побачите абсолютний шлях до папки сайту.
Якщо ви використовуєте значення куків для збереження в базу, то використовуйте одну з описаних вище фільтрацій, також стосується і змінної $_SERVER .Фільтрація. Помилка №5. Включено директиву register_globals. Обов'язково вимкніть її, якщо вона увімкнена.
У деяких ситуаціях можна передати значення змінної, яка не повинна була передаватися, наприклад, якщо на сайті є групи, то групі 2 змінна $group повинна бути порожньою або дорівнювати 0, але достатньо підробити форму, додавши код:

У PHP скрипті змінна $group дорівнюватиме 5, якщо в скрипті вона не була оголошена зі значенням за умовчанням. Фільтрація. Помилка №6. Перевіряйте файли, що завантажуються.
Виконуйте перевірку за такими пунктами:
  • Розширення файлу. Бажано заборонити завантаження файлів із розширеннями: php, php3, php4, php5 тощо.
  • Чи завантажено файл на сервер move_uploaded_file
  • розмір файла
  • Перевірка. Помилка №1. Стикався з випадками, коли для AJAX запиту (наприклад: підвищення репутації) передавалося ім'я користувача або його ID (кому підвищується репутація), але PHP не було перевірки на існування такого користувача.
    Наприклад:
    $user_id = intval($_REQUEST["user_id"]); ... INSERT INTO REPLOG SET uid = "($user_id)", plus = "1" ... ... UPDATE Users SET reputation = reputation+1 WHERE user_id = "($user_id)" ...
    Виходить ми створюємо запис у базі, яка абсолютно марна нам. Перевірка. Помилка №2. При виконанні різноманітних дій (додавання, редагування, видалення) з даними не забувайте перевіряти права користувача на доступ до цієї функції та додаткові можливості (використання html тегів або можливість опублікувати матеріал без перевірки).

    Давно виправляв в одному модулі форуму подібну помилку, коли будь-хто міг відредагувати повідомлення адміністрації.

    Перевірка. Помилка №3. При використанні кількох PHP файлів зробіть просту перевірку.
    У файлі index.php (або будь-якому іншому головному файлі) напишіть такий рядок перед підключенням інших php файлів:
    define ("READFILE", true);
    На початку інших php файлів напишіть:
    if (! defined ("READFILE")) ( exit ( "Error, wrong way to file").
    Go to main."); }
    Так ви обмежите доступ до файлів.Перевірка. Помилка №4. Використовуйте хеші для користувачів. Це допоможе запобігти виклику тієї чи іншої функції шляхом XSS.
    Приклад складання хешу для користувачів:
    $secret_key = md5(strtolower("http://site.ru/" . $member["name"] . sha1($password) . date("Ymd")))); // $secret_key – це наш хеш
    Далі у всі важливі форми підставляйте інпут зі значенням поточного хеша користувача:

    Під час виконання скрипту здійснюйте перевірку:
    if ($_POST["secret_key"] !== $secret_key) ( exit ("Error: secret_key!"); ) Перевірка. Помилка №5. При виведенні SQL помилок зробіть просте обмеження доступу інформації. Наприклад, задайте пароль для GET змінної:
    if ($_GET["passsql"] == "password") ( ... висновок SQL помилки... ) else ( ... Просто інформація про помилку, без подробиць... )
    Це дозволить приховати від хакера інформацію, яка може йому допомогти у зломі сайту. Перевірка. Помилка №5. Намагайтеся не підключати файли, отримуючи імена файлів ззовні.
    Наприклад:
    if (isset($_GET["file_name"])) ( include $_GET["file_name"] .".php"; )
    Використовуйте перемикач

    Я створюю один простий список на PHP, де користувач може додати ім'я, вік, електронні листи і т.д. Я також додав параметр видалення, але я хочу додати підтверджуюче повідомлення, коли користувач натискає кнопку "Видалити".

    Я пробував шукати Google, але знайшов лише jQuery та JavaScript-рішення. Чи є спосіб зробити це лише з PHP?

    Delete.php

    в

    Якщо ви хочете зробити це тільки в PHP, вам потрібно додати "кроки" у свій скрипт, наприклад:

    Step1 (show form) -> step2 (ask validation) -> step3 (validate)

    Для цього можна використовувати сеанси для збереження вмісту форми та параметра GET для відстеження цього кроку. В іншому випадку найпростішим рішенням є використання javascript:

    Echo " x//use double quotes for js inside php!

    Це вам потрібно

    While($query2=mysql_fetch_array($query1)) ( echo " ".$query2["name"].""; echo" ".$query2["age"].""; echo" Edit"; echo" x"; ) в while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["name"].""; echo" ".$query2["age"].""; echo" Edit"; echo" x"; }

    та створити функцію javascript

    Function confirmationDelete(anchor) ( var conf = confirm("Are you sure want to delete this record?"); if(conf) window.location=anchor.attr("href"); )

    повірте мені, це робота 🙂

    Додайте подію onClick щоб викликати діалогове вікно та javascript:return confirm("are you sure you want to delete this?");

    Echo " x";

    function deleletconfig()( var del=confirm("Are you sure you want to delete this record?"); if (del==true)( alert ("record deleted") ) return del; ) //add onclick event onclick ="return deleletconfig()"

    працюйте для мене, але змініть це:

    Onclick="javascript:confirmationDelete($(this));return false;"

    Onclick="confirmationDelete(this);return false;"

    Нижче наведено варіант вище, який дає поле підтвердження і передає змінну від PHP Javascript і назад до PHP.
    Я використав це, щоб вибрати перемикач, щоб видалити файл зі списку файлів.
    Див. Функція запуску OnClick з ім'ям php $ fileName в Javascript, підтвердження з ім'ям файлу, і якщо так, то передача в href зі змінними для $ _GET

    PHP/HTML-код:

    Стаття не про кластери, не про шардинг із реплікацією і навіть не про хмари. Стаття – про побудову високонадійної обчислювальної архітектури, де кількість користувачів та його запитів може зрости лавиноподібно. І для бізнесу критично, щоб веб-сервіс прийняв кожен запит, відпрацював його коректно і до кінця (незалежно від збоїв та падінь якихось компонентів), та гарантовано доставив би відповідь клієнту. Причому, ясна річ, без “космічних” витрат за обладнання і зарплату сисадмінам.

    Інакше кажучи, насамперед подумайте – “чи треба воно мені”. Якщо у когось інтернет-магазин, який торгує хом'яками, що говорять, з обігом 100 замовлень на місяць - швидше ні. А якщо ви плануєте вести бізнес, здатний прийняти сотні тисяч і мільйони користувачів, що вимагає великого об'єму обчислень, працює з високоцінними даними, що гарантує транзакційність кожного бізнес-процесу, що потребує паралельної обробки даних, це саме.

    Фінансовий сектор, великі інтернет-магазини з номенклатурою в сотні тисяч одиниць, інтернет-аукціони, системи бронювання готелів та авіаквитків, нові “хмарні” чи соціальні сервіси з амбіціями отримати мільйонну базу користувачів наступного дня після старту рекламної кампанії – потенційно зацікавлені у високонадійній системі для веб-сервісів.

    Кому адресовано цей матеріал

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

    2. Власникам нових або бізнесів, що розширюються, які передбачають “вибухове” зростання користувальницької бази, і висувають високі вимоги до обчислювальної частини.

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

    Чому так багато слів про “обчислення”?

    Тому що найближче майбутнє великих веб-проектів лежить в області “Big data” (“Великих даних”) – це тренд, який ще у 2011 році був відзначений як один із топових, нарівні з віртуалізацією, енергозбереженням та моніторингом, а з 2013 року міцно зайняв своє місце в індустрії і навіть став одним з академічних предметів у великих зарубіжних університетах.

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

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

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

    Автор цих рядків переконаний, що "класичний" сучасний підхід до побудови високонавантажених веб-сервісів має низку серйозних недоліків. Давайте розберемося чому. Спочатку розглянемо типову сучасну схему:

    Класичний підхід до побудови високонавантаженого веб-сервісу

    1. Багато серверів, поділених на ролі.

    2. Частина серверів (роль Frontend) призначена для віддачі статичних ресурсів (зображень, CSS, JS-файлів) і "розподілу" фронту вхідного трафіку по нижчестоящим вузлам. Основний софт, як правило, Nginx.

    3. Нижчі вузли (роль Backend) займаються динамічними обчисленнями. Простіше кажучи, це може бути типова зв'язка Apache+PHP.

    4. Ще одна група серверів призначена для зберігання даних. Це MySQL, Memcache, Redis тощо.

    5. Сам код веб-сервісу (в даному прикладі – PHP-код) однаково скопійований на всі вузли, де є Apache+PHP, і однаково обробляє запити, які “припали” на той чи інший вузол.

    6. Бази даних з допомогою тієї чи іншої форми шардингу “розмазуються” за групою серверів, і навантаження ними балансується аналогічно.

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

    Недоліки класичного підходу

    1. Основний тренд - ускладнення. З часом життя проекту “класична” схема дедалі більше ускладнюється. З додаванням кожного нового сервера потрібно вводити їх у схему розподілу трафіку. Безумовно, у великих проектах введення сервера у роль – “однокнопкову” дію, проте – це зростання інфраструктури, яку потрібно підтримувати. І тим більше - у разі, коли поточних потужностей під БД вже не вистачає, і потрібно "живо" (без зупинки сервісу) переносити або розносити базу даних на нові сервери.

    Але найголовніша проблема – нарощування кластера розподілу трафіку ніяк не призводить до зниження складності програмного коду. Ви можете бездоганно побудувати кластер, але код залишиться таким самим, як був.

    2. Деплой не атомарний. Говорячи зрозумілими словами, викладання нової версії проекту на бойові сервери займає якийсь час. Потрібно фізично завантажити файли на N-дцять машин, зробити зміни в БД, скинути кеші (багато різних кешів), і одноразово на всіх серверах закінчити обробку запитів "старим кодом" і почати обробку "новим кодом". Інакше може виникнути безліч дрібних конфліктів, коли частина запиту користувача оброблена по-старому, частина по-новому, якась частина лягла в базу даних за старою схемою, частина за новою, і так далі.

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

    3. Використовується HTTP. Протокол HTTP явно застарів морально та технічно, і якщо ви стежите (наприклад) за мобільною розробкою – ви знаєте, що він повсюдно витісняється більш легкими протоколами. Але основний недолік в іншому: протокол HTTP "у браузері" вимагає завершення петлі - вимагає відповіді в обмежений час. Це зобов'язує сервіс обчислити і підготувати відповідь суворо в той невеликий тайм-аут, який дозволяє браузер. Якщо сервіс зараз перевантажений – запит буде втрачено безповоротно.

    Тому в "типових веб-проектах" вдаються до різних хитрощів типу Long polling або іншої форми періодичних запитів, що не тільки ускладнює архітектуру, а й перевантажує сервіс зайвим "смиканням даремно".

    4. Ініціалізація скрипта на кожен запит. Це наслідок використання HTTP і скриптових мов на кшталт PHP, які за давно усталеної традиції запускаються заново у відповідь кожен запит. Так-так, у відповідь на кожен із 1000 запитів на секунду PHP-скрипт стартуватиме заново, ініціалізуватиме всі змінні заново, встановлюватиме з'єднання з БД заново. На практиці буває так, що на обробку запиту потрібно 0.005 секунд, а скрипт ініціалізується близько 0.05 секунд - в десять разів довше!

    Іншими словами, 90% часу ваші сервери зайняті не обробкою запитів клієнтів, а марною ініціалізацією скриптів. Спробуйте переказати це в гроші. Тому придумана маса обхідних шляхів на кшталт OPcode-кешування, персистентних коннекшенів до БД, локальних кешів на зразок Memcache або Redis, призначених для того, щоб погасити цей неприємний ефект.

    5. Монолітне додаток. Як би ви не ділили додаток на модулі, як би не намагалися розносити код за складною структурою каталогів, якою б lazy autoloading ви не використовували – критерій один: якщо для викладення хоча б однієї зміни вам потрібно викласти додаток цілком – у вас монолітний додаток. Іншого не дано.

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

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

    6. Веб-інтерфейс малюється бекендом. У типовому випадку зовнішній вигляд (і відповідно HTML-код) сторінок проекту відображається на стороні Backend-а, ​​як правило, у відповідь на кожен запит. Це надмірна, нічим не виправдана витрата ресурсів та грошей.

    7. Політичний поділ відділів. Відділ системних адміністраторів відповідає за те, щоб вхідний фронт трафіку був "розмазаний" купою серверів, на яких крутиться PHP-код. Відділ програмістів відповідає за PHP-код. Якщо PHP-код не встиг обробити якийсь конкретний запит, то за це відповідає незрозуміло хтось – або адмін, який “пустив” надто багато трафіку на сервак і перевантажив його, або програміст, який написав неоптимальний скрипт. Якщо починає гальмувати база даних - то теж незрозуміло хто залишається крайнім: адмін, який не зрозумів вчасно її "пошардити", або програміст, який теж міг би збагнути.

    Якщо приклади вам здаються перебільшеними і "не з реального життя", згадайте, що автор працював у проекті, який розміщувався на 200 серверах, причому 60 з них були зайняті під БД. Скільки людей зайнято під обслуговування цього проекту – страшно згадати.

    Основний недолік

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

    Теоретичний ідеал

    Ах, як би нам хотілося, щоб можна було:

    1. Відмовитися від купи дорогих серверів та використовувати одну-дві невеликі групи.

    2. Відмовитися від схеми Nginx->Apache->PHP з її диким "оверхедом" за споживаними ресурсами, які коштують грошей.

    3. Виключити жахливі витрати на ініціалізацію PHP-скриптів з тієї ж причини.

    4. Відмовитися від необхідності “малювати” сторінки на бекенді. Було б зовсім мрією, якби веб-сервіс міг працювати при нестабільному або відсутньому інтернет-з'єднанні (наприклад, при використанні мобільної мережі в дорозі).

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

    6. Оновлювати проект невеликими частинами, без зупинки та без втрат жодного запиту клієнта.

    7. Не турбуватися про втрати запитів, якщо частина проекту (якийсь компонент) “упала” або була тимчасово вимкнена з метою налагодження.

    Нереально? Легко!

    Перші кроки до ідеалу

    Спочатку засвоїмо, щотреба зробити, тому обговоримо – як.

    1. Спроектуйте всю систему як SOA (сервісно-орієнтовану архітектуру) з ESB (шиною обміну повідомленнями підприємства), відмовившись від монолітного підходу, щоб кожну незалежну частину бізнес-логіки обробляв окремий "сервіс", а між собою вони спілкувалися б по незалежній шині обміну .

    2. Відмовтеся від синхронності . Наприклад, у синхронній схемі “запит – обробка – відповідь” це одна петля HTTP, яка не має жорсткого контролю завершеності та легко може перерватися. В асинхронній – три окремі процеси: запит (надіслано та підтверджено), обробка (з повтором у разі збою), доставка відповіді (з гарантією).

    3. Поділіть проект на дві програми – Frontend і Backend. У випадку веб-сервісу, фронтенд – це (як правило) JavaScript-додаток. Суть у тому, щоб програми працювали асинхронно та розв'язано щодо один одного, обмінюючись повідомленнями за двостороннім протоколом зв'язку.

    4. Відмовтеся від HTTP на користь WebSocket. Протокол WebSocket має фантастичну швидкодію в порівнянні з HTTP, не має ніяких "петель з тайм'ятами", і дозволяє передавати в обидві сторони будь-які дані (у тому числі бінарні).

    5. Забезпечте “зберігання” запитів . Як тільки запит прийнято від клієнта, скажіть йому “Confirm” та збережіть цей запит. Як тільки бекенд звільниться від попереднього циклу обробки, передайте запит йому. Поки запит "іде" між вузлами бекенда, зберігайте його з моменту, коли він "увійшов" у вузол і фіксуйте його як тільки він "вийшов" з вузла. Таким чином, якщо якийсь вузол "впаде", система не втратить запит і відразу направить його знову в обробку. Після закінчення обробки направте результат клієнту, і зберігайте його до того часу, поки клієнт не скаже “Confirm”.

    6. Забезпечте паралельність обчислень для операцій, які можуть виконуватися паралельно з точки зору бізнес-логіки, і послідовність для тих, які повинні виконуватися суворо послідовно. Цей пункт написаний не з претензією на "Капітана Очевидність", а щоб показати, що не будь-який бізнес-процес можна "наосліп покласти" на багатопоточний код.

    7. Відмовтеся від написання скриптів на користь "демонів". Демон - процес, що запускається одноразово і далі постійно "висить" у пам'яті. Так як він працює постійно, йому не потрібно витрачати час на переініціалізацію на кожний запит. Забігаючи вперед, скажу, що PHP-демон (при використанні сучасних версій PHP) не має принципових відмінностей від звичайного PHP-скрипту.

    Підхід до проектування SOA

    SOA – сервісно-орієнтована архітектура – ​​не новомодна течія. Цей модульний підхід до розробки ПЗ був ініційований IBM ще в минулому столітті, і в даний час підтримується і просувається лідерами індустрії, в основному в продукції ентерпрайз-рівня мовами.NET і JAVA.

    У класичному підході до програмування веб-сервісів мовами PHP та аналогічних – проектування починається від моделей, їх властивостей та операцій над ними. Моделі відображають об'єкти реального світу, а операції дії над об'єктами. Однак, як показує практика, реальний світ набагато багатогранніший і складніший, і набагато ефективніше описується мовою подій і реакцій на них (докладніше цьому присвячений пост #1593з описом та прикладами).

    Реальний світ складається з подій, які відбуваються одночасно (у термінах програмування – “паралельно”) і переважно без нашої участі, і на які виникають чи не виникають різні реакції. Реакції, своєю чергою, можуть породжувати такі події. Архітектура SOA ідеально підходить для "програмування реального світу", тому що в ній найбільш зручно оперувати подіями, зв'язками між ними та реакціями на них. Причому при правильному підході до організації архітектури, і події та реакції на них будуть відбуватися паралельно, навіть якщо ви використовуєте “однопоточну” мову програмування на кшталт PHP.

    Проектувати SOA-продукт потрібно виходячи з того, які події відбуваються у вашій бізнес-логіці, як вони пов'язані один з одним або повинні слідувати один за одним, які реакції повинні відбуватися у відповідь на ті чи інші події, і хто конкретно оброблятиме ті чи інші інші події. Реалізація моделей даних та дій над ними відходить на другий план (інкапсулюється в “сервіс”), а на перший план ставиться список “сервісів” та план взаємодії між ними (міжсервісне API).

    Реалізація: перше наближення

    1. Фронтенд як незалежний додаток. Для реалізації підійде будь-який популярний JavaScript-MVC-фреймворк. Однак, зауважу з практики, якщо у вас починають нити зуби при поєднанні слів "JavaScript, MVC і фреймворк" в одному реченні - вам буде важкувато. Додаток повинен вміти малювати всі свої "екрани" без звернення до бекенду, давати користувачеві навігацію (переходи між "екранами") також без звернення до бекенду, та підтримувати двонаправлений канал зв'язку з бекендом.

    2. Точка входу для WebSocket-з'єднання з бекендом. Є ряд готових рішень на NodeJS, які до того ж підтримують fallback запитів на long-polling та ajax для ідеологічно застарілихбраузерів. Зауважу на майбутнє, що до цього вузла можна буде звертатися і на чистому HTTP, якщо вам потрібно буде писати якісь шлюзи з чужими сервісами, проте для спрощення можна буде написати і окремий "чисто-HTTP" вузол.

    Точка входу забезпечуватиме двонаправлений канал зв'язку з фротенд-додатком (простіше кажучи – з браузером), приймаючи від нього запити та повертаючи йому відповіді.

    3. Зберігання протікають запитів у системі. Для цього якнайкраще підійде популярний AMQP-сервер, що забезпечує черги повідомлень та роутинг між ними. Як тільки надійшов черговий запит від клієнта, помістіть його в чергу "вхідних". Далі, з цієї черги він буде вилучений демоном, який проаналізує вміст запиту і відправить його в "роутинг" за системою (що фактично означає переклад у одну або кілька черг за певними алгоритмами). Кожен демон, який займається своєю частиною бізнес-логіки, отримуватиме те чи інше повідомлення зі “своєї” вхідної черги, проводитиме його обробку і поміщатиме відповідь у “вихідну” чергу.

    Зауважу, що в термінології популярного брокера RabbitMQ немає поняття вихідних черг. Повідомлення публікуються в exchange (обмінник), звідки самим брокером перекладаються у конкретні черги згідно з правилами роутингу. Тут же так написано для умовного розуміння, що відповідь не надсилається тому, хто запитав.

    4. Управління демонами (супервізор). Щоб запустити найпростіший PHP-скрипт як демон, достатньо обернути виконуваний код у while(true) (…) і набрати в командному рядку щось на кшталт “php your-script.php”. Але краще для цього використовувати будь-який відповідний супервізор, який зробить по суті те саме, але ще й забезпечить необхідний стан середовища, стежитиме за станом процесу і робитиме ще деякі корисні штуки.

    У реальному житті PHP-демон робиться трохи складніше: він повинен отримувати керуючі сигнали і повідомлення про переконфігурацію, повинен "не текти" по пам'яті, повинен підтримувати (або відновлювати з'єднання з БД, що впали) - але в цілому він не складніше звичних вам PHP-скриптів .

    На крок ближче до реальності: подієво-орієнтований підхід у SOA

    Деякі (на думку автора – застарілі) підходи до побудови модульних додатків базуються на принципі RPC (Remote Procedure Calling), який має на увазі прямий виклик конкретних методів чи процедур у віддаленому компоненті проекту. Такий підхід на корені знищує всі переваги SOA, оскільки зазвичай означає прямий і жорсткий зв'язок між відправляючим і виконуючим вузлами. У проектуванні та реалізації складного продукту слід максимально дотримуватися принципу слабозв'язаності компонентів, оскільки саме складність архітектури та коду врешті-решт визначатиме вартість володіння (внесення виправлень та змін до продукту після його запуску).

    Подієво-орієнтований підхід у SOA передбачає, що компоненти (сервіси) спілкуються між собою шляхом відправки асинхронних подій ( "евентів", від слова Event). Подія – це повідомлення (наприклад, у термінології AMQP), яке має назву (ім'я) та набір параметрів. Подія призначена для того, щоб повідомити систему, що щось сталося, або для того, щоб "задати питання" системі. У загальному випадку події відправляються “в систему” (точніше – у загальну шину ESB) безадресно – тобто без конкретних намірів щодо доставки конкретним вузлам або виконавцям.

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

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

    Подієва модель SOA у програмному коді

    Коротко кажучи, вам потрібно дивитися на свій код не як на класи з функціями (методами), а як на події та дії, які відбуваються як реакція на ці події. Причому результати дій теж події. Стосовно обговорюваної архітектури, можна сказати, що локальні події - це події, що відбулися всередині конкретного PHP-скрипту, а віддалені події - це події, що прийшли в цей скрипт з черги AMQP (або туди, що відправляються, як результат). Якщо ви розглядатимете весь свій код саме так, то це негайно призведе до дивовижного і дуже важливого ефекту:

    Якщо локальні та віддалені події – це те саме, те й локальні та віддалені обробники – це одне й те саме!

    Чому так важливо? Тому, що програмісти вашої команди продовжують писати звичайний PHP-код, не замислюючись, де буде оброблена та чи інша подія – тут же в цьому чи сусідньому PHP-скрипті, або десь на іншому кінці системи, в іншому демоні, хоч на іншому мовою програмування. Якщо ви робите проект із публічним API – то будь-який сторонній учасник зможе “підписати” свій код на ваші події (і обробляти їх), або навпаки – надсилати вам свої, щоб ви обробляли його події як запити (і отримували за це гроші, якщо ви використовуєте бізнес-модель SAAS з оплатою за ресурси, що споживаються, як Amazon).

    Згадайте, що ми називали основним недоліком великих класичних веб-проектів – безперервно зростаючускладність, а отже – вартість володіння, вартість підтримки та внесення змін. У випадку з подійною SOA-архітектурою – складність безперервно зменшується, оскільки “складні вузли” легко ділити на незалежні послуги (у разі – демони), у своїй принципи роботи системи залишаються постійними, та її швидкодія лише збільшується.

    Деплой нової версії без втрат поточних процесів

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

    Ви просто вимикаєте сервіс, який потрібно оновити. Оновлюєте його код та структуру БД (за потреби), потім запускаєте знову. Усі поточні запити до цього сервісу чекатимуть у черзі AMQP, доки сервіс не підніметься. Зауважу, що оскільки сервіси маленькі (невелика кількість коду, необхідна для вирішення лише невеликої частини бізнес-логіки), це відбувається набагато швидше, ніж деплой цілої монолітної програми. Але в будь-якому разі – втрат не станеться.

    Проблеми з веб-інтерфейсом

    Швидкий, чуйний веб-інтерфейс – необхідна умова високонавантаженого проекту. Давайте розберемося, а чому взагалі веб-інтерфейс може "гальмувати" при класичному підході до реалізації:

    1. Інтерфейс малюється на бекенді, який перевантажений і робить це повільно. Повільно переходить між сторінками. Навіть із застосуванням AJAX – блоки перемальовуються надто повільно.

    2. Вихідний код інтерфейсу (HTML, CSS, JS) надмірний і повільно передається каналами зв'язку, особливо якщо це робиться при завантаженні кожної сторінки в процесі навігації користувача за інтерфейсом.

    3. Інтерфейс містить велику кількість неоптимізованої JavaScript-логіки, яка повільно працює на слабких пристроях (насамперед – на мобільних).

    Спробуємо вирішити ці проблеми:

    Як зробити швидкий та чуйний веб-інтерфейс

    1. По-перше, і найголовніше, вихідний код інтерфейсу повинен передаватися клієнту не більше одного разу. Єдиний цивілізований спосіб цього досягти – зробити повноцінний JavaScript-додаток. Воно завантажується клієнту один раз (при цьому можна показати гарний анімований прелоадер), і далі за весь час роботи з сервісом - клієнту більше не потрібно чекати на завантаження.

    2. Всі переходи між “екранами” веб-інтерфейсу повинні виконуватися всередині JavaScript-додатку, а в жодному разі не як окремі запити до бекенду. Є відповідний термін - "односторінковий веб-додаток", в якому навігація по суті виконується шляхом перемикання "екранів", при цьому вміст адресного рядка динамічно змінюється, створюючи повне відчуття класичних "переходів по сторінках".

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

    Таким чином, користувачеві потрібне інтернет-з'єднання тільки для первинного завантаження програми (кілька секунд). Далі він може працювати з сервісом навіть за тимчасової відсутності підключення (наприклад з мобільного пристрою в метро, ​​за містом, у перенаселеному готелі за кордоном і т.д.) – додаток фіксуватиме запити і намагатиметься їх відправити, як тільки з'явиться інтернет, і таким ж буде отримувати відповіді.

    Звичайно, це не позбавляє розробника необхідності оптимізувати і мінімізувати код. Однак, як показує практика (наприклад сервіс Trello), це завдання нітрохи не складніше за інші.

    Примітка для розробників веб-сервісів для мобільних пристроїв, що сумніваються: за практикою автора, в 2013 році односторінкові JavaScript-додатки на вебсокет-транспорті - успішно працюють на iPad.

    Робота користувача з кількох пристроїв

    З роботи він користується вашим сервісом з робочого настільного комп'ютера, дорогою додому дістає айфон, а вдома включає планшет. Якщо користувач відправив з інтерфейсу якусь команду в сервіс, він чекає відповіді результати обробки. Легко зрозуміти, що якщо (коли) обробка зайняла якийсь відчутний час, відповідь треба надіслати саме до того пристрою, яким користувач користується (вибачте за каламбур) на момент доставки відповіді, а чи не на момент запиту.

    Проблема в тому, що не можна однозначно сказати, чи припинив користувач користуватися (вибачте ще раз) тим чи іншим конкретним пристроєм. Можливо, він закрив браузер. Можливо, в нього сіла батарея. Можливо, він поїхав у тунель метро, ​​де немає зв'язку, а за півхвилини з'явиться знову. Варіантів маса, і автору невідомий найкращий спосіб визначення. Однак, ось що вам може стати в нагоді:

    1. Фіксуйте (на бекенді) всі пристрої користувача та час останньої активності кожного з них.

    2. Класифікуйте події в системі, про які треба повідомляти користувачеві, на ті, які треба доставляти тільки в активні пристрої, і ті, які треба доставляти широкомовно (в усі пристрої).

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

    4. Забезпечте чергу надсилання кожному користувачеві по кожному окремому каналу зв'язку (веб-інтерфейс, мобільний пристрій, пошта). Стандартний функціонал AMQP допоможе вам і з таймаутами старіння повідомлень, щоб вони лежали там не довше за певний час і не засмічували систему. Коли користувач з'явиться "на зв'язку" через той чи інший конкретний канал, йому будуть доставлені свіжі повідомлення, що очікують конкретного типу.

    Автор може доповнити, що на основі цієї системи можна побудувати і відкладене відправлення повідомлень (які будуть відправлені не раніше певної дати), і навіть відправлення реальної паперової періодичної кореспонденції (актів, платіжок і т.д.), але це – тема окремої статті .

    Підкреслю головне: не розглядайте повідомлення, що доставляють, як деякі нотифікації, звичні вам по "Facebook" або "Вконтакте". Надіслані повідомлення – це саме результати запитівкористувача! Всі дії користувача в інтерфейсі, що мають на увазі якісь запити до бекенду, отримують відповіді в однаковому вигляді "повідомлень, що доставляються", по єдиному уніфікованому каналу зв'язку. А далі алгоритм веб-додатку розбирається, що треба зробити з тим чи іншим повідомленням – відмалювати нотифікацію з текстом, додати рядок у таблиці, переключити щось в інтерфейсі і так далі.

    Паралельні та послідовні обчислення

    Було б марно проектувати швидкодіючий веб-інтерфейс на фронтенд, якщо у вас повільний бекенд. Ні, мова піде не про потоки, не про форки та не про Erlang. Залишаємося на звичайному PHP, доступному будь-якому початківцю/середньому програмісту.

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

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

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

    1. До системи надійшов запит на включення опції.
    2. Авторизуємо користувача та з'ясовуємо його тарифний план.
    3. Перевіряємо, чи можна взагалі включити цю опцію за тарифним планом користувача.
    4. Перевіряємо, чи достатньо у користувача грошей на рахунку.
    5. Перевіряємо, чи ця опція не суперечить якимось іншим налаштуванням.
    6. Якщо все окей, то вмикаємо опцію.
    7. Надсилаємо повідомлення у браузер.
    8. Надсилаємо повідомлення поштою.
    9. Списуємо гроші у білінгу.
    10. Повідомляємо клієнтський відділ.

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

    Що ми бачимо? Зауважте, що немає жодних підстав виконувати всі дії послідовно. Набагато правильніше було б "розпаралелити" 3,4,5 в три потоки, і в кінці - 7,8,9,10 в чотири потоки.

    Задумалися про потоки та форки? Даремно, у вас є SOA!

    Як зробити паралельні обчислення в SOA

    Читачам, які тільки прогорнули статтю до цього місця, поясню, що мова не про паралелізацію одного і того ж завдання в SOA – для цього в загальному випадку достатньо запустити демона в N інстансів і подбати про конкуренцію доступу до БД.

    Отже, у нас у цьому прикладі є три-чотири кілька різних завдань, які виконуються різними сервісами, і які ми хочемо виконати паралельно. Надіслати їх у паралельну обробку нескладно: достатньо відправити одну подію "чи може користувач username включити опцію X?", і всі підписані на цю подію сервіси - зловлять її, проведуть свої перевірки, і віддисчать результуючі події.

    Проблема якраз у тому, щоб ці результуючі події зібрати, коли нам потрібен сумарний результат їхньої роботи, щоб рухатися далі. Наприклад, у наведеному вище списку результат 3+4+5 нам потрібен, а 7+8+9+10 – можна ігнорувати.

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

    Звичайно, якщо наш демон "висітиме і чекатиме", споживаючи ресурси (так званий "холостий хід"), то ніякий високонавантажений сервіс так не побудуєш. Сенс якраз у тому, щоб демон вирішував інші завдання та обслуговував інші запити інших клієнтів, поки три окремі потоки (3,4,5) займаються вирішенням своїх підзадач. Проблем додає і те, що результуючі події можуть приходити в довільному порядку. Однак все це вирішується легко та просто:

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

    1. Перед тим, як відправити подію в AMQP, фіксуйте у швидкій пам'яті (скористайтеся будь-яким відповідним in-memory storage) перелік імен результуючих подій, які сервіс очікує отримати, а також ім'я події (назвемо його “R”), яку потрібно віддиспатчити із сумою результатів.

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

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

    4. В іншому випадку, тобто якщо за всіма подіями у списку надійшла відповідь, сервіс склеює їх та диспатчить склеєний результат під ім'ям події “R”, запам'ятаної раніше. Після цього, з метою збереження пам'яті, список з результатами з пам'яті просто видаляється - він більше не потрібен.

    5. Той самий сервіс, або якийсь інший (на розсуд проектувальника системи) отримує результуючу подію "R" з усіма результатами паралельної обробки. Далі – очевидно.

    Якщо з опису вам здалося, що це довго, то поясню – мова йде про тисячі та десятки тисяч подій за секунду (!) на одному середньому сервері.

    Використання in-memory storage припускає, що навіть при зупинці (падінні, оновленні) сервісу – поточний бізнес-процес не буде втрачено. Після того, як сервіс знову буде запущений, він продовжуватиме отримувати події з ESB та обробляти їх за вищеописаним алгоритмом.

    Транзакційність, відкат операцій (rollback) та fail-сценарії у SOA

    Оскільки в SOA через ESB “ходять” рівноправні події – вам потрібна якась ознака, щоб вказати, що “ось ця відповідь” стосується “він до того запиту”. Тут не потрібно винаходити жодних велосипедів – у специфікаціях будь-якого популярного протоколу ви знайдете параметр під назвою типу correlation_id. Як правило, це рядок. Вона повинна міститися в параметрах всіх подій кожного окремого бізнес-процесу, від входу до виходу, щоб ідентифікувати ланцюжок повідомлень на належність цього бізнес-процесу. Дивлячись з боку веб-інтерфейсу, веб-додаток зберігає поточні активні (надіслані) запити і по correlation_id “розуміє”, у відповідь на який запит надійшла кожна конкретна відповідь.

    Розберемося з термінологією: транзакційність – властивість системи виконувати кілька дій як одну загальну операцію, яка має сенс і може бути завершена лише повністю. Оскільки у розподіленій системі з паралельними потоками фізично неможливо атомарно виконати кілька операцій, у системі передбачаються звані fail-сценарії і ролбеки (rollback).

    Fail-сценарій у загальному випадку – це дія, яку потрібно виконати у разі виникнення помилки. Rollback - це, в даному контексті, сценарій дій, який потрібно виконати для "скасування" ряду попередніх дій, які зрештою призвели до помилки. Грубо кажучи, ролбеки – це процеси, обернені до нормальних бізнес-процесів у системі.

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

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

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

    Масштабування SOA

    Будь-яка система рано чи пізно потребуватиме розширення. У випадку з SOA це робиться легко і невимушено:

    1. Дублювання точки входу. Мається на увазі той самий WebSocket-шлюз, який ми розглядали на початку статті. Його можна дублювати необмежену кількість разів, оскільки спілкування між ним та клієнтом уніфіковано та відв'язане від нутрощів системи, а спілкування між ним та системою – у свою чергу, відв'язане від комунікацій з клієнтом.

    2. Дублювання інстансів (примірників) сервісів. Безпроблемно дублюються послуги, що не вимагають БД або тільки "читають" з них. А штатний функціонал RabbitMQ дозволить підписати N інстансів на ту саму чергу, повідомлення з якої будуть випадковим чином приходить в той чи інший інстанс. При дублюванні сервісів, що мають справу із зовнішніми програмами (бази даних, сторонній софт) необхідно враховувати, як ці програми забезпечують транзакційність запитів від кількох паралельних клієнтів.

    3. Дублювання сховищ даних. Тут ви вільні застосовувати будь-який відомий вам шардинг. Якщо ви маєте справу з 10 мільйонами користувачів і вам це здається багато, поділіть їх на 10 баз по мільйону (наприклад, на основі CRC32 від логіну користувача або іншим циклічним методом). Якщо база даних одного сервісу безперервно зростає та ускладнюється, розділіть його на два сервіси.

    4. Дублювання AMQP-брокера та In-memory Storage. З практики автора, RabbitMQ та Redis чудово виконують свою роль. Якщо у вас обладнання не в одній стійці ДЦ, вибирайте режим раббіта, толерантний до збоїв мережевих з'єднань.

    5. Дублювання машин цілком. З сучасними технологіями віртуалізації (KVM) та конфігурації (Chef), завдання "підняти таку саму машинку" зводиться до натискання однієї кнопки.

    Шифрування трафіку між фронтендом та бекендом

    Рекомендується організовувати WebSocket з'єднання через SSL. У плюс до всього, так підвищується "пробивна здатність" проти відсталих офісних провайдерів, які блокують "будь-який дивний трафік" крім HTTP [S].

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

    Захист від DDOS та аналогічних зловживань

    Автор навмисно опускає питання про “низькорівневий” захист, коли йдеться про SYN-флуд та заливання каналів сотнями гігабіт, оскільки про це написано сотні книг спеціалізованої літератури. Поговоримо про те, як захистити систему вже всередині, на її логічних рівнях, коли зловмисник знайшов спосіб заливати вашу систему (SOA+ESB) тисячами подій.

    1. Перше правило: нічого не повинно оброблятися, доки не підтверджено його валідність. Якщо ви очікуєте на вхід невеликий текст в JSON, обгорнутий в BASE64, то рядок, що прийшов, довше мегабайта явно повинен бути відкинутий - не намагайтеся його розпакувати. Рядок, що містить "нелатинські" символи - аналогічно. Коли ви розпакували рядок – не намагайтеся відразу зробити json_decode, спочатку перевірте кількість та парність дужок. І так далі.

    Схоже на параною, але в іншому випадку вас легко можна буде "завалити по пам'яті", тобто призвести до відмови сервісу, змусивши зайняти всю доступну йому оперативну пам'ять.

    2. Сервіс, що обробляє вхідні повідомлення, не повинен нічого писати на згадку, в БД, та інші сховища. Причина та сама. Спочатку переконайтеся, що повідомлення загалом валідно, а потім пропускайте його “глибше” в систему.

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

    4. На вході в систему потрібен сервіс, що відкидає запити від "підозрілих" джерел, наприклад, від IP-адрес з "чорного списку".

    Начебто б класичні поради, то в чому ж справа? Основна проблема в тому, що якщо ми поставимо аналізуючий-фільтруючий сервіс на вході в систему (як робиться в класичних веб-проектах), то продуктивність усієї системи буде не вищою, ніж продуктивність цього аналізатора-фільтра. Розглядати кожне повідомлення на підозрілість “насправді” надзвичайно дорого. Можна і потрібно зробити це постфактум, і ось як:

    1. Зробіть сервіс, який “слухатиме” всі повідомлення у системі. У RabbitMQ це досягається шляхом підписки на routing key “#”.

    2. Навчіть цей сервіс певним правилам, за якими він зможе діагностувати "підозрілих" відправників. Наприклад, це відправники які надсилають занадто багато схожих повідомлень за інтервал часу, або які надсилають повторювані повідомлення, або які надсилають повідомлення від імені одного користувача з різних IP-адрес... Варіантів маса, увімкніть фантазію. При цьому немає значення, наскільки швидко спрацює такий сервіс (у розумних межах, звичайно) – на швидкість роботи всієї системи він не впливає.

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

    4. Поставте на вході дуже простий і швидкодіючий демон – фільтруючий сервіс, завданням якого буде входити просто “тупа” блокування підозрілих відправників. Жодного аналізу, ніякого розбору, жодних зайвих витрат. Про те, кого вважати підозрілими, легко здогадатися: сервіс дізнаватиметься про них із подій, описаних у попередньому пункті, та поповнюватиме ними свій внутрішній чорний список.

    Кінець першої частини. Продовження: SOA: розподілена архітектура та її обслуговування .

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