Материалът е предназначен предимно за начинаещи уеб програмисти.

Въведение.

Често към мен се обръщат клиенти, които имат самостоятелно написана CMS или модули, инсталирани от начинаещи уеб програмисти, които не разбират какво е необходимо за защита на данните и често копират филтриращи функции, без да се замислят как работят и какво точно трябва да се направи с тях.

Тук ще се опитам да опиша възможно най-подробно. често срещани грешкипри филтриране на данни в PHP скрипти дай прости съветикак правилно да филтрирате данните.

В мрежата има много статии за филтриране на данни, но те, както трябва, не са пълни и без подробни примери.

Дебрифинг.

Филтриране. Грешка №1
За числови променливи се използва следната проверка:
$число = $_GET["въведено_число"]; if (intval($number)) ( ... изпълни SQL заявка... )
Защо води до SQL инжекция? Въпросът е, че потребителят може да посочи променлива входно_числозначение:
1"+ОБЪЕДИНЕНИЕ+ИЗБЕРЕТЕ
В такива случаи проверката ще бъде премината успешно, т.к функцията intval получава целочислената стойност на променливата, т.е. 1, но в самата променлива $номернищо не се е променило, значи зловреден кодще бъдат предадени на SQL заявката.
Правилно филтриране:
$number = intval($_GET["input_number"]); if ($number) ( ... изпълни SQL заявка... )
Разбира се, условието може да се промени, например ако трябва да получите само определен диапазон:
ако ($номер >= 32 И $номер<= 65)

Ако използвате квадратчета за отметка или множествен избор с числови стойности, проверете това:
$checkbox_arr = array_map("intval", $_POST["чекбокс"]);
array_map
Срещам и филтриране във формата:
$number = htmlspecialchars(intval($_GET["input_number"]));
htmlspecialchars
Или:
$number = mysql_escape_string(intval($_GET["input_number"]));
mysql_escape_string

Нищо друго освен една усмивка не може да го причини :)

Филтриране. Грешка №2.
За низови променливи се използва следното филтриране:
$input_text = addslashes($_GET["input_text"]);
Функцията addslashes избягва спецификацията. символи, но не отчита кодирането на базата данни и е възможно да се заобиколи филтрирането. Няма да копирам текста на автора, който описа тази уязвимост и просто ще дам връзка към Крис Шифлет (можете да потърсите превода в Runet).

Използвайте функцията mysql_escape_string или mysql_real_escape_string, например:
$input_text = mysql_escape_string($_GET["input_text"]);
Ако нямате намерение да влизате html тагове, тогава е най-добре да направите следното филтриране:
$input_text = strip_tags($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
strip_tags - премахва html таговете.
htmlspecialchars - конвертира специални. символи в html обекта.
Това е начинът, по който се предпазвате от XSS атаки, в допълнение към SQL инжектирането.
Ако имате нужда от html тагове, но само за показване на изходния код, тогава е достатъчно да използвате:
$input_text = htmlspecialchars($_GET["input_text"]); $input_text = mysql_escape_string($input_text);

Ако за вас е важно стойността на променливата да не е празна, използвайте функцията trim, например:
$input_text = trim($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);

Филтриране. Грешка #3.
Става въпрос за търсене в базата данни.
За да търсите по числа, използвайте филтрирането, описано в първата грешка.
За търсене по текст използвайте филтрирането, описано във втората грешка, но с резерви.
За да попречите на потребителя да извърши логическа грешка, трябва да премахнете или да избегнете специалния. SQL знаци.
Пример без добавка. редова обработка:
$input_text = htmlspecialchars($_GET["input_text"]); // Търсене: "%" $input_text = mysql_escape_string($input_text);
В резултат на това получаваме запитване като:
... WHERE text_row LIKE "%".$input_text."%" ... // WHERE text_row LIKE "%%%"
Това значително ще увеличи натоварването на основата.
В моя скрипт използвам функция, която премахва знаците, които не искам от търсенето:
функция strip_data($text) ($кавички = масив ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!"); $goodquotes = масив ("-", "+", "#"); $repquotes = масив ("\-", "\+", "\#"); $text = trim(strip_tags($text)); $text = str_replace($quotes, "", $text); $text = str_replace($goodquotes, $repquotes, $text); $text = ereg_replace(" +" , " ", $text); върнете $text; )
Разбира се, не всички от горните символи са опасни, но в моя случай те не са необходими, така че извършвам търсене и замяна.
Пример за използване на филтриране:
$input_text = strip_data($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
Също така ви съветвам да ограничите броя на знаците в търсенето, поне не по-малко от 3, т.к. ако имате голям брой записи в базата данни, тогава търсенето на 1-2 знака значително ще увеличи натоварването на базата данни.
Филтриране. Грешка #4.
Стойностите на променливите не се филтрират $_COOKIE. Някои хора смятат, че тъй като тази променлива не може да бъде предадена през формата, това е гаранция за сигурност.
Тази променлива е много лесна за фалшифициране от всеки браузър чрез редактиране на бисквитките на сайта.
Например, в една добре позната CMS имаше проверка на използвания шаблон на сайта:
if (@is_dir (MAIN_DIR . "/template/" . $_COOKIE["skin"]))( $config["skin"] = $_COOKIE["skin"]; ) $tpl->dir = MAIN_DIR . "/шаблон/" . $config["скин"];
В този случай можете да промените стойността на променливата $_COOKIE["скин"]и генерира грешка, в резултат на което ще видите абсолютния път до папката на сайта.
Ако използвате стойността на бисквитките, за да запазите в базата данни, тогава използвайте една от гореописаните филтрации, същото важи и за променливата $_SERVER.
Филтриране. Грешка #5.
Включена директива регистър_глобали. Не забравяйте да го изключите, ако е включен.
В някои ситуации е възможно да се предаде стойността на променлива, която не трябва да се предава, например, ако сайтът има групи, тогава за група 2 променливата $group трябва да е празна или равна на 0, но е достатъчно да фалшифицирате формуляра, като добавите кода:

Променлива в PHP скрипт $групаще бъде равно на 5, ако не е декларирано със стойност по подразбиране в скрипта.
Филтриране. Грешка №6.
Проверете изтеглените файлове.
Проверете за следното:
  1. Разширение на файл. Препоръчително е да деактивирате зареждането на файлове с разширения: php, php3, php4, php5 и др.
  2. Файлът качен ли е на сървъра move_uploaded_file
  3. размер на файла
Преглед. Грешка №1.
Попаднах на случаи, когато за AJAX заявка (например: увеличаване на репутацията) се предава потребителско име или ID (на когото се увеличава репутацията), но самият PHP не проверява за съществуването на такъв потребител.
Например:
$user_id = intval($_REQUEST["user_id"]); ... INSERT INTO REPLOG SET uid = "($user_id)", plus = "1" ... ... UPDATE Потребители SET репутация = репутация+1 WHERE user_id = "($user_id)" ...
Оказва се, че създаваме запис в базата данни, който е напълно безполезен за нас.
Преглед. Грешка №2.
Когато извършвате различни действия (добавяне, редактиране, изтриване) с данни, не забравяйте да проверите правата на потребителя за достъп до тази функция и допълнителни функции (използване на htmlтагове или възможност за публикуване на материал без проверка).

Дълго време поправих подобна грешка в един форумен модул, когато всеки потребител можеше да редактира съобщението на администрацията.

Преглед. Грешка #3.
При използване на множество php файловенаправете проста проверка.
Във файл index.php(или във всеки друг главен файл) напишете този ред, преди да включите други php файлове:
define("READFILE", true);
В началото на други php файлове напишете:
if (! дефиниран ("READFILE")) ( изход ("Грешка, грешен начин за файл.
Отидете на главния."); }
Това ще ограничи достъпа до файловете.
Преглед. Грешка #4.
Използвайте хешове за потребителите. Това ще помогне да се предотврати извикването на определена функция от XSS.
Пример за компилиране на хеш за потребители:
$secret_key = md5(strtolower("http://site.ru/" . $member["име"] . sha1($password) . date("Ymd"))); // $secret_key е нашият хеш
След това във всички важни форми заменете въведеното със стойността на текущия хеш на потребителя:

По време на изпълнение на скрипта проверете:
if ($_POST["secret_key"] !== $secret_key) ( изход ("Грешка: secret_key!"); )
Преглед. Грешка #5.
Когато извеждате SQL грешки, направете просто ограничение на достъпа до информация. Например, задайте парола за GET променлива:
if ($_GET["passsql"] == "password") ( ... извеждане на SQL грешка... ) else ( ... Само информация за грешка, без подробности... )
Това ще скрие от хакера информация, която може да му помогне при хакването на сайта.
Преглед. Грешка #5.
Опитайте се да не включвате файлове, като получавате имена на файлове отвън.
Например:
if (isset($_GET["file_name"])) (включете $_GET["file_name"] .".php"; )
Използвайте превключвател

Създавам един прост списък в PHP, където потребителят може да добави име, възраст, имейли и т.н. Добавих също опция за изтриване, но искам да добавя съобщение за потвърждение, когато потребителят щракне върху бутона за изтриване.

Опитах да потърся в Google, но намерих само jQuery и JavaScript решения. Има ли начин да направите това само с PHP?

ИмеВъзраст"; докато ($query2=mysql_fetch_array($query1)) ( ехо " ".$query2["име"].""; ехо " ".$query2["възраст"].""; ехо " редактиране"; ехо " х"; } ?>

Изтрий.php

в

Ако искате да го направите само в PHP, трябва да добавите "стъпки" към вашия скрипт, така:

Стъпка 1 (показване на формуляра) -> стъпка 2 (питане за валидиране) -> стъпка 3 (проверка)

За да направите това, можете да използвате сесии, за да запазите съдържанието на формуляра и параметър GET, за да следите тази стъпка. Иначе най просто решениее да използвате javascript:

ехо" х"; //използвайте двойни кавички за js в php!

Това е, което ви трябва

While($query2=mysql_fetch_array($query1)) ( ехо " ".$query2["име"].""; ехо " ".$query2["възраст"].""; ехо " редактиране"; ехо " х"; ) в while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["име"].""; ехо " ".$query2["възраст"].""; ехо " редактиране"; ехо " х"; }

и създайте функция на javascript

Функция confirmationDelete(anchor) ( var conf = confirm("Наистина ли искате да изтриете този запис?"); if(conf) window.location=anchor.attr("href"); )

повярвайте ми, това е работа 🙂

Добавете събитие onClick, за да задействате диалога и javascript:return confirm("сигурни ли сте, че искате да изтриете това?");

ехо" х";

//добавете събитие onclick onclick="return deleteconfig()"

работи за мен, но променете това:

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

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

По-долу е даден вариант на горното, който дава поле за потвърждение и предава променливата от PHP към Javascript и обратно към PHP.
Използвах това, за да избера радио бутон за премахване на файл от списъка с файлове.
Вижте функцията за задействане на OnClick с име php $fileName в Javascript, потвърдете с име на файл и ако е така, предайте href с променливи за $_GET

PHP/HTML код:

$fileName $extn $ размер $modtime "; ?>

Статията не е за клъстери, не за шардинг с репликация и дори не за облаци. Статията е за изграждането на високонадеждна изчислителна архитектура, в която броят на потребителите и техните заявки могат да растат лавинообразно. А за бизнеса е критично уеб услугата да приеме всяка заявка, да я обработи коректно и докрай (независимо от повреди и падания на някои компоненти) и гарантирано да достави отговор на клиента. И, разбира се, без „космическите“ разходи за оборудване и заплати на системните администратори.

С други думи, на първо място, помислете - "имам ли нужда от това." Ако някой има онлайн магазин, който продава говорещи хамстери с оборот от 100 поръчки на месец, вероятно не. И ако планирате да управлявате бизнес, който може да поеме стотици хиляди и милиони потребители, изисква голямо количество изчисления, работи с данни с висока стойност, гарантира транзакционността на всеки бизнес процес и се нуждае от паралелна обработка на данни, това Така ли.

Финансовият сектор, големи онлайн магазини с гама от стотици хиляди единици, онлайн търгове, системи за резервации на хотели и авиолинии, нов „облак“ или социални услуги с амбиции да получат милионна потребителска база на следващия ден след началото на рекламата кампания потенциално се интересуват от високонадеждна система за вашите уеб услуги.

Към кого е адресиран този материал

1. Разработчици на големи уеб проекти, които се интересуват от създаването на високо натоварени и устойчиви на грешки компютърни услуги.

2. Собственици на нов или разширяващ се бизнес, които очакват "експлозивен" растеж на потребителската база и поставят високи изисквания към компютърната част.

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

Защо толкова много думи за „изчисления“?

Тъй като близкото бъдеще на големите уеб проекти е в областта на „ голяма информация” („Големи данни”) е тенденция, отбелязана като една от водещите през 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. Монолитно приложение. Без значение как разделяте приложението на модули, без значение колко упорито се опитвате да разпространите кода в сложна структура на директория, без значение какво мързеливо автоматично зареждане използвате, има само един критерий: ако трябва да качите цялото приложение, за да качите поне една промяна, имате монолитно приложение. Нищо друго не се дава.

Недостатъците на монолитните приложения са описани масово в литературата. Една от основните може да бъде спомената накратко: ако искате и най-малката функция да бъде в производство в рамките на един час, трябва да поберете цялата производствена верига в един час. Дефиниране на проблем, внедряване, проверка на обратна съвместимост, писане на тестове, писане на документация, преминаване през отдела за ръчно тестване, коригиране на грешки - всичко това в рамките на един час.

Защото, ако качите цялото приложение точно в 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. Осигурете "хранилище" за стартиране на заявки. След като заявката бъде получена от клиента, кажете „Потвърди“ на клиента и запазете тази заявка. Веднага щом задната част се освободи от предишния цикъл на обработка, предайте заявката към нея. Докато заявката се „разхожда“ между задните възли, запазете я от момента, в който е „влязла“ във възела и я ангажирайте веднага щом „напусне“ възела. По този начин, ако някой възел „падне“, системата няма да загуби заявката и веднага ще я изпрати обратно на обработка. В края на обработката изпратете резултата на клиента и го запазете, докато клиентът каже „Потвърди“.

6. Осигурете паралелно изчислениеза тези операции, които могат да се изпълняват паралелно от гледна точка на бизнес логиката, и последователност за тези, които трябва да се изпълняват строго последователно. Този абзац е написан не с претенция за „Капитанска очевидност“, а за да покаже, че нито един бизнес процес не може да бъде „сляпо поставен“ върху многонишков код.

7. Откажете се от скриптовете в полза на „демони“. Демонът е процес, който започва веднъж и след това постоянно „виси“ в паметта. Тъй като работи през цялото време, не е необходимо да прекарва време в повторно инициализиране на всяка заявка. Гледайки напред, ще кажа, че PHP демонът (когато се използват модерни версии на PHP) няма фундаментални разлики от обикновен PHP скрипт.

Подход за проектиране на SOA

SOA - Service Oriented Architecture - не е новомодна. Този модулен подход към разработката на софтуер беше иницииран от IBM още през миналия век и в момента се поддържа и насърчава от лидери в индустрията, главно в продукти на "корпоративно ниво" в .NET и JAVA.

В класическия подход за програмиране на уеб услуги в PHP езиции подобни - проектирането започва от модели, техните свойства и операции върху тях. Моделите представляват обекти от реалния свят, а операциите представляват действия върху обекти. Въпреки това, както показва практиката, реалният свят е много по-многостранен и сложен и е много по-ефективно описан от езика на събитията и реакциите към тях (за повече подробности вижте публикация # 1593 с описание и примери).

Реалният свят се състои от събития, които се случват едновременно (от гледна точка на програмирането - „паралелно“) и най-вече без наше участие, и на които възникват или не възникват различни реакции. Реакциите от своя страна могат да генерират следните събития. SOA е идеален за „програмиране в реалния свят“, тъй като е най-удобно да се работи със събития, връзки между тях и реакции към тях. Освен това при правилен подходкъм организацията на архитектурата и събитията и реакциите към тях ще се случват паралелно, дори ако използвате „еднонишков“ език за програмиране като PHP.

Трябва да проектирате SOA продукт въз основа на това какви събития се случват във вашата бизнес логика, как те са свързани едно с друго или трябва да следват едно друго, какви реакции трябва да възникнат в отговор на определени събития и кой точно ще обработва тези или онези събития. други събития. Внедряването на моделите на данни и действията върху тях изчезват на заден план (капсулирани в „услуга“), а списъкът с „услуги“ и планът за взаимодействие между тях (inter-service API) са поставени на преден план.

Реализация: първо приближение

1. Frontend като самостоятелно приложение. Всяка популярна JavaScript-MVC-рамка е подходяща за внедряване. От практиката обаче отбелязвам, че ако започнете да се болите, когато комбинирате думите „JavaScript, MVC и framework“ в едно изречение, ще ви бъде трудно. Приложението трябва да може да рисува всички свои „екрани“, без да се позовава на бекенда, да дава на потребителя навигация (преходи между „екрани“) също без да се позовава на бекенда и да поддържа двупосочен канал за комуникация с бекенда.

2. Входна точка за WebSocket връзка към бекенда. В NodeJS има редица готови решения, които също поддържат резервни заявки за дълго запитване и ajax за идеологически остарелибраузъри. Отбелязвам за в бъдеще, че този възел може да бъде достъпен и на чист HTTP, ако трябва да напишете някои шлюзове с услуги на други хора, но за да опростите, можете да напишете отделен „чист HTTP“ възел.

Входната точка ще осигури двупосочен комуникационен канал с предното приложение (с други думи, с браузъра), приемайки заявки от него и връщайки отговори към него.

3. Съхраняване на изпълнявани заявки в системата. За това популярният AMQP сървър е най-подходящ, осигурявайки опашки от съобщения и маршрутизиране между тях. Веднага щом дойде следващата заявка от клиента, поставете я в опашката „входящи“. Освен това тя ще бъде извлечена от тази опашка от демона, който ще анализира съдържанието на заявката и ще я изпрати на „маршрутизиране“ в цялата система (което всъщност означава прехвърлянето й към една или повече опашки според определени алгоритми). Всеки демон, работещ със собствената си част от бизнес логиката, ще получи това или онова съобщение от „своята“ входяща опашка, ще го обработи и ще постави отговора в „изходящата“ опашка.

Отбелязвам, че в терминологията на популярния брокер RabbitMQ няма концепция за изходящи опашки. Съобщенията се публикуват в борсата (обменника), откъдето самият брокер се прехвърля към определени опашки според правилата за маршрутизиране. Тук е така написано за условно разбиране, че отговорът не се изпраща директно на заявителя.

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 приложения на websocket транспорт успешно работят на iPad.

Потребителска работа от множество устройства

От работа той ползва вашата услуга от работа настолен компютър, на път за вкъщи вади айфон, а вкъщи пуска таблета. Ако потребителят изпрати някаква команда от интерфейса към услугата, тогава той чака отговор за резултатите от обработката. Лесно е да се разбере, че ако (когато) обработката отне известно време, отговорът трябва да бъде изпратен до устройството, което потребителят използва (съжалявам за играта на думи) в момента доставка на отговор, а не в момента на заявката.

Проблемът е, че е невъзможно да се каже недвусмислено дали потребителят е спрял да използва (съжалявам отново) това или онова конкретно устройство. Може би е затворил браузъра. Може би батерията му е изтощена. Може би е тръгнал към тунела на метрото, където няма връзка, и след половин минута ще се появи отново. Има много варианти, а авторът е неизвестен По най-добрия начинопределения. Но ето какво може да намерите за полезно:

1. Запишете (на бекенда) всички устройства на потребителя и времето на последната активност от всяко от тях.

2. Класифицирайте системните събития, които трябва да бъдат докладвани на потребителя, на такива, които трябва да бъдат доставени само на активни устройства, и такива, които трябва да бъдат доставени „излъчени“ (до всички устройства).

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

4. Осигурете опашки за изпращане до всеки потребител по всеки отделен комуникационен канал (уеб интерфейс, мобилно устройство, поща). Стандартната функционалност на AMQP също ще ви помогне с времето за изтичане на съобщенията, така че те да лежат там не повече от определено време и да не задръстват системата. Когато даден потребител влезе онлайн през конкретен канал, ще му бъдат доставени нови, чакащи съобщения от този конкретен тип.

Авторът може да добави, че на базата на същата система е възможно да се изгради забавено изпращане на известия (които ще бъдат изпратени не по-рано от определена дата) и дори изпращане на истинска хартиена периодична кореспонденция (актове, плащания и др. ), но това е тема за отделна статия.

Ще подчертая основното: не считайте доставените съобщения за някакви известия, с които сте свикнали във Facebook или Vkontakte. Доставените съобщения са резултати от заявкатапотребител! Всички потребителски действия в интерфейса, предполагащи някакъв вид заявки към бекенда, получават отговори в единна форма на „доставени съобщения“ чрез единен унифициран комуникационен канал. И тогава алгоритъмът на уеб приложението разбира какво трябва да се направи с това или онова съобщение - начертайте известие с текст, добавете ред в таблицата, превключете нещо в интерфейса и т.н.

Паралелни и последователни изчисления

Би било безполезно да проектирате бърз уеб интерфейс на предния интерфейс, ако имате бавен бекенд. Не, не става въпрос за потоци, не за разклонения и не за Erlang. Оставаме на обичайния PHP, достъпен за всеки начинаещ/средно напреднал програмист.

Защо изобщо се нуждаем от паралелизъм? Дори и да не говорим за недостатъците на еднонишковите езици като цяло, паралелизмът значително ускорява изчисляването на задачата, което означава, че значително намалява изискванията за хардуерни ресурси (хардуер) и повишава удовлетвореността на потребителите от работата в интерфейса (те получават резултати по-бързо).

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

Нека ви дам пример: да кажем, че потребител иска да закупи услуга, която е включена като допълнителна платена опция в неговия тарифен план. Броят на опциите е ограничен. Ако опцията е включена успешно, тогава трябва да изпратите известие до потребителя в браузъра, да изпратите дублиран имейл, да приспаднете пари от сметката му за таксуване и да уведомите клиентския отдел. Начертайте верига:

1. Системата получи заявка за активиране на опцията.
2. Упълномощаваме потребителя и откриваме неговия тарифен план.
3. Проверяваме дали изобщо е възможно да активирате тази опция от тарифен планпотребител.
4. Проверете дали потребителят има достатъчно пари в сметката.
5. Проверете дали тази опция е в конфликт с други настройки.
6. Ако всичко е наред, активирайте опцията.
7. Изпращаме известие до браузъра.
8. Изпращаме известие по пощата.
9. Отписвайте пари в фактурирането.
10. Уведомяваме клиентския отдел.

Внимателният читател може да намери грешка в последователността от действия, но авторът ще ви напомни, че това е приблизителен пример.

какво виждаме Имайте предвид, че няма причина да изпълнявате всички стъпки последователно. Би било много по-правилно да „паралелизираме“ 3,4,5 в три нишки, а накрая - 7,8,9,10 в четири нишки.

Мислите ли за потоци и разклонения? Напразно, имате SOA!

Как се прави паралелно изчисление в SOA

За читателите, които току-що са превъртели статията до тук, ще обясня, че не става въпрос за паралелизиране на една и съща задача в SOA - за това в общия случай е достатъчно да стартирате демона в N инстанции и да се погрижите за спорът за достъп до базата данни.

И така, в този пример имаме три-четири-няколко различни задачи, които се изпълняват от различни услуги и които искаме да изпълним паралелно. Не е трудно да ги изпратите на паралелна обработка: достатъчно е да изпратите едно събитие „може ли потребителското име да активира опция X?“ И всички услуги, абонирани за това събитие, ще го хванат, ще извършат своите проверки и ще изпратят произтичащите събития.

Проблемът е именно да съберем тези произтичащи събития, когато имаме нужда от общия резултат от тяхната работа, за да продължим напред. Например в списъка по-горе се нуждаем от резултата 3+4+5, а 7+8+9+10 може да се игнорира.

Всъщност, с високи изисквания за задължително завършване на транзакции, трябва да контролирате всяка верига до края, но ще обсъдим това по-късно.

Естествено, ако нашият демон ще „виси и чака“, консумирайки ресурси (така наречения „неактивен“), тогава не можете да изградите нито една високо натоварена услуга по този начин. Въпросът е само, че демонът решава други задачи и обслужва други заявки на други клиенти, докато три отделни „нишки“ (3,4,5) решават своите подзадачи. Трудности се добавят и от факта, че произтичащите събития могат да идват в произволен ред. Всичко това обаче се решава лесно и просто:

Доколкото авторът знае, нито една от внезапните внедрявания на AMQP, които съществуват днес, не позволява очакване и „залепване“ на няколко събития в едно, за да получите само него - един резултат. Така че трябва да се погрижите сами за това, както следва:

1. Преди да изпратите събитие до AMQP, поемете ангажимент за бърза памет(използвайте всяко подходящо хранилище в паметта) списък с имената на произтичащите събития, които услугата очаква да получи, както и името на събитието (нека го наречем „R“), което трябва да бъде изпратено със сумата от резултатите.

2. След това услугата приключва цикъла на обработка на текущото събитие и се освобождава за следващи задачи.

3. Веднага щом пристигне всяко събитие от списъка, който сме съхранили в паметта, услугата го „разопакова“ и съхранява съдържанието му в паметта, като го приписва на името на събитието. В същото време той проверява дали в този списък има други събития, за които не е получен отговор. Ако е така, цикълът завършва в тази точка.

4. В противен случай, т.е. ако всички събития в списъка са получили отговор, услугата ги свързва заедно и изпраща залепения резултат под името на събитието „R“, запомнено по-рано. След това, за да се спести памет, списъкът с резултатите просто се изтрива от паметта - вече не е необходим.

5. Същата услуга или друга (по преценка на системния дизайнер) получава полученото събитие „R“ с всички резултати от паралелната обработка. Това, което следва, е очевидно.

Ако от описанието ви се стори, че това е дълго време, тогава ще обясня - говорим за хиляди и десетки хиляди събития в секунда (!) На един среден сървър.

Използването на съхранение в паметта предполага, че дори ако услугата спре (пада, актуализира), текущият бизнес процес няма да бъде загубен. След като услугата бъде стартирана отново, тя ще продължи да получава събития от ESB и да ги обработва съгласно описания по-горе алгоритъм.

Транзакционалност, връщане назад на операции (връщане назад) и сценарии за отказ в SOA

Тъй като в SOA партньорските събития „минават“ през ESB, имате нужда от някаква индикация, която да показва, че „този отговор тук“ се отнася до „онази заявка там“. Тук няма нужда да преоткривате колелото - в спецификациите на всеки популярен протокол ще намерите параметър с име като correlation_id. Обикновено това е низ. Той трябва да се съдържа в параметрите на всички събития на всеки отделен бизнес процес, от влизане до изход, за да се идентифицира веригата от съобщения, която принадлежи към този бизнес процес. Погледнато от страна на уеб интерфейса, уеб приложението съхранява текущите активни (изпратени) заявки и чрез correlation_id „разбира“ в отговор на коя заявка е дошъл всеки конкретен отговор.

Нека се справим с терминологията: транзакционността е свойството на системата да извършва няколко действия като една обща операция, която има смисъл и може да бъде завършена само напълно. Тъй като е физически невъзможно да се извършат атомно няколко операции в разпределена система с паралелни нишки, системата осигурява така наречените сценарии на отказ и връщане назад.

Сценарият на неуспех обикновено е действие, което трябва да се предприеме, когато възникне грешка. В този контекст връщането назад е скрипт от действия, които трябва да бъдат изпълнени, за да се „отмени“ поредица от предишни действия, които в крайна сметка са довели до грешка. Грубо казано, връщанията са процеси, които са обратни на нормалните бизнес процеси в системата.

Възстановяването не винаги е необходимо и не винаги е възможно. Например, ако сте свързали някаква опция към потребителя и след това сте „паднали“ върху таксуването, тогава опцията може да бъде деактивирана обратно. Е, тогава можете да опитате отново, автоматично или чрез втора команда от потребителя. И ако физически изтриете съдържанието и някои от последващите операции не работят ... Ситуацията е двусмислена.

Следователно към сценариите на неуспех и връщанията трябва да се подходи разумно. Авторът може да препоръча следния път: Винаги пишете неуспешни скриптове, но не винаги пишете връщания назад. Вашите неуспехи ще бъдат незабавно отразени в мониторинга - и екипът за поддръжка ще може бързо да коригира ситуацията с ръцете си, да натрупа опит и да формулира технически изисквания за програмистите. Въпреки че писането на уникално правилно връщане назад от нулата може да бъде много, много трудно.

Въпреки това трябва да се разбере, че връщането назад, връщането назад, обработката на грешни ситуации са същите бизнес процеси като всичко останало. Те също се основават на събития, преминаващи през системата. Ще бъде хубаво, ако първоначално заложите два противоположни пътя (напред и назад, успех и неуспех) във всяко събитие и всеки манипулатор, за да ги приложите в конкретни задачи.

SOA мащабиране

Всяка система рано или късно трябва да бъде разширена. В случая на SOA това се прави лесно и естествено:

1. Дублирана входна точка. Това се отнася за същия WebSocket шлюз, който разгледахме в началото на статията. Може да се дублира неограничен брой пъти, тъй като комуникацията между него и клиента е унифицирана и отделена от вътрешността на системата, а комуникацията между него и системата от своя страна е отделена от комуникацията с клиента.

2. Дублирани инстанции(инстанции) на услуги. Услуги, които не изискват база данни или само „четат“ от тях, се дублират безпроблемно. А редовната функционалност на RabbitMQ ще ви позволи да абонирате N екземпляра за една и съща опашка, съобщенията от които произволно ще пристигат в един или друг екземпляр. Когато дублирате услуги, които работят с външни приложения (бази данни, софтуер на трети страни), трябва да обмислите как тези приложения предоставят заявки за транзакции от няколко паралелни клиента.

3. Дублиране на хранилища за данни. Тук можете свободно да използвате всяко познато ви шардинг. Ако имате работа с 10 милиона потребители и това изглежда много, разделете на 10 милиона бази (например въз основа на CRC32 от данните за влизане на потребителя или някакъв друг кръгов метод). Ако базата данни на една услуга непрекъснато расте и става по-сложна, разделете я на две услуги.

4. Дублиране на AMQP брокери съхранение в паметта. От практиката на автора RabbitMQ и Redis перфектно изпълняват своята роля. Ако имате оборудване в повече от един DC шкаф, изберете режим на заек, който е толерантен към повреди на мрежовата връзка.

5. Пълно машинно дублиране. ОТ модерни технологиивиртуализация (KVM) и конфигурация (Chef), задачата за „вдигане на същата машина“ се свежда до натискане на един бутон.

Криптиране на трафика между фронтенд и бекенд

Препоръчително е да организирате WebSocket връзка през SSL. Освен това увеличава „проникването“ срещу изостанали офис доставчици, които блокират „всеки странен трафик“, с изключение на HTTP[S].

Ако обаче това ви се струва недостатъчно, можете да организирате генерирането на двойки ключове с всяко влизане на клиент (една двойка в предния край, втората в задния край), да обменяте публични ключове и допълнително да шифровате целия трафик с обикновен RSA.

Защита срещу DDOS и подобни злоупотреби

Авторът умишлено пропуска въпроса за защитата на „ниско ниво“, когато става въпрос за наводняване на SYN и наводняване на канали със стотици гигабита, тъй като за това са написани стотици книги със специализирана литература. Нека да поговорим за това как да защитим системата вече вътре, на нейните логически нива, когато хакер е намерил начин да „наводни“ вашата система (SOA + ESB) с хиляди събития.

1. Първо правило: нищо не трябва да се обработва, докато валидността му не бъде потвърдена. Ако очаквате малък JSON текст, обвит в BASE64 като вход, тогава входящият низ, по-дълъг от мегабайт, трябва изрично да бъде отхвърлен - не се опитвайте да го разопаковате. Подобен е низ, съдържащ „нелатински“ знаци. Когато сте разопаковали низ, не се опитвайте да направите json_decode веднага, първо проверете номера и двойката на скобите. И така нататък.

Изглежда като параноя, но в противен случай лесно можете да бъдете „запълнени от паметта“, тоест да доведете до повреда на услугата, принуждавайки я да заеме цялата налична RAM памет.

2. Услугата, която обработва входящите съобщения, не трябва да записва нищо в паметта, в базата данни и други хранилища. Причината е същата. Първо се уверете, че съобщението като цяло е валидно и едва след това го пуснете „по-дълбоко“ в системата.

3. Услуга, която може да бъде принудена да „отиде в базата данни“ често, трябва да бъде защитена чрез кеширане. Прост пример е услуга за оторизация на потребители. Ако не е защитен, тогава атакуващият може да изпрати хиляди заявки за оторизация подред, като по този начин претовари базата данни.

4. На входа на системата се нуждаете от услуга, която отхвърля заявки от „подозрителни“ източници, например от IP адреси от „черния списък“.

Звучи като класически съвет, така че каква е сделката? Основният проблем е, че ако поставим услуга за анализатор-филтриране на входа на системата (както се прави в класическите уеб проекти), тогава производителността на цялата система няма да бъде по-висока от производителността на този анализатор-филтър. Изключително скъпо е да се преглежда всеки доклад за съмнение „в реално време“. Можете и трябва да направите това след факта и ето как:

1. Направете услуга, която ще "слуша" всички съобщения в системата. В RabbitMQ това се постига чрез абониране за ключа за маршрутизиране "#".

2. Научете тази услуга на определени правила, чрез които може да диагностицира „подозрителни“ податели. Например, това са податели, които изпращат твърде много подобни съобщения в интервал от време, или които изпращат повтарящи се съобщения, или които изпращат съобщения от името на един и същ потребител от различни IP адреси ... Има много опции, включете вашия въображение. В същото време няма значение колко бързо работи такава услуга (в разумни граници, разбира се) - това не влияе на скоростта на цялата система.

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

4. Поставете много прост и бърз демон на входа - услуга за филтриране, чиято задача ще бъде просто "глупаво" да блокира подозрителни изпращачи. Без анализ, без анализ, без допълнителни разходи. Лесно е да се познае кой се счита за подозрителен: услугата ще научи за тях от събитията, описани в предишния параграф, и ще ги добави към своя вътрешен черен списък.

Край на първата част. Продължение: SOA: разпределена архитектура и нейната поддръжка.

Ментор съм в ИТ проекти. Това означава, че ако сте собственик или лидер, мога да ви помогна да поемете нови висоти. Изчистете процесите, разберете мотивацията на екипа, внедрете инструменти и постигнете конкретни цели. Не уча как да правите бизнес, а само помагам да заобиколите щедро разпръснатия рейк по пътя си. .