Materiál je určen především začínajícím webovým programátorům.

Úvod.

Často se na mě obracejí klienti, kteří mají nainstalovaný CMS s vlastním psaním nebo moduly napsané začínajícími webovými programátory, kteří nechápou, co je potřeba k ochraně dat a často kopírují funkce filtrování, aniž by přemýšleli o tom, jak fungují a co přesně je s nimi potřeba udělat .

Zde se pokusím popsat co nejpodrobněji. obyčejné chyby při filtrování dat PHP skript a dát jednoduché tipy jak správně filtrovat data.

Na netu je spousta článků o filtrování dat, ale nejsou, jak by to mělo být, úplné a bez podrobných příkladů.

Debriefing.

Filtrace. Chyba #1
Pro číselné proměnné se používá následující kontrola:
$číslo = $_GET["vstupní_číslo"]; if (intval($number)) ( ... spustit SQL dotaz... )
Proč to vede k SQL injekce? Jde o to, že uživatel může specifikovat v proměnné vstupní_číslo význam:
1"+UNION+SELECT
V takových případech kontrola úspěšně projde, protože funkce intval získá celočíselnou hodnotu proměnné, tzn. 1, ale v samotné proměnné $číslo nic se nezměnilo, takže Škodlivý kód budou předány SQL dotazu.
Správné filtrování:
$číslo = intval($_GET["vstupní_číslo"]); if ($number) ( ... spustit SQL dotaz... )
Podmínka se samozřejmě může změnit, například pokud potřebujete získat pouze určitý rozsah:
if ($číslo >= 32 A $číslo<= 65)

Pokud používáte zaškrtávací políčka nebo vícenásobné výběry s číselnými hodnotami, zaškrtněte toto:
$checkbox_arr = array_map("intval", $_POST["checkbox"]);
pole_map
Setkávám se také s filtrováním ve tvaru:
$number = htmlspecialchars(intval($_GET["vstupni_cislo"]));
htmlspeciální znaky
Nebo:
$cislo = mysql_escape_string(intval($_GET["vstupni_cislo"]));
mysql_escape_string

Nic jiného než úsměv to způsobit nemůže :)

Filtrace. Chyba #2.
Pro řetězcové proměnné se používá následující filtrování:
$vstupní_text = přidá lomítka($_GET["vstupní_text"]);
Funkce lomítka opustí specifikaci. znaků, ale nezohledňuje kódování databáze a je možné filtrování obejít. Nebudu kopírovat text autora, který tuto zranitelnost popsal a pouze dám odkaz na Chrise Shiflett (překlad můžete vyhledat v Runetu).

Použijte funkci mysql_escape_string nebo mysql_real_escape_string, příklad:
$vstupni_text = mysql_escape_string($_GET["vstupni_text"]);
Pokud nehodláte vstoupit html tagy, pak je nejlepší provést následující filtrování:
$vstupni_text = strip_tags($_GET["vstupni_text"]); $vstupni_text = htmlspecialchars($vstupni_text); $vstupni_text = mysql_escape_string($vstupni_text);
strip_tags - stripuje html tagy.
htmlspecialchars - převede speciální. znaky v entitě html.
Tímto způsobem se kromě SQL injection chráníte před útoky XSS.
Pokud potřebujete html tagy, ale pouze pro zobrazení zdrojového kódu, pak stačí použít:
$vstupni_text = htmlspecialchars($_GET["vstupni_text"]); $vstupni_text = mysql_escape_string($vstupni_text);

Pokud je pro vás důležité, aby hodnota proměnné nebyla prázdná, použijte funkci trim, například:
$vstupni_text = trim($_GET["vstupni_text"]); $vstupni_text = htmlspecialchars($vstupni_text); $vstupni_text = mysql_escape_string($vstupni_text);

Filtrace. Chyba #3.
Jde o vyhledávání v databázi.
Pro vyhledávání podle čísel použijte filtrování popsané v první chybě.
Pro vyhledávání podle textu použijte filtrování popsané v druhé chybě, ale s výhradami.
Abyste zabránili uživateli provést logickou chybu, musíte speciální položku odstranit nebo ji opustit. SQL znaky.
Příklad bez dodatku. zpracování linky:
$vstupni_text = htmlspecialchars($_GET["vstupni_text"]); // Hledat: "%" $input_text = mysql_escape_string($input_text);
V důsledku toho dostaneme dotaz jako:
... WHERE text_row LIKE "%".$input_text."%" ... // WHERE text_row LIKE "%%%"
Tím se výrazně zvýší zatížení základny.
Ve svém skriptu používám funkci, která z vyhledávání odstraňuje znaky, které nechci:
funkce strip_data($text) ( $quotes = pole ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!"); $goodquotes = pole ("-", "+", "#"); $repquotes = pole ("\-", "\+", "\#"); $text = trim(strip_tags($text)); $text = str_replace($quotes, "", $text); $text = str_replace($goodquotes, $repquotes, $text); $text = ereg_replace(" +" , " ", $text); vrátit $text; )
Samozřejmě ne všechny výše uvedené symboly jsou nebezpečné, ale v mém případě nejsou potřeba, proto provádím vyhledávání a nahrazování.
Příklad použití filtrování:
$vstupni_text = strip_data($_GET["vstupni_text"]); $vstupni_text = htmlspecialchars($vstupni_text); $vstupni_text = mysql_escape_string($vstupni_text);
Také vám doporučuji omezit počet znaků ve vyhledávání, alespoň ne méně než 3, protože. pokud máte v databázi velké množství záznamů, pak hledání 1-2 znaků výrazně zvýší zátěž databáze.
Filtrace. Chyba #4.
Hodnoty proměnných nejsou filtrovány $_COOKIE. Někteří lidé si myslí, že vzhledem k tomu, že tato proměnná nemůže projít formulářem, je to záruka bezpečnosti.
Tuto proměnnou lze velmi snadno zfalšovat jakýmkoli prohlížečem úpravou souborů cookie webu.
Například v jednom známém CMS proběhla kontrola použité šablony webu:
if (@is_dir (MAIN_DIR . "/template/" . $_COOKIE["skin"]))( $config["skin"] = $_COOKIE["skin"]; ) $tpl->dir = MAIN_DIR . "/šablona/". $config["skin"];
V tomto případě můžete změnit hodnotu proměnné $_COOKIE["kůže"] a vyvoláte chybu, v důsledku čehož uvidíte absolutní cestu ke složce webu.
Pokud pro uložení do databáze použijete hodnotu cookies, pak použijte některou z výše popsaných filtrací, totéž platí pro proměnnou $_SERVER.
Filtrace. Chyba #5.
Včetně směrnice register_globals. Pokud je zapnutý, nezapomeňte jej vypnout.
V některých situacích můžete předat hodnotu proměnné, která by neměla být předána, například pokud má web skupiny, pak pro skupinu 2 by proměnná $group měla být prázdná nebo rovna 0, ale stačí to předstírat formulář přidáním kódu:

Proměnná v PHP skriptu $skupina bude rovna 5, pokud nebyla deklarována s výchozí hodnotou ve skriptu.
Filtrace. Chyba #6.
Zkontrolujte stažené soubory.
Zkontrolujte následující položky:
  1. Přípona souboru. Je vhodné zakázat načítání souborů s příponami: php, php3, php4, php5 atd.
  2. Je soubor nahrán na server move_uploaded_file
  3. velikost souboru
Zkouška. Chyba #1.
Setkal jsem se s případy, kdy pro požadavek AJAX (např.: zvýšení reputace) bylo předáno uživatelské jméno nebo ID (komu se reputace zvyšuje), ale samotné PHP existenci takového uživatele nekontrolovalo.
Například:
$user_id = intval($_REQUEST["user_id"]); ... INSERT INTO REPLOG SET uid = "($user_id)", plus = "1" ... ... AKTUALIZACE SADA uživatelů reputace = reputace+1 WHERE user_id = "($user_id)" ...
Ukázalo se, že vytváříme záznam v databázi, který je pro nás zcela k ničemu.
Zkouška. Chyba #2.
Při provádění různých akcí (přidávání, editace, mazání) s daty nezapomeňte zkontrolovat práva uživatele pro přístup k této funkci a další funkce (použití html tagy nebo možnost publikovat materiál bez ověření).

Dlouho jsem opravoval podobnou chybu v jednom modulu fóra, kdy mohl kterýkoli uživatel editovat administrační zprávu.

Zkouška. Chyba #3.
Při použití více php soubory provést jednoduchou kontrolu.
V souboru index.php(nebo do jakéhokoli jiného hlavního souboru) napište tento řádek před zahrnutím dalších souborů php:
define("READFILE", true);
Na začátek ostatních souborů php napište:
if (! definováno ("READFILE")) ( exit ("Chyba, špatný způsob uložení.
Přejít na hlavní."); }
To omezí přístup k souborům.
Zkouška. Chyba #4.
Použijte hash pro uživatele. To pomůže zabránit volání konkrétní funkce pomocí XSS.
Příklad kompilace hash pro uživatele:
$tajný_klíč = md5(strtolower("http://site.ru/" . $člen["jméno"] . sha1($heslo) . datum("Ymd"))); // $secret_key je náš hash
Dále ve všech důležitých formulářích nahraďte vstup hodnotou aktuálního hashe uživatele:

Během provádění skriptu zkontrolujte:
if ($_POST["secret_key"] !== $secret_key) ( exit ("Chyba: tajný_klíč!"); )
Zkouška. Chyba #5.
Při výstupu chyb SQL proveďte jednoduché omezení přístupu k informacím. Například nastavit heslo pro GET proměnná:
if ($_GET["passsql"] == "heslo") ( ... chybový výstup SQL... ) else ( ... Jen informace o chybě, žádné podrobnosti... )
Tím se před hackerem skryjí informace, které mu mohou pomoci při hackování webu.
Zkouška. Chyba #5.
Pokuste se nezahrnout soubory získáním názvů souborů zvenčí.
Například:
if (isset($_GET["název_souboru"])) (zahrnout $_GET["název_souboru"] .".php"; )
Použijte vypínač

Vytvářím jeden jednoduchý seznam v PHP, kam může uživatel přidat jméno, věk, e-maily atd. Přidal jsem také možnost odstranění, ale chci přidat potvrzovací zprávu, když uživatel klikne na tlačítko smazat.

Zkoušel jsem googlovat, ale našel jsem pouze řešení jQuery a JavaScript. Existuje způsob, jak to udělat pouze s PHP?

názevStáří"; while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["jméno"].""; echo" ".$query2["věk"].""; echo" Upravit"; echo" X"; } ?>

Smazat.php

v

Pokud to chcete udělat pouze v PHP, musíte do skriptu přidat „kroky“, například:

Krok 1 (zobrazit formulář) -> krok 2 (požádat o ověření) -> krok 3 (ověřit)

Chcete-li to provést, můžete použít relace k uložení obsahu formuláře a parametr GET ke sledování tohoto kroku. Jinak nejvíc jednoduché řešení je použít javascript:

echo" X"; //použijte dvojité uvozovky pro js uvnitř php!

To je to, co potřebujete

While($query2=mysql_fetch_array($query1)) ( echo " ".$query2["jméno"].""; echo" ".$query2["věk"].""; echo" Upravit"; echo" X"; ) in while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["jméno"].""; echo" ".$query2["věk"].""; echo" Upravit"; echo" X"; }

a vytvořit funkci javascript

Funkce potvrzeníDelete(anchor) ( var conf = potvrdit("Opravdu chcete smazat tento záznam?"); if(conf) window.location=anchor.attr("href"); )

věř mi, je to práce 🙂

Přidejte událost onClick ke spuštění dialogu a javascript:return potvrďte("opravdu to chcete smazat?");

echo" X";

//přidat událost onclick onclick="return deleteconfig()"

pracovat pro mě, ale změňte toto:

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

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

Níže je varianta výše uvedeného, ​​která poskytuje potvrzovací pole a předává proměnnou z PHP do Javascriptu a zpět do PHP.
Použil jsem to k výběru přepínače pro odstranění souboru ze seznamu souborů.
Viz spouštěcí funkce OnClick s názvem php $fileName v Javascriptu, potvrďte názvem souboru a pokud ano, předejte href s proměnnými pro $_GET

PHP/HTML kód:

$fileName $extn $velikost $modtime "; ?>

Článek není o clusterech, ani o shardingu s replikací a dokonce ani o cloudech. Článek je o budování vysoce spolehlivé výpočetní architektury, ve které může počet uživatelů a jejich požadavků růst jako lavina. A pro podnik je zásadní, aby webová služba přijala každý požadavek, zpracovala jej správně a do konce (bez ohledu na selhání a pády některých komponent) a byla zaručena, že klientovi doručí odpověď. A samozřejmě bez „prostorových“ nákladů na vybavení a platy pro systémové administrátory.

Jinými slovy, nejprve se zamyslete - "potřebuji to." Pokud má někdo internetový obchod, který prodává mluvící křečky s obratem 100 objednávek za měsíc, asi ne. A pokud plánujete provozovat firmu, která pojme stovky tisíc a miliony uživatelů, vyžaduje velké množství výpočtů, pracuje s daty vysoké hodnoty, zaručuje transakční transakční procesy každého obchodního procesu a potřebuje paralelní zpracování dat, je to?

Finanční sektor, velké internetové obchody se statisícovým sortimentem, online aukce, rezervační systémy hotelů a leteckých společností, nový cloud nebo sociální služby s ambicemi získat milionovou uživatelskou základnu druhý den po startu reklamní kampaně jsou potenciální zájem o vysoce spolehlivý systém pro vaše webové služby.

Komu je tento materiál určen

1. Vývojáři velkých webových projektů, kteří mají zájem vytvářet vysoce zatížené a chybově odolné počítačové služby.

2. Vlastníci nových nebo expandujících podniků, kteří očekávají „explozivní“ růst uživatelské základny a kladou vysoké nároky na výpočetní část.

3. Techničtí lídři a manažeři velkých webových projektů, kteří nejsou spokojeni se současným stavem a uvažují o zásadní reorganizaci.

Proč tolik slov o „výpočtech“?

Protože bezprostřední budoucnost velkých webových projektů leží v oblasti „ velká data“ („Big Data“) je trend, který byl v roce 2011 spolu s virtualizací, úsporou energie a monitorováním označen jako jeden z nejlepších a od roku 2013 pevně zaujal své místo v průmyslu a stal se dokonce jedním z akademických předměty na velkých zahraničních univerzitách.

Objem dat ke zpracování pro řešení obchodních problémů se dnes neustále zvyšuje a v budoucnu se tento proces bude jen zrychlovat. Jestliže před deseti lety stačilo ukázat uživateli „internetový obchod“ s produktem, před rokem stačilo analyzovat cestu uživatele webem a ukázat mu striktně relevantní produkt (tzv. „behaviorální technologie“ ), dnes se považuje za normu vědět o uživateli vše, včetně výšky, váhy, věku a jména svého oblíbeného psa.

Zákony přirozené konkurence diktují, že pokud chcete zákazníkům poskytnout více možností než vaši konkurenti, potřebujete více dat a více výpočtů. A dříve nebo později se v nich váš projekt bez patřičných přístupů může utopit – stejně jako se teď všude topí různé projekty: někdo kvůli složitosti podpory, někdo prostě kvůli špatnému kódu, někdo kvůli vysoké konektivitě modulů , někdo kvůli použití nespolehlivých komponentů.

Každý, kdo dnes rozjíždí webový projekt s velkými ambicemi, tedy získá více výhod oproti soupeřům, pokud svůj projekt zpočátku bude považovat nejen za programový kód, ale také za výpočetní prostředí – systém s vlastními zákony existence a vývoje. Čím více pozornosti věnujete správa výpočetní techniky na startu, tím je pravděpodobnější, že v příštích letech předběhnete konkurenty.

Autor těchto řádků je přesvědčen, že „klasický“ moderní přístup k budování vysoce zatížených webových služeb má řadu vážných nedostatků. Podívejme se proč. Nejprve zvažte typické moderní schéma:

Klasický přístup k budování vysoce nabité webové služby

1. Mnoho serverů rozdělených do rolí.

2. Část serverů (role Frontendu) je navržena tak, aby vracela statické zdroje (obrázky, CSS, JS soubory) a „distribuovala“ přední část příchozího provozu do downstream uzlů. Hlavním softwarem je obvykle Nginx.

3. Podřízené uzly (role Backend) jsou zapojeny do dynamických výpočtů. Jednoduše řečeno, může to být typický balíček Apache + PHP.

4. Další skupina serverů je určena pro ukládání dat. Jedná se o MySQL, Memcache, Redis a tak dále.

5. Samotný kód webové služby (v tento příklad– kód PHP) se stejně zkopíruje do všech uzlů, kde je Apache + PHP, a rovnoměrně zpracovává ty požadavky, které „padnou“ na jeden nebo jiný uzel.

6. Databáze jsou „rozmazány“ přes svou skupinu serverů pomocí nějaké formy shardingu a zátěž na nich je vyrovnávána podobným způsobem.

Pozorný čtenář si všimne, že ve schématu není zmíněno vyvažování DNS a CDN, ale autor je záměrně vynechal, aby schéma příliš nekomplikoval. Princip fungování těchto kusů je velmi podobný výše uvedenému.

Nevýhody klasického přístupu

1. Hlavním trendem jsou komplikace. V průběhu života projektu se „klasické“ schéma stává stále složitějším. S přidáním každého nového serveru jej musíte zadat do schématu distribuce provozu. Samozřejmě, že ve velkých projektech je uvedení serveru do role akcí „jednoho tlačítka“, ale přesto se jedná o nárůst infrastruktury, kterou je třeba podporovat. A ještě více - v případě, kdy stávající kapacity databáze již nestačí a potřebujete „žít“ (bez zastavení služby) přenést nebo distribuovat databázi na nové servery.

Ale hlavním problémem je, že zvýšení clusteru distribuce provozu nevede ke snížení složitosti programového kódu. Cluster můžete sestavit bezchybně, ale kód zůstane stejný.

2. Rozmístění není atomové. Jednoduše řečeno, rozvržení nová verze projekt na bojových serverech nějakou dobu trvá. Je nutné fyzicky stáhnout soubory na N-20 strojů, provést změny v databázi, resetovat cache (mnoho různých cache) a zároveň na všech serverech dokončit zpracování požadavků se „starým kódem“ a zahájit zpracování pomocí „ nový kód“. V opačném případě může dojít k mnoha drobným konfliktům, když je část požadavku uživatele zpracována starým způsobem, část novým způsobem, část šla do databáze podle „starého schématu“, část „podle nového“ a již brzy.

Proto v ideálním případě chce každý službu po dobu aktualizace (pár sekund či desítek sekund) pozastavit a poté znovu zapnout. Ve skutečnosti to s tokem minimálně 1000 požadavků za sekundu nikdo nedělá, raději pravidelně opravuje drobné kolize „ručně“ nebo je překrývá defenzivním programováním, které podporuje zpětnou kompatibilitu „až do sedmé generace“. O tom, jak pravidelná podpora zpětná kompatibilita komplikuje život programátorům (a prodražuje projekt jako celek) – chytrý čtenář může přemýšlet sám za sebe.

3. Používá HTTP. Protokol HTTP je evidentně morálně i technicky zastaralý, a pokud se budete řídit (např. mobilní vývoj- víte, že je všude nahrazován lehčími protokoly. Hlavní nevýhoda je však jiná: protokol HTTP „v prohlížeči“ vyžaduje dokončení smyčky - vyžaduje odpověď v omezeném čase. To zavazuje službu vypočítat a připravit odpověď přesně v rámci malého časového limitu, který jí prohlížeč umožňuje. Pokud je služba tento moment přetížený - požadavek bude navždy ztracen.

Proto se v „typických webových projektech“ uchylují k různým trikům, jako je Long polling nebo jiná forma periodických požadavků, což nejen komplikuje architekturu, ale také službu přetěžuje zbytečným „zbytečným taháním“.

4. Inicializace skriptu na požadavek. Je to důsledek používání HTTP a skriptovacích jazyků, jako je PHP, které se podle dlouholeté tradice restartují v reakci na každý požadavek. Ano, ano, v reakci na každý z 1000 požadavků za sekundu se PHP skript znovu spustí, znovu inicializuje všechny proměnné a znovu naváže spojení s databází. V praxi se stává, že zpracování požadavku trvá 0,005 sekundy a skript se inicializuje v řádu 0,05 sekundy – desetkrát déle!

Jinými slovy, 90 % času jsou vaše servery zaneprázdněny nezpracováním požadavků klientů, ale zbytečnou inicializací skriptů. Zkuste to převést na peníze. Proto bylo vynalezeno mnoho řešení, jako je ukládání do mezipaměti OPcode, trvalá databázová připojení, místní mezipaměti jako Memcache nebo Redis, navržená tak, aby tento nepříjemný efekt kompenzovala.

5. Monolitická aplikace. Bez ohledu na to, jak rozdělíte aplikaci do modulů, bez ohledu na to, jak moc se snažíte rozšířit kód do složité adresářové struktury, bez ohledu na to, jaké líné automatické načítání používáte, existuje pouze jedno kritérium: pokud k nahrání potřebujete nahrát celou aplikaci alespoň jedna změna, máte monolitickou aplikaci. Nic jiného není dáno.

Nevýhody monolitických aplikací jsou masivně popsány v literatuře. Jeden z hlavních lze stručně zmínit: chcete-li, aby i ten nejmenší prvek byl ve výrobě do hodiny, musíte do jedné hodiny vměstnat celý výrobní řetězec. Definice problému, implementace, zpětná kontrola kompatibility, psaní testů, psaní dokumentace, procházení oddělením ručního testování, oprava chyb – to vše do hodiny.

Protože pokud nahrajete celou aplikaci přesně v 00 minut každé hodiny, pak do konce každé hodiny byste měli přinést celou aplikaci do stabilního stavu.

6. Webové rozhraní je vykreslováno backendem. V typickém případě vzhled(a v souladu s tím i kód HTML) stránek projektu je zpravidla vykreslován na straně Backendu v reakci na každý požadavek. Jedná se o nadměrné, neodůvodněné výdaje zdrojů a peněz.

7. Politické členění resortů. oddělení správci systému je zodpovědný za zajištění toho, že příchozí provoz je „rozmazaný“ přes spoustu serverů, na kterých běží PHP kód. Oddělení programování je zodpovědné za kód PHP. Pokud PHP kód nestihl zpracovat konkrétní požadavek, pak není jasné, kdo je za to zodpovědný - buď admin, který „pustil“ příliš mnoho provozu na server a přetížil jej, nebo programátor, který napsal non - optimální skript. Pokud se databáze začne zpomalovat, pak také není jasné, kdo zůstává extrémní: zda admin, který si včas neuvědomil, že ji „natrhal“, nebo programátor, který na to mohl také přijít.

Pokud se vám příklady zdají přehnané a „ne z reálného života“, pamatujte, že autor pracoval v projektu, který byl hostován na 200 serverech a 60 z nich bylo obsazeno databází. Je děsivé vzpomenout si, kolik lidí bylo zaměstnáno na obsluhu tohoto projektu.

Hlavní nevýhoda

Opakujeme výše uvedenou myšlenku: hlavní nevýhodou klasického schématu je podle autora to, že techničtí specialisté optimalizují špatnou věc. Optimalizují příchozí frontu požadavků, ve skutečnosti je „rozmazávají“ napříč velkou skupinou strojů, místo aby optimalizovaly samotnou podstatu – výpočetní část. A je to mnohem jednodušší, než to vypadá.

teoretický ideál

Ach, jak bychom si přáli, abychom mohli:

1. Zbavte se hromady drahých serverů a použijte jednu nebo dvě malé skupiny.

2. Opusťte schéma Nginx->Apache->PHP s jeho divokou „režií“ ve smyslu spotřebovaných zdrojů, které stojí peníze.

3. Ze stejného důvodu eliminujte monstrózní náklady na inicializaci PHP skriptů.

4. Odmítněte potřebu „vykreslovat“ stránky na backendu. Byl by to docela sen, kdyby webová služba mohla fungovat s nestabilním nebo žádným internetovým připojením (například při použití mobilní síť na cestě).

5. Zbavte se „smyčky časového limitu“ HTTP, doručte odpověď klientovi pouze tehdy, když je tato odpověď připravena a se zárukou doručení.

6. Aktualizujte projekt po malých částech, bez zastavení a bez ztráty jediného požadavku klienta.

7. Nedělejte si starosti se ztracenými požadavky, pokud část projektu (některá komponenta) "spadla" nebo byla dočasně vypnuta pro účely ladění.

Neskutečný? Snadno!

První kroky k dokonalosti

Za prvé, pojďme se učit co musí být provedeno, proto budeme diskutovat - jak.

1. Navrhněte celý systém jako SOA(servisně orientovaná architektura) s ESB (enterprise messaging bus), opouští monolitický přístup, takže každá nezávislá část obchodní logiky je zpracovávána samostatnou „službou“ a komunikují spolu prostřednictvím nezávislé výměnné sběrnice.

2. Pusťte se do synchronicity. Například v synchronním schématu „požadavek – zpracování – odpověď“ se jedná o jednu HTTP smyčku, která nemá přísnou kontrolu ukončení a lze ji snadno přerušit. V asynchronním režimu existují tři samostatné procesy: požadavek (odeslaný a potvrzený), zpracování (opakování v případě selhání), doručení odpovědi (se zárukou).

3. Rozdělte projekt na dvě aplikace- Frontend a Backend. V případě webové služby je frontendem (obvykle) JavaScriptová aplikace. Základem je, že aplikace fungují asynchronně a vzájemně oddělené a vyměňují si zprávy přes obousměrný komunikační protokol.

4. Odhlaste se z HTTP ve prospěch WebSocket. Protokol WebSocket má ve srovnání s HTTP fantastický výkon, nemá žádné „smyčky s časovými limity“ a umožňuje přenášet jakákoli data (včetně binárních dat) v obou směrech.

5. Poskytněte „úložiště“ pro spouštění dotazů. Po obdržení požadavku od klienta řekněte klientovi „Potvrdit“ a uložte tento požadavek. Jakmile se backend uvolní z předchozího cyklu zpracování, předejte mu požadavek. Dokud požadavek „prochází“ mezi uzly backendu, uchovávejte jej od okamžiku, kdy „vstoupil“ do uzlu, a potvrďte jej, jakmile „opustí“ uzel. Pokud tedy některý uzel „spadne“, systém požadavek neztratí a okamžitě jej pošle zpět ke zpracování. Na konci zpracování odešlete výsledek klientovi a uložte jej, dokud klient neřekne „Potvrdit“.

6. Zajistěte paralelní výpočty pro ty operace, které lze z hlediska obchodní logiky provádět paralelně, a posloupnost pro ty, které musí být prováděny přísně sekvenčně. Tento odstavec nebyl napsán s nárokem na „zřejmost kapitána“, ale proto, aby ukázal, že žádný obchodní proces nelze „slepě umístit“ do vícevláknového kódu.

7. Vzdát se skriptování ve prospěch „démonů“. Démon je proces, který se spustí jednou a pak neustále „visí“ v paměti. Vzhledem k tomu, že běží neustále, nemusí trávit čas opětovnou inicializací každého požadavku. Při pohledu do budoucna řeknu, že démon PHP (při použití moderních verzí PHP) nemá žádné zásadní rozdíly od běžného skriptu PHP.

Přístup k návrhu SOA

Architektura SOA – Service Oriented Architecture – není nová. Tento modulární přístup k vývoji softwaru byl iniciován společností IBM již v minulém století a v současnosti je podporován a propagován předními průmyslovými společnostmi, zejména v produktech "podnikové úrovně" v .NET a JAVA.

V klasickém přístupu k programování webových služeb v PHP jazyky a podobně - návrh vychází z modelů, jejich vlastností a operací na nich. Modely představují objekty reálného světa a operace představují akce na objektech. Jak však ukazuje praxe, skutečný svět je mnohem mnohotvárnější a složitější a je mnohem efektivněji popsán jazykem událostí a reakcí na ně (podrobněji viz příspěvek #1593 s popisem a příklady).

Reálný svět se skládá z událostí, které se odehrávají současně (programově - „paralelně“) a většinou bez naší účasti a na které dochází či nedochází k různým reakcím. Reakce zase mohou generovat následující události. SOA je ideální pro „programování v reálném světě“, protože je nejpohodlnější pracovat s událostmi, vztahy mezi nimi a reakcemi na ně. Navíc v správný přístup k organizaci architektury a události a reakce na ně budou probíhat paralelně, i když používáte „jednovláknový“ programovací jazyk, jako je PHP.

Potřebujete navrhnout produkt SOA na základě toho, jaké události se vyskytují ve vaší obchodní logice, jak spolu souvisí nebo by na sebe měly navazovat, jaké reakce by měly nastat v reakci na určité události a kdo přesně bude ty či ony události zpracovávat. další události. Implementace datových modelů a akcí na nich ustupuje do pozadí (zapouzdřena do „služby“) a do popředí se dostává seznam „služeb“ a plán interakce mezi nimi (inter-service API).

Realizace: první přiblížení

1. Frontend jako nezávislá aplikace. Pro implementaci je vhodný jakýkoli oblíbený rámec JavaScript-MVC. Z praxe však podotýkám, že pokud vás při spojení slov “JavaScript, MVC a framework” v jedné větě začne bolet, bude to pro vás těžké. Aplikace musí být schopna kreslit všechny své „obrazovky“ bez odkazu na backend, poskytovat uživateli navigaci (přechody mezi „obrazovkami“) také bez odkazování na backend a podporovat obousměrný komunikační kanál s backendem.

2. Vstupní bod pro připojení WebSocket k backendu. V NodeJS existuje řada hotových řešení, která také podporují záložní požadavky na long-polling a ajax for ideologicky zastaralé prohlížeče. Do budoucna podotýkám, že k tomuto uzlu lze přistupovat i na čistém HTTP, pokud potřebujete napsat nějaké brány se službami jiných lidí, ale pro zjednodušení můžete napsat samostatný uzel „čistý HTTP“.

Vstupní bod bude poskytovat obousměrný komunikační kanál s front-end aplikací (jinými slovy s prohlížečem), přijímat od ní požadavky a vracet jí odpovědi.

3. Ukládání běžících požadavků v systému. K tomu se nejlépe hodí oblíbený server AMQP, který poskytuje fronty zpráv a směrování mezi nimi. Jakmile přijde další požadavek od klienta, zařaďte jej do „příchozí“ fronty. Dále bude z této fronty extrahován démonem, který zanalyzuje obsah požadavku a odešle jej do „routingu“ v celém systému (což ve skutečnosti znamená převedení do jedné nebo více front podle určitých algoritmů). Každý démon, který se zabývá svou vlastní částí obchodní logiky, obdrží tu či onu zprávu ze „své“ příchozí fronty, zpracuje ji a umístí odpověď do „odchozí“ fronty.

Podotýkám, že v terminologii populárního brokera RabbitMQ neexistuje žádný koncept odchozích front. Zprávy jsou zveřejňovány v burze (exchangeru), odkud je samotný broker podle směrovacích pravidel přesouván do konkrétních front. Zde je pro podmíněné porozumění tak napsáno, že odpověď není zaslána přímo žadateli.

4. Ovládání démonů(dozorce). Chcete-li spustit jednoduchý skript PHP jako démona, stačí zabalit spustitelný kód do while(true) (...) a zadat příkazový řádek něco jako „php your-script.php“. K tomu je ale lepší využít jakéhokoliv vhodného supervizora, který udělá v podstatě totéž, ale také zajistí potřebný stav prostředí, hlídá stav procesu a dělá nějaké užitečnější věci.

V reálném životě je PHP démon trochu komplikovanější: musí přijímat řídicí signály a rekonfigurační zprávy, nesmí unikat paměť, musí udržovat (nebo obnovovat přerušená) spojení s databází – ale obecně to není o nic složitější než PHP skripty, na které jste zvyklí.

O krok blíže realitě: událostmi řízený přístup v SOA

Některé (podle názoru autora zastaralé) přístupy k budování modulárních aplikací jsou založeny na principu RPC (Remote Procedure Calling), který implikuje přímé volání konkrétních metod nebo procedur ve vzdálené komponentě projektu. Tento přístup zcela ničí všechny výhody SOA, protože obvykle znamená přímé a tvrdé spojení mezi odesílajícími a prováděcími uzly. Při návrhu a implementaci komplexního produktu by měl být v maximální možné míře dodržen princip volně svázaných komponent, protože právě složitost architektury a kódu nakonec určí náklady na vlastnictví (opravy a změny produktu po jeho spuštění).

Událostmi řízený přístup v SOA předpokládá, že komponenty (služby) spolu komunikují odesíláním asynchronních událostí („události“, od slova Event). Událost je zpráva (například v terminologii AMQP), která má jméno (název) a sadu parametrů. Událost má systému sdělit, že se něco stalo, nebo „položit systému otázku“. V obecném případě jsou události odesílány „do systému“ (přesněji na společnou sběrnici ESB) bez adresy – tedy bez konkrétních záměrů pro doručení konkrétním uzlům nebo interpretům.

Naopak konkrétní uzly (komponenty, služby) naslouchají společné sběrnici pro určité události, na které jsou připraveny reagovat. To může znamenat, že služba je připravena vyslechnout nějakou událost a provést příslušnou akci. Nebo má služba určité znalosti (například vlastní databázi s informacemi o uživatelích) a je připravena je poskytnout na základě „žádosti“. V obou případech je výsledkem reakce na událost vygenerování nové události (s jiným názvem a jinými parametry), kterou mohou slyšet i další zainteresované služby.

Se správnou organizací generála pneumatiky ESB, služby odesílají a přijímají události asynchronně, aniž by na sebe čekaly. To znamená, že odesílající služba může bez časových prodlev odeslat libovolný počet událostí do ESB a přejít k řešení následujících úkolů. Porovnejte to s klasickým HTTP, což znamená čekání na odpověď v aktuálním cyklu zpracování, a uvidíte výhody. A přijímající služby budou také přijímat nové události asynchronně, nezávisle na sobě, ihned po dokončení zpracování předchozí události.

Model událostí SOA v kódu

Stručně řečeno, musíte se na svůj kód dívat ne jako na třídy s funkcemi (metodami), ale jako na události a akce, které nastanou v reakci na tyto události. Navíc výsledky akcí jsou také události. Ve vztahu k diskutované architektuře můžeme říci, že lokální události jsou události, které se vyskytly uvnitř určitého PHP skriptu, a vzdálené události jsou události, které do tohoto skriptu přišly z fronty AMQP (nebo jsou tam v důsledku toho odeslány). Pokud takto zacházíte s celým svým kódem, okamžitě to povede k překvapivému a velmi důležitému efektu:

Pokud jsou místní a vzdálené události stejné, pak jsou stejné obslužné rutiny místní a vzdálené události!

Proč je to tak důležité? Protože programátoři vašeho týmu pokračují v psaní běžného PHP kódu, aniž by přemýšleli o tom, kde bude ta či ona událost zpracována – přímo tam v tomto nebo sousedním PHP skriptu, nebo někde na druhém konci systému, v jiném démonu, na adrese alespoň v jiném programovacím jazyce. Pokud vytváříte projekt s veřejným API, pak každý účastník třetí strany bude moci „podepsat“ svůj kód do vašich událostí (a zpracovat je), nebo naopak – poslat vám svůj vlastní, abyste jeho události zpracovali jako požadavky (a dostanete za to zaplaceno, pokud používáte obchodní model SAAS s platbou za použití, jako je Amazon).

Pamatujte, co jsme nazvali hlavní nevýhodou klasických velkých webových projektů – neustále roste složitost, a tedy náklady na vlastnictví, náklady na podporu a změny. V případě architektury SOA řízené událostmi − složitost neustále klesá, protože „složité uzly“ lze snadno rozdělit na nezávislé služby (v tomto případě démony), přičemž principy systému zůstávají nezměněny a jeho výkon se pouze zvyšuje.

Nasaďte novou verzi bez ztráty stávajících procesů

Protože již nemáte monolitický systém, nemusíte nasazovat celý systém. Navíc nasazení komponenty (služby, démona) může trvat kdykoliv, samozřejmě v rozumných mezích. Důležité je, že během doby nasazení (těch pár sekund či několika desítek sekund) komponenty celý projekt ani na okamžik nepřeruší službu. Jak se to dělá?

Jednoduše vypnete službu, kterou je třeba aktualizovat. Aktualizujte jeho kód a strukturu databáze (je-li to nutné) a poté jej znovu spusťte. Všechny aktuální požadavky na tuto službu budou čekat ve frontě AMQP, dokud služba nepřijde. Podotýkám, že vzhledem k tomu, že služby jsou malé (malé množství kódu potřebného k vyřešení pouze malé části obchodní logiky), je to mnohem rychlejší než nasazení celé monolitické aplikace. Ale v žádném případě nebudou žádné ztráty.

Problémy s webovým rozhraním

Rychlé a responzivní webové rozhraní je předpokladem pro vysoce zatěžovaný projekt. Podívejme se, proč se webové rozhraní může obecně „zpomalit“ s klasickým přístupem k implementaci:

1. Rozhraní se kreslí na backendu, který je přetížený a dělá to pomalu. Přechod mezi stránkami je pomalý. I při použití AJAX se bloky překreslují příliš pomalu.

2. Zdrojový kód rozhraní (HTML, CSS, JS) je redundantní a pomalu přenášený komunikačními kanály, zejména pokud se tak děje při načítání každé stránky během navigace uživatele rozhraním.

3. Rozhraní obsahuje velké množství neoptimalizované logiky JavaScriptu, která je pomalá na slabých zařízeních (především na mobilních zařízeních).

Pokusme se vyřešit tyto problémy:

Jak vytvořit rychlé a responzivní webové rozhraní

1. Za prvé, a to nejdůležitější, zdroj rozhraní by mělo předány klientovi maximálně jednou. Jediným civilizovaným způsobem, jak toho dosáhnout, je vytvořit plnohodnotnou JavaScriptovou aplikaci. Do klienta se stáhne jednou (v tomto případě můžete ukázat krásný animovaný preloader) a poté po celou dobu práce se službou již klient nebude muset čekat na stažení.

2. Je nutné provést všechny přechody mezi "obrazovkami" webového rozhraní uvnitř aplikace JavaScript a v žádném případě jako samostatné požadavky na backend. Existuje pro to termín „jednostránková webová aplikace“, ve které se navigace v podstatě provádí přepínáním „obrazovek“, zatímco obsah adresní řádek se dynamicky mění a vytvářejí dojem klasických „přechodů stránek“.

3. Odesílání zpráv (událostí) do backendu a přijímání odpovědí musí být oddělené od sebe navzájem a od uživatelské navigace(asynchronní). Zmíněný WebSocket ze své podstaty „doporučuje“ právě takovou implementaci. Všechny zdlouhavé operace by také neměly blokovat rozhraní, pokud tak není výslovně provedeno.

Uživatel tak potřebuje pouze připojení k internetu pro prvotní stažení aplikace (několik sekund). Dále dokáže se službou pracovat i při dočasném výpadku připojení (například z mobilního zařízení v metru, mimo město, v přeplněném hotelu v zahraničí apod.) - aplikace bude zaznamenávat požadavky a zkoušet poslat je, jakmile se objeví internet, a tak stejným způsobem obdrží odpovědi.

To přirozeně nezbavuje vývojáře nutnosti optimalizovat a minimalizovat kód. Jak však ukazuje praxe (například služba Trello), tento úkol není o nic těžší než ostatní.

Poznámka pro pochybující vývojáře webových služeb pro mobilní zařízení: podle praxe autora v roce 2013 na iPadu úspěšně fungují jednostránkové JavaScript aplikace na websocket transportu.

Uživatel pracuje z více zařízení

Z práce využívá vaši službu z práce stolní počítač, cestou domů vytáhne iPhone, a doma zapne tablet. Pokud uživatel odeslal službě nějaký příkaz z rozhraní, čeká na odpověď o výsledcích zpracování. Je snadné pochopit, že pokud (kdy) zpracování trvalo nějaký hmatatelný čas, odpověď by měla být odeslána do zařízení, které uživatel v tuto chvíli používá (omlouvám se za slovní hříčku). doručení odpovědi, nikoli v době žádosti.

Problém je v tom, že nelze jednoznačně říci, zda uživatel přestal používat (opět pardon) to či ono konkrétní zařízení. Možná zavřel prohlížeč. Možná má vybitou baterii. Možná odešel do tunelu metra, kde není žádné spojení, a za půl minuty se objeví znovu. Možností je spousta a autor není znám Nejlepší způsob definice. Zde je však to, co by se vám mohlo hodit:

1. Zaznamenejte (na backendu) všechna zařízení uživatele a čas poslední aktivity z každého z nich.

2. Klasifikujte systémové události, které je třeba hlásit uživateli, na ty, které je třeba doručit pouze aktivním zařízením, a ty, které je třeba doručit „vysílaně“ (na všechna zařízení).

3. Zadejte vrstva navíc abstrakce - služba, která zachytí určité události, které jsou pro uživatele zajímavé, a vytvoří z nich zprávy. Můžete tak snadno vysílat stejnou zprávu o úspěchu operace - v několika typech: krátké upozornění v mobilní zařízení, trochu autentičtější - do prohlížeče, podrobná zpráva - od e-mailem.

4. Vytvořte fronty pro odeslání každému uživateli na každém samostatném komunikačním kanálu (webové rozhraní, mobilní zařízení, pošta). Standardní funkcionalita AMQP vám také pomůže s časovými limity vypršení platnosti zpráv, aby tam neležely déle než určitou dobu a nezanášely systém. Když se uživatel připojí online prostřednictvím určitého kanálu, budou mu doručeny čerstvé nevyřízené zprávy tohoto konkrétního typu.

Autor může dodat, že na stejném systému je možné postavit zpožděné zasílání notifikací (které budou odeslány nejdříve k určitému datu), a dokonce i zasílání skutečné papírové periodické korespondence (úkony, platby atd.). ), ale to je téma na samostatný článek .

Zdůrazním to hlavní: nepovažujte doručené zprávy za nějaké oznámení, na které jste zvyklí na Facebooku nebo Vkontakte. Doručené zprávy jsou výsledky dotazu uživatel! Všechny akce uživatele v rozhraní, které zahrnují nějaké požadavky na backend, dostávají odpovědi v jednotné formě „doručovaných zpráv“ prostřednictvím jediného jednotného komunikačního kanálu. A pak algoritmus webové aplikace pochopí, co je třeba udělat s tou či onou zprávou – nakreslit upozornění s textem, přidat řádek do tabulky, přepnout něco v rozhraní a tak dále.

Paralelní a sekvenční výpočty

Bylo by zbytečné navrhovat rychlé frontendové webové rozhraní, pokud máte pomalý backend. Ne, tohle není o streamech, ani o rozvětvení, ani o Erlangu. Zůstáváme u obvyklého PHP, dostupného pro každého začátečníka/středně pokročilého programátora.

Proč vůbec potřebujeme paralelismus? I když nehovoříme o nedostatcích jednovláknových jazyků obecně, paralelismus výrazně zrychluje výpočet úlohy, což znamená, že výrazně snižuje nároky na hardwarové zdroje (hardware) a zvyšuje spokojenost uživatelů z práce v rozhraní (získávají výsledky rychleji).

Vezměte ve svém webovém projektu jakýkoli poměrně složitý obchodní proces a nakreslete jej jako řetězec kroků. Získáte sekvenci akcí v systému od požadavku po odpověď. S největší pravděpodobností nejprve proběhnou nějaké kontroly, pak provedení hlavního úkolu, poté vedlejší dílčí úkoly a nakonec výstup výsledku. Podívejte se pozorně: lze některou z akcí provádět paralelně?

Uvedu příklad: řekněme, že si uživatel chce zakoupit nějakou službu, která je zahrnuta jako doplňková placená možnost v jeho tarifu. Počet možností je omezený. Pokud je možnost úspěšně zapnuta, musíte uživateli odeslat upozornění v prohlížeči, odeslat duplicitní e-mail, odečíst peníze z jeho fakturačního účtu a upozornit klientské oddělení. Nakreslete řetěz:

1. Systém obdržel požadavek na povolení této možnosti.
2. Autorizujeme uživatele a zjišťujeme jeho tarif.
3. Zkontrolujeme, zda je možné tuto volbu vůbec povolit pomocí tarifní plán uživatel.
4. Zkontrolujte, zda má uživatel na účtu dostatek peněz.
5. Zkontrolujte, zda tato možnost není v konfliktu s jinými nastaveními.
6. Pokud je vše v pořádku, povolte možnost.
7. Odešleme upozornění do prohlížeče.
8. Zasíláme oznámení poštou.
9. Odepsat peníze ve vyúčtování.
10. Informujeme klientské oddělení.

Pozorný čtenář možná najde chybu v sledu akcí, ale autor vám připomene, že jde o přibližný příklad.

co vidíme? Všimněte si, že není důvod provádět všechny kroky postupně. Bylo by mnohem správnější „paralelizovat“ 3,4,5 do tří vláken a na konci - 7,8,9,10 do čtyř vláken.

Přemýšlíte o tocích a rozvětvení? Marně, máte SOA!

Jak dělat paralelní výpočty v SOA

Pro čtenáře, kteří se právě proklikali článkem až sem, vysvětlím, že nejde o paralelizaci stejné úlohy v SOA – k tomu v obecném případě stačí spustit démona v N instancích a postarat se o spor o přístup do databáze.

V tomto příkladu tedy máme tři-čtyři-několik různých úloh, které provádějí různé služby a které chceme provádět paralelně. Odeslání do paralelního zpracování není složité: stačí odeslat jednu událost „může uživatel uživatelského jména povolit volbu X?“ a všechny služby přihlášené k této události ji zachytí, provedou svou kontrolu a odešlou výsledné události.

Problém je právě shromáždit tyto výsledné události, když potřebujeme celkový výsledek jejich práce, abychom se mohli posunout dál. Například ve výše uvedeném seznamu potřebujeme výsledek 3+4+5 a 7+8+9+10 lze ignorovat.

Ve skutečnosti s vysokými požadavky na povinné dokončení transakcí musíte kontrolovat každý řetězec až do konce, ale o tom budeme diskutovat později.

Přirozeně, pokud bude náš démon „viset a čekat“, spotřebovávat zdroje (takzvaný „nečinný“), pak nemůžete vytvořit žádnou takto vysoce nabitou službu. Jde jen o to, že démon řeší jiné úkoly a obsluhuje jiné požadavky jiných klientů, zatímco tři samostatná „vlákna“ (3,4,5) řeší své dílčí úkoly. Potíže přidává také skutečnost, že výsledné události mohou přijít v libovolném pořadí. To vše je však vyřešeno snadno a jednoduše:

Pokud autor ví, žádná z předpřipravených implementací AMQP, které dnes existují, neumožňuje očekávat a „slepit“ několik událostí do jedné, abyste obdrželi pouze to – jeden výsledek. Takže se o to musíte postarat sami, takto:

1. Před odesláním události do AMQP se zavázat k rychlá paměť(použijte jakékoli vhodné úložiště v paměti) seznam názvů výsledných událostí, které služba očekává, že obdrží, a také název události (říkejme tomu „R“), kterou je třeba odeslat se součtem výsledky.

2. Poté služba ukončí cyklus zpracování aktuální události a uvolní se pro další úkoly.

3. Jakmile dorazí jakákoliv událost ze seznamu, který máme uložený v paměti, služba ji „rozbalí“ a uloží její obsah do paměti, přičemž ji přiřadí názvu události. Zároveň kontroluje, zda se v tomto seznamu nenacházejí další události, na které nepřišla odpověď. Pokud ano, smyčka v tomto bodě končí.

4. V opačném případě, to znamená, že pokud všechny události v seznamu obdržely odpověď, služba je slepí dohromady a odešle slepený výsledek pod názvem události „R“, kterou jste si pamatovali dříve. Poté, aby se ušetřila paměť, se seznam s výsledky jednoduše vymaže z paměti - již není potřeba.

5. Stejná služba nebo nějaká jiná (podle uvážení projektanta systému) obdrží výslednou událost „R“ se všemi výsledky paralelního zpracování. Co následuje, je zřejmé.

Pokud se vám z popisu zdálo, že je to dlouhá doba, pak vysvětlím - bavíme se o tisících a desetitisících událostí za sekundu (!) na jednom průměrném serveru.

Použití úložiště v paměti znamená, že i když se služba zastaví (spadne, aktualizuje), aktuální obchodní proces se neztratí. Po opětovném spuštění bude služba nadále přijímat události z ESB a zpracovávat je podle výše popsaného algoritmu.

Transakčnost, vrácení operací (rollback) a scénáře selhání v SOA

Protože v SOA „procházejí“ peer události přes ESB, potřebujete nějaký druh náznaku, že „tato odpověď“ odkazuje na „tamhle požadavek“. Zde není třeba znovu vymýšlet kolo - ve specifikacích jakéhokoli populárního protokolu najdete parametr s názvem jako id_korelace. Obvykle se jedná o řetězec. Musí být obsažen v parametrech všech událostí každého jednotlivého obchodního procesu, od vstupu až po výstup, aby bylo možné identifikovat řetězec zpráv, který patří k tomuto obchodnímu procesu. Při pohledu ze strany webového rozhraní webová aplikace ukládá aktuální aktivní (odeslané) požadavky a pomocí correlation_id „rozumí“, na který požadavek každá konkrétní odpověď přišla.

Pojďme se zabývat terminologií: transakčnost je vlastnost systému provádět několik akcí jako jednu společnou operaci, která dává smysl a lze ji dokončit pouze úplně. Protože je fyzicky nemožné provádět několik operací atomicky v distribuovaném systému s paralelními vlákny, systém poskytuje takzvané scénáře selhání a vrácení zpět.

Scénář selhání je obecně akce, která se má provést, když dojde k chybě. Vrácení zpět je v tomto kontextu skript akcí, které je třeba provést, aby se „vrátila“ řada předchozích akcí, které nakonec vedly k chybě. Zhruba řečeno, vrácení zpět jsou procesy, které jsou opakem běžných obchodních procesů v systému.

Vrácení zpět není vždy potřeba a ne vždy je možné. Pokud jste například připojili nějakou možnost k uživateli a poté „spadli“ na fakturaci, lze tuto možnost zpět zakázat. No, pak to můžete zkusit znovu, automaticky nebo druhým příkazem od uživatele. A pokud jste obsah fyzicky smazali a některé následné operace nefungovaly... Situace je nejednoznačná.

Proto je třeba ke scénářům selhání a vrácení zpět přistupovat moudře. Autor může doporučit následující cestu: Vždy pište neúspěšné skripty, ale ne vždy pište vrácení zpět. Vaše neúspěchy se okamžitě promítnou do monitoringu – a tým podpory bude moci rychle opravit situaci vlastníma rukama, získat zkušenosti a formulovat technické požadavky na programátory. Zatímco napsat jedinečně správný rollback od nuly může být velmi, velmi obtížné.

Nicméně je třeba chápat, že vrácení zpět, vrácení zpět, řešení chybných situací jsou stejné obchodní procesy jako všechno ostatní. Jsou také založeny na událostech procházejících systémem. Bude hezké, když si zpočátku stanovíte dvě opačné cesty (vpřed a vzad, úspěch a neúspěch) v každé události a u každého handlera, abyste je mohli implementovat do konkrétních úkolů.

SOA škálování

Jakýkoli systém bude muset být dříve nebo později rozšířen. V případě SOA se to dělá snadno a přirozeně:

1. Duplicitní vstupní bod. To se týká stejné brány WebSocket, kterou jsme zvažovali na začátku článku. Může být duplikován neomezeně mnohokrát, protože komunikace mezi ním a klientem je sjednocená a oddělená od vnitřností systému a komunikace mezi ním a systémem je zase oddělena od komunikace s klientem.

2. Duplicitní instance(instance) služeb. Služby, které nevyžadují databázi nebo z nich pouze „čtou“, jsou plynule duplikovány. A běžná funkčnost RabbitMQ vám umožní přihlásit se k N instancím do stejné fronty, zprávy, ze kterých budou náhodně přicházet v té či oné instanci. Při duplikování služeb, které se zabývají externími aplikacemi (databáze, software třetích stran), musíte zvážit, jak tyto aplikace poskytují transakční požadavky od několika paralelních klientů.

3. Duplikace datových úložišť. Zde můžete volně používat jakýkoli sharding, který znáte. Pokud máte co do činění s 10 miliony uživatelů a zdá se vám to hodně, vydělte je 10 miliony základen (například na základě CRC32 z přihlášení uživatele nebo nějakou jinou kruhovou metodou). Pokud databáze jedné služby neustále roste a stává se složitější, rozdělte ji na dvě služby.

4. Duplikování AMQP brokera a úložiště v paměti. Z autorovy praxe RabbitMQ a Redis dokonale plní svou roli. Pokud máte zařízení ve více než jednom DC racku, zvolte králičí režim, který je tolerantní k výpadkům síťového připojení.

5. Plná strojová duplikace. Z moderní technologie virtualizace (KVM) a konfigurace (Chef), úkol „vybudovat stejný stroj“ spočívá ve stisknutí jednoho tlačítka.

Šifrování provozu mezi frontendem a backendem

Doporučuje se zorganizovat připojení WebSocket přes SSL. Kromě toho zvyšuje „penetraci“ proti zaostalým kancelářským poskytovatelům, kteří blokují „jakýkoli podivný provoz“ kromě HTTP[S].

Pokud by se vám to však zdálo nedostatečné, můžete si zajistit generování párů klíčů s každým přihlášením klienta (jeden pár na frontendu, druhý na backendu), vyměňovat si veřejné klíče a dále šifrovat veškerý provoz běžným RSA.

Ochrana proti DDOS a podobnému zneužití

Autor záměrně vynechává otázku „nízkoúrovňové“ ochrany, pokud jde o zaplavení SYN a zaplavení kanálů se stovkami gigabitů, protože o tom byly napsány stovky knih odborné literatury. Promluvme si o tom, jak ochránit systém již uvnitř, na jeho logických úrovních, když útočník našel způsob, jak „zaplavit“ váš systém (SOA + ESB) tisíci událostmi.

1. První pravidlo: nic se nesmí zpracovávat, dokud není potvrzena jeho platnost. Pokud očekáváte jako vstup malý text v JSON zabalený do BASE64, pak by měl být příchozí řetězec delší než megabajt výslovně zahozen – nepokoušejte se jej rozbalit. Řetězec obsahující „nelatinské“ znaky je podobný. Když rozbalíte řetězec, nezkoušejte hned provést json_decode, nejprve zkontrolujte počet a párování závorek. A tak dále.

Vypadá to jako paranoia, ale jinak můžete být snadno „zaplněni z paměti“, to znamená, že to povede k selhání služby a přinutí ji zabírat veškerou dostupnou RAM.

2. Služba, která zpracovává příchozí zprávy, by neměla nic zapisovat do paměti, do databáze a dalších úložišť. Důvod je stejný. Nejprve se ujistěte, že je zpráva platná jako celek, a teprve poté ji pusťte „hlouběji“ do systému.

3. Služba, která může být nucena „přejít do databáze“, musí být často chráněna ukládáním do mezipaměti. Jednoduchým příkladem je služba autorizace uživatelů. Pokud není chráněn, může útočník poslat tisíce požadavků na autorizaci za sebou, čímž přetíží databázi.

4. Na vstupu do systému potřebujete službu, která odmítá požadavky z „podezřelých“ zdrojů, například z IP adres z „černé listiny“.

Zní to jako klasická rada, tak o co jde? Hlavním problémem je, že pokud na vstup do systému dáme službu analyzátor-filtrování (jak se to dělá v klasických webových projektech), pak výkon celého systému nebude vyšší než výkon tohoto analyzátoru-filtru. Přezkoumání každé zprávy na podezření „v reálném čase“ je extrémně nákladné. Můžete a měli byste to udělat až poté, a takto:

1. Vytvořte službu, která bude „naslouchat“ všem zprávám v systému. V RabbitMQ je toho dosaženo přihlášením ke směrovacímu klíči "#".

2. Naučte tuto službu určitým pravidlům, podle kterých může diagnostikovat „podezřelé“ odesílatele. Jedná se například o odesílatele, kteří posílají příliš mnoho podobných zpráv v časovém intervalu, nebo posílají opakované zprávy, případně posílají zprávy jménem stejného uživatele z různých IP adres... Možností je spousta, zapněte si představivost. Nezáleží přitom na tom, jak rychle taková služba funguje (samozřejmě v rozumných mezích) – na rychlost celého systému to nemá vliv.

3. Jakmile služba usoudí, že ten a ten odesílatel je podezřelý, odešle tuto událost do systému a dál si dělá po svém.

4. Na vstup dejte velmi jednoduchého a rychlého démona - filtrovací službu, jejímž úkolem bude prostě "hloupě" blokovat podezřelé odesílatele. Žádná analýza, žádná analýza, žádné dodatečné náklady. Je snadné uhodnout, kdo je považován za podezřelého: služba se o nich dozví z událostí popsaných v předchozím odstavci a přidá je na svou interní černou listinu.

Konec prvního dílu. Pokračování: SOA: distribuovaná architektura a její údržba.

Jsem mentor v IT projektech. To znamená, že pokud jste vlastníkem nebo vůdcem, mohu vám pomoci dosáhnout nových výšin. Vyčistit procesy, pochopit motivaci týmu, implementovat nástroje a dosáhnout konkrétních cílů. Neučím, jak podnikat, ale pouze pomáhám obejít štědře rozházené hrábě na vaší cestě. .