Materiál je určený hlavne pre začínajúcich programátorov webu.

Úvod.

Často sa na mňa obracajú klienti, ktorí majú nainštalovaný vlastný CMS systém alebo moduly napísané začínajúcimi webovými programátormi, ktorí nerozumejú tomu, čo je potrebné na ochranu údajov a často kopírujú funkcie filtrovania bez toho, aby premýšľali o tom, ako fungujú a čo presne je s nimi potrebné urobiť. .

Tu sa pokúsim opísať čo najpodrobnejšie. Bežné chyby pri filtrovaní údajov PHP skript a dať jednoduché tipy ako správne filtrovať údaje.

Na nete je množstvo článkov o filtrovaní dát, no nie sú, ako sa patrí, nie úplné a bez podrobných príkladov.

Debrífing.

Filtrácia. Chyba #1
Pre číselné premenné sa používa nasledujúca kontrola:
$číslo = $_GET["vstupné_číslo"]; if (intval($number)) ( ... spustiť SQL dotaz... )
Prečo to vedie k SQL injekcia? Ide o to, že používateľ môže špecifikovať v premennej vstupné_číslo význam:
1"+UNION+SELECT
V takýchto prípadoch prebehne kontrola úspešne, pretože funkcia intval dostane celočíselnú hodnotu premennej, t.j. 1, ale v samotnej premennej $číslo nic sa teda nezmenilo škodlivý kód budú odovzdané SQL dotazu.
Správne filtrovanie:
$cislo = intval($_GET["vstupne_cislo"]); if ($number) ( ... spustiť SQL dotaz... )
Samozrejme, podmienka sa môže zmeniť, napríklad ak potrebujete získať len určitý rozsah:
if ($číslo >= 32 A $číslo<= 65)

Ak používate začiarkavacie políčka alebo viacnásobné výbery s číselnými hodnotami, začiarknite toto:
$checkbox_arr = array_map("intval", $_POST["checkbox"]);
array_map
S filtrovaním sa stretávam aj v tvare:
$cislo = htmlspecialchars(intval($_GET["vstupne_cislo"]));
htmlšpeciálne znaky
alebo:
$cislo = mysql_escape_string(intval($_GET["vstupne_cislo"]));
mysql_escape_string

Nič iné ako úsmev za to nemôže :)

Filtrácia. Chyba #2.
Pre reťazcové premenné sa používa nasledujúce filtrovanie:
$vstupny_text = pridavne lomky($_GET["vstupny_text"]);
Funkcia lomítka uniká zo špecifikácie. znakov, ale nezohľadňuje kódovanie databázy a je možné obísť filtrovanie. Nebudem kopírovať text autora, ktorý opísal túto zraniteľnosť a jednoducho dám odkaz na Chrisa Shifletta (preklad si môžete vyhľadať v Runete).

Použite funkciu mysql_escape_string alebo mysql_real_escape_string, príklad:
$vstupny_text = mysql_escape_string($_GET["vstupny_text"]);
Ak nemáte v úmysle vstúpiť html tagy, potom je najlepšie vykonať nasledujúce filtrovanie:
$vstupny_text = strip_tags($_GET["vstupny_text"]); $vstupny_text = htmlspecialchars($vstupny_text); $vstupny_text = mysql_escape_string($vstupny_text);
strip_tags - stripuje html značky.
htmlspecialchars - konvertuje špeciálne. znaky v entite html.
Takto sa okrem SQL injection ochránite aj pred XSS útokmi.
Ak potrebujete html tagy, ale len na zobrazenie zdrojového kódu, potom stačí použiť:
$vstupny_text = htmlspecialchars($_GET["vstupny_text"]); $vstupny_text = mysql_escape_string($vstupny_text);

Ak je pre vás dôležité, aby hodnota premennej nebola prázdna, použite funkciu trim, napríklad:
$vstupny_text = trim($_GET["vstupny_text"]); $vstupny_text = htmlspecialchars($vstupny_text); $vstupny_text = mysql_escape_string($vstupny_text);

Filtrácia. Chyba #3.
Ide o vyhľadávanie v databáze.
Na vyhľadávanie podľa čísel použite filtrovanie popísané v prvej chybe.
Na vyhľadávanie podľa textu použite filtrovanie popísané v druhej chybe, ale s výhradami.
Aby ste zabránili používateľovi vykonať logickú chybu, musíte odstrániť alebo uniknúť špeciálne. SQL znaky.
Príklad bez pridania. spracovanie linky:
$vstupny_text = htmlspecialchars($_GET["vstupny_text"]); // Hľadanie: "%" $input_text = mysql_escape_string($input_text);
V dôsledku toho dostaneme dotaz ako:
... WHERE text_row LIKE "%".$input_text."%" ... // WHERE text_row LIKE "%%%"
Tým sa výrazne zvýši zaťaženie základne.
V mojom skripte používam funkciu, ktorá z vyhľadávania odstraňuje znaky, ktoré nechcem:
function 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); návrat $text; )
Samozrejme, nie všetky vyššie uvedené symboly sú nebezpečné, ale v mojom prípade nie sú potrebné, preto vykonávam vyhľadávanie a nahrádzanie.
Príklad použitia filtrovania:
$vstupny_text = strip_data($_GET["vstupny_text"]); $vstupny_text = htmlspecialchars($vstupny_text); $vstupny_text = mysql_escape_string($vstupny_text);
Odporúčam vám tiež obmedziť počet znakov vo vyhľadávaní, aspoň nie menej ako 3, pretože. ak máte v databáze veľké množstvo záznamov, tak vyhľadávanie 1-2 znakov výrazne zvýši záťaž databázy.
Filtrácia. Chyba #4.
Hodnoty premenných nie sú filtrované $_COOKIE. Niektorí ľudia si myslia, že keďže táto premenná nemôže byť prenesená cez formulár, potom je to záruka bezpečnosti.
Túto premennú je veľmi ľahké sfalšovať ľubovoľným prehliadačom úpravou súborov cookie stránky.
Napríklad v jednom známom CMS bola kontrola použitej šablóny stránky:
if (@is_dir (MAIN_DIR . "/template/" . $_COOKIE["skin"]))( $config["skin"] = $_COOKIE["skin"]; ) $tpl->dir = MAIN_DIR . "/šablóna/". $config["skin"];
V tomto prípade môžete zmeniť hodnotu premennej $_COOKIE["koža"] a vyvolať chybu, v dôsledku čoho uvidíte absolútnu cestu k priečinku lokality.
Ak na uloženie do databázy použijete hodnotu cookies, potom použite niektorú z vyššie popísaných filtrácií, to isté platí pre premennú $_SERVER.
Filtrácia. Chyba #5.
Vrátane smernice register_globals. Nezabudnite ho vypnúť, ak je zapnutý.
V niektorých situáciách môžete odovzdať hodnotu premennej, ktorá nemala byť odovzdaná, napríklad ak má stránka skupiny, potom pre skupinu 2 premenná $group by mala byť prázdna alebo rovná 0, ale stačí na falošné formulár pridaním kódu:

Premenná v PHP skripte $skupina sa bude rovnať 5, ak nebol deklarovaný s predvolenou hodnotou v skripte.
Filtrácia. Chyba číslo 6.
Skontrolujte stiahnuté súbory.
Skontrolujte nasledujúce položky:
  1. Rozšírenie súboru. Je vhodné zakázať načítanie súborov s príponami: php, php3, php4, php5 atď.
  2. Je súbor nahraný na server move_uploaded_file
  3. veľkosť súboru
Vyšetrenie. Chyba #1.
Stretol som sa s prípadmi, keď na požiadavku AJAX (napríklad: zvýšenie reputácie) bolo odovzdané používateľské meno alebo ID (komu sa reputácia zvyšuje), ale samotné PHP existenciu takéhoto používateľa nekontrolovalo.
Napríklad:
$user_id = intval($_REQUEST["user_id"]); ... INSERT INTO REPLOG SET uid = "($user_id)", plus = "1" ... ... AKTUALIZÁCIA SADA POUŽÍVATEĽOV reputácia = reputácia+1 WHERE user_id = "($user_id)" ...
Ukázalo sa, že vytvoríme záznam v databáze, ktorý je pre nás úplne zbytočný.
Vyšetrenie. Chyba #2.
Pri vykonávaní rôznych akcií (pridávanie, úprava, mazanie) s údajmi nezabudnite skontrolovať práva používateľa na prístup k tejto funkcii a pridané vlastnosti (html použitie značky alebo možnosť publikovať materiál bez overenia).

Dlho som odstraňoval podobnú chybu v jednom module fóra, kedy mohol ľubovoľný používateľ upravovať správu o administrácii.

Vyšetrenie. Chyba #3.
Pri použití viacerých php súbory urobte jednoduchú kontrolu.
V súbore index.php(alebo do akéhokoľvek iného hlavného súboru) napíšte tento riadok pred zahrnutím ďalších súborov php:
define("READFILE", true);
Na začiatok ostatných súborov php napíšte:
if (! definované ("READFILE")) ( exit ("Chyba, nesprávna cesta k súboru.
Prejdite na hlavnú."); }
Tým sa obmedzí prístup k súborom.
Vyšetrenie. Chyba #4.
Použite hash pre používateľov. Pomôže to zabrániť volaniu konkrétnej funkcie pomocou XSS.
Príklad zostavenia hash pre používateľov:
$tajný_kľúč = md5(strtolower("http://site.ru/" . $člen["meno"] . sha1($heslo) . dátum("Ymd"))); // $secret_key je náš hash
Ďalej vo všetkých dôležitých formulároch nahraďte vstup hodnotou aktuálneho hashu používateľa:

Počas vykonávania skriptu skontrolujte:
if ($_POST["secret_key"] !== $secret_key) ( exit ("Error: secret_key!"); )
Vyšetrenie. Chyba #5.
Pri výstupe chýb SQL urobte jednoduché obmedzenie prístupu k informáciám. Napríklad nastaviť heslo pre GET premenná:
if ($_GET["passsql"] == "heslo") ( ... výstup chyby SQL... ) else ( ... Iba informácie o chybe, žiadne podrobnosti... )
Tým sa pred hackerom skryjú informácie, ktoré mu môžu pomôcť pri hackovaní stránky.
Vyšetrenie. Chyba #5.
Snažte sa nezahŕňať súbory získavaním názvov súborov zvonku.
Napríklad:
if (isset($_GET["názov_súboru"])) (zahrnúť $_GET["názov_súboru"] .".php"; )
Použite prepínač

Vytváram jeden jednoduchý zoznam v PHP, kde môže používateľ pridať meno, vek, e-maily atď. Pridal som aj možnosť odstránenia, ale chcem pridať potvrdzujúcu správu, keď používateľ klikne na tlačidlo vymazať.

Skúšal som googliť, ale našiel som len riešenia jQuery a JavaScript. Existuje spôsob, ako to urobiť iba s PHP?

názovVek"; while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["meno"].""; echo" ".$query2["vek"].""; echo" Upraviť"; echo" X"; } ?>

Odstrániť.php

v

Ak to chcete urobiť iba v PHP, musíte do skriptu pridať „kroky“, napríklad:

Krok 1 (zobraziť formulár) -> krok 2 (požiadať o overenie) -> krok 3 (overiť)

Ak to chcete urobiť, môžete použiť relácie na uloženie obsahu formulára a parameter GET na sledovanie tohto kroku. Inak najviac jednoduché riešenie je použiť javascript:

ozvena" X"; //použite dvojité úvodzovky pre js v php!

To je to, čo potrebujete

While($query2=mysql_fetch_array($query1)) ( echo " ".$query2["meno"].""; echo" ".$query2["vek"].""; echo" Upraviť"; echo" X"; ) in while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["meno"].""; echo" ".$query2["vek"].""; echo" Upraviť"; echo" X"; }

a vytvorte funkciu javascript

Funkcia potvrdenieDelete(anchor) ( var conf = potvrdit("Naozaj chcete odstrániť tento záznam?"); if(conf) window.location=anchor.attr("href"); )

ver mi, je to praca 🙂

Pridajte udalosť onClick na spustenie dialógového okna a javascript:return potvrďte ("naozaj to chcete vymazať?");

ozvena" X";

//pridať udalosť onclick onclick="return deleteconfig()"

pracujte pre mňa, ale zmeňte toto:

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

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

Nižšie je uvedený variant vyššie, ktorý poskytuje potvrdzovacie pole a odovzdáva premennú z PHP do Javascriptu a späť do PHP.
Použil som to na výber prepínača na odstránenie súboru zo zoznamu súborov.
Pozrite si spúšťaciu funkciu OnClick s názvom php $fileName v Javascripte, potvrďte názov súboru a ak áno, zadajte href s premennými pre $_GET

PHP/HTML kód:

$fileName $extn $veľkosť $modtime "; ?>

Článok nie je o klastroch, ani o shardovaní s replikáciou a dokonca ani o cloudoch. Článok je o budovaní vysoko spoľahlivej výpočtovej architektúry, v ktorej počet používateľov a ich požiadaviek môže rásť ako lavína. A pre biznis je rozhodujúce, aby webová služba prijala každú požiadavku, spracovala ju správne a do konca (bez ohľadu na zlyhania a pády niektorých komponentov) a zaručene doručila klientovi odpoveď. A, samozrejme, bez „priestorových“ nákladov na vybavenie a platy pre správcov systému.

Inými slovami, v prvom rade premýšľajte - "potrebujem to." Ak má niekto internetový obchod, ktorý predáva hovoriacich škrečkov s obratom 100 objednávok za mesiac, asi nie. A ak plánujete prevádzkovať podnik, ktorý pojme státisíce a milióny používateľov, vyžaduje veľké množstvo výpočtov, pracuje s dátami vysokej hodnoty, zaručuje transakčnú schopnosť každého obchodného procesu a potrebuje paralelné spracovanie údajov, je to?

Finančný sektor, veľké internetové obchody s radom státisícov kusov, online aukcie, rezervačné systémy hotelov a leteckých spoločností, nový cloud či sociálne služby s ambíciou získať miliónovú užívateľskú základňu už na druhý deň po spustení reklamnej kampane sú potenciálny záujem o vysoko spoľahlivý systém pre vaše webové služby.

Komu je tento materiál určený

1. Vývojári veľkých webových projektov, ktorí majú záujem o vytváranie vysoko zaťažených a chybám odolných výpočtových služieb.

2. Majitelia nových alebo expandujúcich podnikov, ktorí očakávajú „explozívny“ rast používateľskej základne a kladú vysoké nároky na výpočtovú časť.

3. Technickí lídri a manažéri veľkých webových projektov, ktorí nie sú spokojní so súčasným stavom a uvažujú o zásadnej reorganizácii.

Prečo toľko slov o „výpočtoch“?

Pretože bezprostredná budúcnosť veľkých webových projektov leží v oblasti „ veľké dáta“ („Big Data“) je trend, ktorý bol v roku 2011 spolu s virtualizáciou, úsporou energie a monitorovaním označený ako jeden z najlepších a od roku 2013 pevne zaujal svoje miesto v priemysle a dokonca sa stal jedným z akademických predmetov na veľkých zahraničných univerzitách.

Množstvo údajov, ktoré je potrebné spracovať na riešenie obchodných problémov, sa dnes neustále zvyšuje a v budúcnosti sa tento proces bude len zrýchľovať. Ak pred desiatimi rokmi stačilo používateľovi ukázať „internetový obchod“ s produktom, pred rokom stačilo analyzovať cestu používateľa cez stránku a ukázať mu striktne relevantný produkt (tzv. „behaviorálne technológie“ ), dnes sa považuje za normu vedieť o používateľovi všetko, vrátane výšky, hmotnosti, veku a mena vášho obľúbeného psa.

Zákony prirodzenej konkurencie diktujú, že ak chcete zákazníkom poskytnúť viac možností ako vaši konkurenti, potrebujete viac údajov a viac výpočtov. A skôr či neskôr sa v nich váš projekt bez správnych prístupov môže utopiť – tak ako sa teraz všade topia rôzne projekty: niekto kvôli zložitosti podpory, niekto jednoducho kvôli zlému kódu, niekto kvôli vysokej konektivite modulov, niekto z dôvodu použitia nespoľahlivých komponentov.

Preto každý, kto dnes začína s webovým projektom s veľkými ambíciami, získa viac výhod oproti súperom, ak svoj projekt bude spočiatku považovať nielen za programový kód, ale aj za výpočtové prostredie – systém s vlastnými zákonitosťami existencie a vývoja. Čím viac pozornosti venujete riadenie výpočtovej techniky na štarte, tým je pravdepodobnejšie, že v nasledujúcich rokoch predbehnete konkurentov.

Autor týchto riadkov je presvedčený, že „klasický“ moderný prístup k budovaniu vysoko zaťažených webových služieb má množstvo vážnych nedostatkov. Pozrime sa prečo. Najprv zvážte typickú modernú schému:

Klasický prístup k budovaniu vysoko zaťaženej webovej služby

1. Mnoho serverov rozdelených do rolí.

2. Časť serverov (úloha frontendu) je navrhnutá tak, aby vracala statické zdroje (obrázky, CSS, súbory JS) a „distribuovala“ prvú časť prichádzajúcej prevádzky do uzlov v smere toku. Hlavným softvérom je zvyčajne Nginx.

3. Dolné uzly (rola Backend) sú zapojené do dynamických výpočtov. Jednoducho povedané, môže ísť o typický balík Apache + PHP.

4. Ďalšia skupina serverov je určená na ukladanie dát. Sú to MySQL, Memcache, Redis a tak ďalej.

5. Samotný kód webovej služby (v tento príklad– kód PHP) sa rovnako skopíruje do všetkých uzlov, kde je Apache + PHP, a rovnako spracováva tie požiadavky, ktoré „padnú“ na jeden alebo iný uzol.

6. Databázy sú „premazané“ cez svoju skupinu serverov pomocou určitej formy shardingu a záťaž na nich je vyvážená podobným spôsobom.

Pozorný čitateľ si všimne, že vyvažovanie DNS a CDN sa v schéme nespomína, no autor ich zámerne vynechal, aby schému príliš nekomplikoval. Princíp fungovania týchto kusov je veľmi podobný vyššie uvedenému.

Nevýhody klasického prístupu

1. Hlavným trendom sú komplikácie. V priebehu života projektu sa „klasická“ schéma stáva čoraz komplikovanejšou. S pridaním každého nového servera ho musíte zadať do schémy rozloženia prevádzky. Samozrejme, vo veľkých projektoch je uvedenie servera do roly akciou „jedného tlačidla“, no napriek tomu ide o zvýšenie infraštruktúry, ktorú je potrebné podporiť. A ešte viac - v prípade, že súčasné kapacity databázy už nestačia a potrebujete „žiť“ (bez zastavenia služby) preniesť alebo distribuovať databázu na nové servery.

Hlavným problémom však je, že zvýšenie klastra distribúcie návštevnosti nevedie k zníženiu zložitosti programového kódu. Môžete vytvoriť klaster bezchybne, ale kód zostane rovnaký.

2. Nasadenie nie je atómové. Jednoducho povedané, rozloženie Nová verzia projekt na bojových serveroch nejaký čas trvá. Je potrebné fyzicky stiahnuť súbory na N-20 počítačov, vykonať zmeny v databáze, resetovať vyrovnávacie pamäte (veľa rôznych vyrovnávacích pamätí) a súčasne na všetkých serveroch dokončiť spracovanie požiadaviek so „starým kódom“ a začať spracovávať pomocou „ nový kód“. V opačnom prípade môže dôjsť k mnohým malým konfliktom, keď sa časť požiadavky používateľa spracuje starým spôsobom, časť novým spôsobom, časť prešla do databázy podľa „starej schémy“, časť „podľa novej“ a tak ďalej.

Preto v ideálnom prípade chce každý službu na dobu aktualizácie (niekoľko sekúnd či desiatok sekúnd) pozastaviť a následne opäť zapnúť. V skutočnosti s tokom aspoň 1000 požiadaviek za sekundu to nikto nerobí, radšej pravidelne opravuje menšie kolízie „ručne“ alebo ich pokrýva defenzívnym programovaním, ktoré podporuje spätnú kompatibilitu „až do siedmej generácie“. O tom, ako pravidelná podpora spätná kompatibilita komplikuje život programátorom (a zvyšuje náklady na projekt ako celok) – šikovný čitateľ si môže myslieť sám.

3. Používa sa protokolom HTTP. Protokol HTTP je zjavne morálne a technicky zastaraný a ak budete postupovať (napr. mobilný vývoj- viete, že je všade nahrádzaný ľahšími protokolmi. Hlavná nevýhoda je však iná: protokol HTTP „v prehliadači“ vyžaduje dokončenie slučky - vyžaduje odpoveď v obmedzenom čase. To zaväzuje službu vypočítať a pripraviť odpoveď striktne v rámci malého časového limitu, ktorý to prehliadač umožňuje. Ak je služba tento moment preťažený - požiadavka bude navždy stratená.

Preto sa v „typických webových projektoch“ uchyľujú k rôznym trikom, ako je Long polling alebo iná forma periodických požiadaviek, čo nielen komplikuje architektúru, ale aj preťažuje službu zbytočným „premrhaním ťahaním“.

4. Inicializácia skriptu na požiadavku. Je to dôsledok používania HTTP a skriptovacích jazykov ako PHP, ktoré sa podľa dlhoročnej tradície reštartujú v reakcii na každú požiadavku. Áno, áno, v reakcii na každú z 1000 požiadaviek za sekundu sa PHP skript spustí odznova, znova inicializuje všetky premenné a znova vytvorí spojenie s databázou. V praxi sa stáva, že spracovanie požiadavky trvá 0,005 sekundy a skript sa inicializuje rádovo 0,05 sekundy – desaťkrát dlhšie!

Inými slovami, 90% času sú vaše servery zaneprázdnené nevybavovaním požiadaviek klientov, ale zbytočnou inicializáciou skriptov. Skúste to previesť na peniaze. Preto bolo vynájdených veľa riešení, ako napríklad ukladanie do vyrovnávacej pamäte OPcode, trvalé pripojenia k databáze, lokálne vyrovnávacie pamäte ako Memcache alebo Redis, ktoré sú navrhnuté tak, aby kompenzovali tento nepríjemný efekt.

5. Monolitická aplikácia. Bez ohľadu na to, ako rozdelíte aplikáciu na moduly, bez ohľadu na to, ako veľmi sa snažíte šíriť kód cez zložitú adresárovú štruktúru, bez ohľadu na to, aké lenivé automatické načítanie používate, existuje len jedno kritérium: ak potrebujete nahrať celú aplikáciu aspoň jedna zmena, máte monolitickú aplikáciu. Nič iné nie je dané.

Nevýhody monolitických aplikácií sú masívne opísané v literatúre. Jeden z hlavných možno stručne spomenúť: ak chcete, aby bola aj tá najmenšia funkcia vo výrobe do hodiny, musíte do jednej hodiny vtesnať celý výrobný reťazec. Definícia problému, implementácia, spätná kontrola kompatibility, písanie testov, písanie dokumentácie, beh cez oddelenie manuálneho testovania, oprava chýb – to všetko do hodiny.

Pretože ak nahráte celú aplikáciu presne o 00 minút každej hodiny, potom do konca každej hodiny by ste mali priniesť celú aplikáciu do stabilného stavu.

6. Webové rozhranie je vykresľované backendom. V typickom prípade, vzhľad(a teda aj kód HTML) stránok projektu sa spravidla vykresľuje na strane Backendu ako odpoveď na každú požiadavku. Ide o nadmerné, neoprávnené vynakladanie zdrojov a peňazí.

7. Politické členenie rezortov. oddelenie správcov systému je zodpovedný za zabezpečenie toho, aby bol prichádzajúci prenos „premazaný“ cez množstvo serverov, na ktorých beží kód PHP. Za kód PHP je zodpovedné oddelenie programovania. Ak kód PHP nestihol spracovať konkrétnu požiadavku, potom nie je jasné, kto je za to zodpovedný - buď správca, ktorý „prepustil“ príliš veľa prevádzky na server a preťažil ho, alebo programátor, ktorý napísal non - optimálny scenár. Ak sa databáza začne spomaľovať, potom tiež nie je jasné, kto zostáva extrémom: správca, ktorý si to včas neuvedomil, že ju „natrhol“, alebo programátor, ktorý by na to tiež mohol prísť.

Ak sa vám zdajú príklady prehnané a „nie zo skutočného života“, nezabudnite, že autor pracoval v projekte, ktorý bol hosťovaný na 200 serveroch a 60 z nich bolo obsadených databázou. Je desivé spomenúť si, koľko ľudí bolo zamestnaných na obsluhu tohto projektu.

Hlavná nevýhoda

Opakujeme vyššie uvedenú myšlienku: hlavnou nevýhodou klasickej schémy je podľa autora to, že technickí špecialisti optimalizujú nesprávnu vec. Optimalizujú prichádzajúcu frontu požiadaviek, v skutočnosti ich „rozmazávajú“ cez veľkú skupinu strojov, namiesto toho, aby optimalizovali samotnú podstatu – výpočtovú časť. A je to oveľa jednoduchšie, ako to vyzerá.

teoretický ideál

Ach, ako by sme chceli:

1. Zbavte sa množstva drahých serverov a použite jednu alebo dve malé skupiny.

2. Opustite schému Nginx->Apache->PHP s jej divokou „réžiou“ v zmysle spotrebovaných zdrojov, ktoré stoja peniaze.

3. Z rovnakého dôvodu eliminujte obrovské náklady na inicializáciu PHP skriptov.

4. Odmietnite potrebu „renderovať“ stránky na backende. Bolo by celkom snom, keby webová služba mohla fungovať s nestabilným alebo žiadnym internetovým pripojením (napríklad pri používaní mobilná sieť na ceste).

5. Zbavte sa „slučky časového limitu“ HTTP, doručte odpoveď klientovi až vtedy, keď je táto odpoveď pripravená a so zárukou doručenia.

6. Aktualizujte projekt po malých častiach, bez zastavenia a bez straty jedinej požiadavky klienta.

7. Nerobte si starosti so stratenými požiadavkami, ak časť projektu (nejaký komponent) „spadla“ alebo bola dočasne vypnutá pre účely ladenia.

Neskutočné? Jednoducho!

Prvé kroky k dokonalosti

Po prvé, poďme sa učiť čo musí sa to urobiť, preto budeme diskutovať - ako.

1. Navrhnite celý systém ako SOA(servisne orientovaná architektúra) s ESB (enterprise messaging bus), pričom sa upustilo od monolitického prístupu, takže každá nezávislá časť obchodnej logiky je spracovaná samostatnou „službou“ a navzájom by komunikovali prostredníctvom nezávislej výmennej zbernice.

2. Opustite synchronicitu. Napríklad v synchrónnej schéme „požiadavka – spracovanie – odpoveď“ ide o jednu slučku HTTP, ktorá nemá prísnu kontrolu ukončenia a možno ju ľahko prerušiť. V asynchrónnom režime existujú tri samostatné procesy: požiadavka (odoslaná a potvrdená), spracovanie (opakovaný pokus v prípade zlyhania), doručenie odpovede (so zárukou).

3. Rozdeľte projekt na dve aplikácie- Frontend a Backend. V prípade webovej služby je frontendom (zvyčajne) JavaScriptová aplikácia. Pointa je, že aplikácie fungujú asynchrónne a navzájom oddelené, pričom si vymieňajú správy cez obojsmerný komunikačný protokol.

4. Deaktivujte HTTP v prospech WebSocket. Protokol WebSocket má v porovnaní s HTTP fantastický výkon, nemá žiadne „slučky s časovými limitmi“ a umožňuje prenášať akékoľvek dáta (vrátane binárnych dát) v oboch smeroch.

5. Poskytnite „úložisko“ pre spúšťanie dopytov. Po prijatí požiadavky od klienta povedzte klientovi „Potvrdiť“ a uložte túto požiadavku. Hneď ako sa backend uvoľní z predchádzajúceho cyklu spracovania, pošlite mu požiadavku. Pokiaľ požiadavka „prechádza“ medzi koncovými uzlami, uchovávajte ju od okamihu, keď „vstúpila“ do uzla, a potvrďte ju hneď, ako „opustí“ uzol. Ak teda nejaký uzol „spadne“, systém požiadavku nestratí a okamžite ju pošle späť na spracovanie. Na konci spracovania odošlite výsledok klientovi a uložte ho, kým klient nepovie „Potvrdiť“.

6. Zabezpečte paralelné výpočty pre tie operácie, ktoré možno vykonávať paralelne z hľadiska obchodnej logiky, a postupnosť pre tie, ktoré sa musia vykonávať striktne sekvenčne. Tento odsek nebol napísaný s nárokom na „zjavnosť kapitána“, ale aby ukázal, že žiadny obchodný proces nemožno „naslepo vložiť“ do viacvláknového kódu.

7. Vzdajte sa skriptovania v prospech „démonov“. Démon je proces, ktorý sa spustí raz a potom neustále „visí“ v pamäti. Keďže beží neustále, nemusí tráviť čas opätovnou inicializáciou pri každej požiadavke. Pri pohľade do budúcnosti poviem, že démon PHP (pri použití moderných verzií PHP) nemá žiadne zásadné rozdiely od bežného skriptu PHP.

Dizajnový prístup SOA

SOA - Service Oriented Architecture - nie je nová. Tento modulárny prístup k vývoju softvéru bol iniciovaný spoločnosťou IBM v minulom storočí av súčasnosti je podporovaný a propagovaný lídrami v tomto odvetví, najmä v produktoch na "podnikovej úrovni" v .NET a JAVA.

V klasickom prístupe k programovaniu webových služieb v PHP jazyky a podobne - dizajn vychádza z modelov, ich vlastností a operácií na nich. Modely predstavujú objekty reálneho sveta a operácie predstavujú akcie na objektoch. Ako však ukazuje prax, skutočný svet je oveľa mnohostrannejší a komplexnejší a je oveľa efektívnejšie opísaný jazykom udalostí a reakcií na ne (podrobnejšie pozri príspevok #1593 s popisom a príkladmi).

Reálny svet sa skladá z udalostí, ktoré sa dejú súčasne (programovo - „paralelne“) a väčšinou bez našej účasti a na ktoré sa vyskytujú alebo nevyskytujú rôzne reakcie. Reakcie zase môžu generovať nasledujúce udalosti. SOA je ideálna pre „programovanie v reálnom svete“, pretože je najpohodlnejšie pracovať s udalosťami, vzťahmi medzi nimi a reakciami na ne. Navyše, pri správny prístup na organizáciu architektúry a udalosti a reakcie na ne sa budú vyskytovať paralelne, aj keď používate „jednovláknový“ programovací jazyk, akým je PHP.

Musíte navrhnúť produkt SOA na základe toho, aké udalosti sa vyskytujú vo vašej obchodnej logike, ako spolu súvisia alebo by mali na seba nadväzovať, aké reakcie by mali nastať v reakcii na určité udalosti a kto presne bude tieto alebo tie udalosti spracovávať. iné udalosti. Implementácia dátových modelov a akcie na nich ustupujú do pozadia (zapuzdrené v „službe“) a do popredia sa dostáva zoznam „služieb“ a plán interakcie medzi nimi (inter-service API).

Realizácia: prvá aproximácia

1. Frontend ako nezávislá aplikácia. Na implementáciu je vhodný akýkoľvek populárny rámec JavaScript-MVC. Z praxe však podotýkam, ak vás začne bolieť, keď spojíte slová “JavaScript, MVC a framework” do jednej vety, bude to pre vás ťažké. Aplikácia musí byť schopná kresliť všetky svoje „obrazovky“ bez odkazu na backend, poskytnúť používateľovi navigáciu (prechody medzi „obrazovkami“) aj bez odkazu na backend a podporovať obojsmerný komunikačný kanál s backendom.

2. Vstupný bod pre pripojenie WebSocket k backendu. V NodeJS existuje množstvo hotových riešení, ktoré podporujú aj záložné požiadavky na long-polling a ajax for ideologicky zastarané prehliadačov. Do budúcnosti podotýkam, že k tomuto uzlu je možné pristupovať aj na čistom HTTP, ak potrebujete napísať nejaké brány so službami iných ľudí, ale pre zjednodušenie môžete napísať samostatný uzol „čistý HTTP“.

Vstupný bod bude poskytovať obojsmerný komunikačný kanál s front-end aplikáciou (inými slovami s prehliadačom), pričom bude od nej prijímať požiadavky a vracať jej odpovede.

3. Ukladanie spustených požiadaviek v systéme. Na tento účel sa najlepšie hodí populárny server AMQP, ktorý poskytuje fronty správ a smerovanie medzi nimi. Hneď ako príde ďalšia požiadavka od klienta, zaraďte ju do „prichádzajúcej“ fronty. Ďalej bude z tohto frontu extrahovaný démonom, ktorý analyzuje obsah požiadavky a odošle ju do „smerovania“ v celom systéme (čo v skutočnosti znamená preniesť ju do jedného alebo viacerých frontov podľa určitých algoritmov). Každý démon, ktorý sa zaoberá svojou vlastnou časťou obchodnej logiky, dostane tú alebo tú správu zo „svojho“ prichádzajúceho frontu, spracuje ju a umiestni odpoveď do „odchádzajúceho“ frontu.

Podotýkam, že v terminológii populárneho brokera RabbitMQ neexistuje pojem odchádzajúce fronty. Správy sa zverejňujú v burze (výmenníku), odkiaľ sa samotný broker presúva do konkrétnych frontov podľa smerovacích pravidiel. Tu je to tak napísané pre podmienené pochopenie, že odpoveď sa neposiela priamo žiadateľovi.

4. Ovládanie démonov(vedúci). Ak chcete spustiť jednoduchý skript PHP ako démona, stačí zabaliť spustiteľný kód do while(true) (...) a zadať príkazový riadok niečo ako „php your-script.php“. Je však lepšie použiť na to akéhokoľvek vhodného supervízora, ktorý bude v podstate robiť to isté, ale aj zabezpečiť potrebný stav prostredia, monitorovať stav procesu a robiť nejaké užitočnejšie veci.

V reálnom živote je PHP démon trochu komplikovanejší: musí prijímať riadiace signály a rekonfiguračné správy, nesmie prepúšťať pamäť, musí udržiavať (alebo obnovovať prerušené) spojenia s databázou – ale vo všeobecnosti to nie je o nič zložitejšie ako PHP skripty, na ktoré ste zvyknutí.

O krok bližšie k realite: udalosťami riadený prístup v SOA

Niektoré (podľa názoru autora zastarané) prístupy k budovaniu modulárnych aplikácií sú založené na princípe RPC (Remote Procedure Calling), ktorý implikuje priame volanie konkrétnych metód alebo procedúr vo vzdialenom komponente projektu. Tento prístup úplne ničí všetky výhody SOA, pretože zvyčajne znamená priame a tvrdé spojenie medzi odosielajúcimi a vykonávajúcimi uzlami. Pri návrhu a implementácii komplexného produktu by sa mal v maximálnej možnej miere dodržať princíp voľne spájaných komponentov, keďže práve zložitosť architektúry a kódu v konečnom dôsledku určí náklady na vlastníctvo (opravy a zmeny produktu po jeho spustení).

Udalosťami riadený prístup v SOA predpokladá, že komponenty (služby) medzi sebou komunikujú posielaním asynchrónnych udalostí („udalosti“, od slova Event). Udalosť je správa (napríklad v terminológii AMQP), ktorá má názov (názov) a sadu parametrov. Udalosť má systému povedať, že sa niečo stalo, alebo „položiť otázku“ systému. Vo všeobecnosti sa udalosti posielajú „do systému“ (presnejšie na spoločnú zbernicu ESB) bez adresy – teda bez konkrétnych zámerov na doručenie konkrétnym uzlom alebo interpretom.

Naopak, konkrétne uzly (komponenty, služby) počúvajú spoločnú zbernicu na určité udalosti, na ktoré sú pripravené reagovať. To môže znamenať, že služba je pripravená vypočuť si nejakú udalosť a vykonať príslušnú akciu. Alebo má služba určité znalosti (napríklad vlastní databázu s informáciami o používateľoch) a je pripravená ich poskytnúť ako odpoveď na „požiadavku“. V oboch prípadoch je výsledkom reakcie na udalosť vygenerovanie novej udalosti (s iným názvom a inými parametrami), ktorú si môžu vypočuť aj iné zainteresované služby.

Pri správnej organizácii generála pneumatiky ESB, služby odosielajú a prijímajú udalosti asynchrónne bez toho, aby na seba čakali. To znamená, že odosielajúca služba môže bez časového oneskorenia odoslať ľubovoľný počet udalostí do ESB a prejsť k riešeniu nasledujúcich úloh. Porovnajte si to s klasickým HTTP, čo znamená čakanie na odpoveď v aktuálnom cykle spracovania a uvidíte výhody. A aj prijímacie služby budú prijímať nové udalosti asynchrónne, nezávisle od seba, ihneď po dokončení spracovania predchádzajúcej udalosti.

Model udalostí SOA v kóde

Stručne povedané, musíte sa na svoj kód pozerať nie ako na triedy s funkciami (metódami), ale ako na udalosti a akcie, ktoré sa vyskytujú v reakcii na tieto udalosti. Okrem toho sú výsledkom akcií aj udalosti. Vo vzťahu k diskutovanej architektúre môžeme povedať, že lokálne udalosti sú udalosti, ktoré sa vyskytli v konkrétnom PHP skripte, a vzdialené udalosti sú udalosti, ktoré prišli do tohto skriptu z frontu AMQP (alebo sa tam v dôsledku toho odosielajú). Ak budete takto zaobchádzať so všetkým kódom, okamžite to povedie k prekvapivému a veľmi dôležitému efektu:

Ak sú miestne a vzdialené udalosti rovnaké, potom sú miestne a vzdialené obslužné nástroje rovnaké!

Prečo je to také dôležité? Pretože programátori vášho tímu pokračujú v písaní bežného PHP kódu bez toho, aby premýšľali o tom, kde bude tá alebo oná udalosť spracovaná - priamo tam v tomto alebo susednom PHP skripte, alebo niekde na druhom konci systému, v inom démonovi, na adrese aspoň v inom programovacom jazyku. Ak robíte projekt s verejným API, potom každý účastník tretej strany bude môcť „podpísať“ svoj kód do vašich udalostí (a spracovať ich), alebo naopak – poslať vám svoj vlastný, aby ste jeho udalosti spracovali ako žiadosti (a dostanete za to zaplatené, ak používate obchodný model SAAS s platbou za použitie, ako je Amazon).

Pamätajte, čo sme nazvali hlavnou nevýhodou klasických veľkých webových projektov - neustále rastie zložitosť, a teda náklady na vlastníctvo, náklady na podporu a zmeny. V prípade architektúry SOA riadenej udalosťami − zložitosť neustále klesá, pretože „zložité uzly“ možno ľahko rozdeliť na nezávislé služby (v tomto prípade démonov), pričom princípy systému zostávajú nezmenené a jeho výkon sa len zvyšuje.

Nasaďte novú verziu bez straty súčasných procesov

Keďže už nemáte monolitický systém, nemusíte nasadzovať celý systém. Navyše, nasadenie komponentu (služby, démona) môže trvať kedykoľvek, samozrejme v rozumných medziach. Dôležité je, že počas doby nasadenia (tých pár sekúnd či niekoľkých desiatok sekúnd) komponentu celý projekt ani na chvíľu nepreruší službu. Ako sa to robí?

Jednoducho vypnete službu, ktorú je potrebné aktualizovať. Aktualizujte jeho kód a štruktúru databázy (ak je to potrebné), potom ho znova spustite. Všetky aktuálne požiadavky na túto službu budú čakať vo fronte AMQP, kým služba nepríde. Podotýkam, že keďže služby sú malé (malé množstvo kódu potrebného na vyriešenie len malej časti obchodnej logiky) – je to oveľa rýchlejšie ako nasadenie celej monolitickej aplikácie. Ale v každom prípade nedôjde k žiadnym stratám.

Problémy s webovým rozhraním

Rýchle a responzívne webové rozhranie je predpokladom pre vysoko zaťažený projekt. Pozrime sa, prečo sa webové rozhranie môže vo všeobecnosti „spomaliť“ pri klasickom prístupe k implementácii:

1. Rozhranie je nakreslené na backende, ktorý je preťažený a robí to pomaly. Prechod medzi stránkami je pomalý. Aj pri AJAX sa bloky prekresľujú príliš pomaly.

2. Zdrojový kód rozhrania (HTML, CSS, JS) je nadbytočný a pomaly sa prenáša cez komunikačné kanály, najmä ak sa to robí pri načítavaní každej stránky počas navigácie používateľa cez rozhranie.

3. Rozhranie obsahuje veľké množstvo neoptimalizovanej logiky JavaScriptu, ktorá je pomalá na slabých zariadeniach (predovšetkým na mobilných zariadeniach).

Pokúsme sa vyriešiť tieto problémy:

Ako vytvoriť rýchle a responzívne webové rozhranie

1. Po prvé, a to najdôležitejšie, zdroj rozhranie by malo odovzdané klientovi nie viac ako raz. Jediným civilizovaným spôsobom, ako to dosiahnuť, je vytvoriť plnohodnotnú JavaScriptovú aplikáciu. Stiahne sa do klienta raz (v tomto prípade môžete zobraziť krásny animovaný preloader) a potom po celú dobu práce so službou už klient nebude musieť čakať na stiahnutie.

2. Je potrebné vykonať všetky prechody medzi „obrazovkami“ webového rozhrania vnútri aplikácie JavaScript a v žiadnom prípade ako samostatné požiadavky na backend. Existuje pre to výraz „jednostránková webová aplikácia“, v ktorej sa navigácia v podstate vykonáva prepínaním „obrazoviek“, pričom obsah adresný riadok sa dynamicky mení a vytvára dojem klasických „prechodov stránok“.

3. Odosielanie správ (udalostí) do backendu a prijímanie odpovedí musí byť oddelené od seba a od navigácie používateľa(asynchrónne). Spomínaný WebSocket vo svojej podstate „odporúča“ práve takúto implementáciu. Všetky zdĺhavé operácie by tiež nemali blokovať rozhranie, pokiaľ to nie je výslovne určené.

Používateľ tak potrebuje na prvotné stiahnutie aplikácie iba internetové pripojenie (niekoľko sekúnd). Ďalej dokáže so službou spolupracovať aj pri dočasnom výpadku spojenia (napríklad z mobilného zariadenia v metre, mimo mesta, v preplnenom hoteli v zahraničí a pod.) - aplikácia bude zaznamenávať požiadavky a skúšať poslať ich hneď, ako sa objaví internet, a teda rovnakým spôsobom dostanete odpovede.

To samozrejme neoslobodzuje vývojára od potreby optimalizovať a minimalizovať kód. Ako však ukazuje prax (napríklad služba Trello), táto úloha nie je ťažšia ako ostatné.

Poznámka pre pochybujúcich vývojárov webových služieb pre mobilné zariadenia: podľa praxe autora v roku 2013 jednostránkové JavaScript aplikácie na websocket transporte úspešne fungujú na iPade.

Používateľ pracuje z viacerých zariadení

Z práce využíva vašu službu z práce stolný počítač, cestou domov vytiahne iPhone, a doma zapne tablet. Ak používateľ odoslal službe nejaký príkaz z rozhrania, čaká na odpoveď o výsledkoch spracovania. Je ľahké pochopiť, že ak (keď) spracovanie trvalo nejaký hmatateľný čas, odpoveď by sa mala odoslať do zariadenia, ktoré používateľ momentálne používa (prepáčte za slovnú hračku). doručenie odpovede, nie v čase žiadosti.

Problém je v tom, že sa nedá jednoznačne povedať, či používateľ prestal používať (ešte raz prepáčte) to či ono konkrétne zariadenie. Možno zatvoril prehliadač. Možno má vybitú batériu. Možno odišiel do tunela metra, kde nie je spojenie a o pol minúty sa opäť objaví. Možností je veľa a autor nie je známy Najlepšia cesta definície. Tu je však to, čo by sa vám mohlo hodiť:

1. Zaznamenajte (na backende) všetky zariadenia používateľa a čas poslednej aktivity z každého z nich.

2. Klasifikujte systémové udalosti, ktoré je potrebné hlásiť používateľovi, na tie, ktoré je potrebné doručiť iba do aktívnych zariadení, a na tie, ktoré je potrebné doručiť „vysielať“ (na všetky zariadenia).

3. Zadajte extra vrstva abstrakcie – služba, ktorá zachytí určité udalosti, ktoré sú pre používateľa zaujímavé a vytvorí z nich správy. Takto môžete jednoducho vysielať rovnakú správu o úspechu operácie - v niekoľkých typoch: krátke upozornenie v mobilné zariadenie, trochu autentickejšie - do prehliadača, podrobná správa - od e-mail.

4. Poskytnite fronty na odosielanie každému používateľovi na každom samostatnom komunikačnom kanáli (webové rozhranie, mobilné zariadenie, pošta). Štandardná funkcionalita AMQP vám pomôže aj s časovými limitmi vypršania správ, aby tam neležali dlhšie ako určitý čas a nezanášali systém. Keď používateľ príde online cez konkrétny kanál, budú mu doručené čerstvé, čakajúce správy tohto konkrétneho typu.

Autor môže dodať, že na základe toho istého systému je možné vybudovať oneskorené zasielanie notifikácií (ktoré budú odoslané najskôr v určitý dátum), a dokonca aj zasielanie skutočnej papierovej periodickej korešpondencie (úkony, platby atď.). ), ale toto je téma na samostatný článok.

Zdôrazním hlavnú vec: nepovažujte doručené správy za nejaké upozornenia, na ktoré ste zvyknutí na Facebooku alebo Vkontakte. Doručené správy sú výsledky dotazu užívateľ! Všetky akcie používateľa v rozhraní, ktoré znamenajú určité požiadavky na backend, dostávajú odpovede v jednotnej forme „doručených správ“ prostredníctvom jediného jednotného komunikačného kanála. A potom algoritmus webovej aplikácie pochopí, čo je potrebné urobiť s touto alebo tou správou - nakresliť upozornenie s textom, pridať riadok do tabuľky, prepnúť niečo v rozhraní atď.

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

Bolo by zbytočné navrhovať rýchle frontendové webové rozhranie, ak máte pomalý backend. Nie, toto nie je o streamoch, ani o vidličkách a nie o Erlangovi. Zostávame pri bežnom PHP, dostupnom pre každého začiatočníka/stredne pokročilého programátora.

Prečo vôbec potrebujeme paralelizmus? Aj keď nehovoríme o nedostatkoch jednovláknových jazykov vo všeobecnosti, paralelizmus výrazne urýchľuje výpočet úlohy, čo znamená, že výrazne znižuje nároky na hardvérové ​​zdroje (hardvér) a zvyšuje spokojnosť používateľov z práce v rozhranie (získajú výsledky rýchlejšie).

Vezmite akýkoľvek pomerne zložitý obchodný proces vo svojom webovom projekte a nakreslite ho ako reťazec krokov. Dostanete postupnosť akcií v systéme od požiadavky po odpoveď. S najväčšou pravdepodobnosťou najskôr prebehnú nejaké kontroly, potom vykonanie hlavnej úlohy, potom vedľajších podúloh a nakoniec výstup výsledku. Pozrite sa pozorne: dá sa niektorá z akcií vykonávať paralelne?

Uvediem príklad: povedzme, že používateľ si chce kúpiť nejakú službu, ktorá je zahrnutá ako dodatočná platená možnosť v jeho tarifnom pláne. Počet možností je obmedzený. Ak je možnosť úspešne zapnutá, musíte používateľovi poslať upozornenie v prehliadači, poslať duplicitný e-mail, odpočítať peniaze z jeho fakturačného účtu a upozorniť klientske oddelenie. Nakreslite reťaz:

1. Systém dostal požiadavku na povolenie voľby.
2. Autorizujeme užívateľa a zisťujeme jeho tarifný plán.
3. Skontrolujeme, či je možné túto možnosť vôbec povoliť tarifný plán užívateľ.
4. Skontrolujte, či má používateľ na účte dostatok peňazí.
5. Skontrolujte, či táto možnosť nie je v konflikte s inými nastaveniami.
6. Ak je všetko v poriadku, povoľte možnosť.
7. Do prehliadača pošleme upozornenie.
8. Upozornenie posielame poštou.
9. Odpisujte peniaze vo vyúčtovaní.
10. Upovedomíme klientske oddelenie.

Pozorný čitateľ možno nájde chybu v slede akcií, ale autor vám pripomenie, že ide o približný príklad.

čo vidíme? Upozorňujeme, že nie je dôvod vykonávať všetky kroky postupne. Oveľa správnejšie by bolo „paralelizovať“ 3,4,5 do troch vlákien a na konci - 7,8,9,10 do štyroch vlákien.

Premýšľate o tokoch a rozvetveniach? Márne, máte SOA!

Ako robiť paralelné výpočty v SOA

Čitateľom, ktorí si práve prelistovali článok až sem, vysvetlím, že nejde o paralelizáciu rovnakej úlohy v SOA – na to vo všeobecnosti stačí spustiť démona v N inštanciách a postarať sa o spor o prístup k databáze.

Takže v tomto príklade máme tri-štyri-niekoľko rôznych úloh, ktoré vykonávajú rôzne služby a ktoré chceme vykonávať paralelne. Odoslanie na paralelné spracovanie nie je zložité: stačí poslať jednu udalosť „môže používateľ s užívateľským menom povoliť možnosť X?“ a všetky služby prihlásené na túto udalosť ju zachytia, vykonajú kontroly a odošle výsledné udalosti.

Problém je práve zhromaždiť tieto výsledné udalosti, keď potrebujeme celkový výsledok ich práce, aby sme sa pohli ďalej. Napríklad v zozname vyššie potrebujeme výsledok 3+4+5 a 7+8+9+10 možno ignorovať.

V skutočnosti, s vysokými požiadavkami na povinné dokončenie transakcií, musíte kontrolovať každý reťazec až do konca, ale o tom budeme diskutovať neskôr.

Prirodzene, ak náš démon bude „visieť a čakať“, spotrebováva zdroje (takzvané „nečinné“), potom nemôžete vytvoriť žiadnu takú vysoko zaťaženú službu. Ide len o to, že démon rieši iné úlohy a obsluhuje iné požiadavky iných klientov, pričom tri samostatné „vlákna“ (3,4,5) riešia svoje podúlohy. Ťažkosti pridáva aj skutočnosť, že výsledné udalosti môžu prísť v ľubovoľnom poradí. To všetko je však vyriešené jednoducho a jednoducho:

Pokiaľ autor vie, žiadna z predpripravených implementácií AMQP, ktoré dnes existujú, neumožňuje očakávať a „zlepiť“ niekoľko udalostí do jednej, aby ste dostali iba to – jeden výsledok. Takže sa o to musíte postarať sami, takto:

1. Pred odoslaním udalosti do AMQP sa zaviažte rýchla pamäť(použite akékoľvek vhodné úložisko v pamäti) zoznam názvov výsledných udalostí, ktorých príjem služba očakáva, ako aj názov udalosti (nazvime to „R“), ktorú je potrebné odoslať so súčtom výsledky.

2. Potom služba ukončí cyklus spracovania aktuálnej udalosti a uvoľní sa pre ďalšie úlohy.

3. Akonáhle príde akákoľvek udalosť zo zoznamu, ktorý máme uložený v pamäti, služba ju „rozbalí“ a uloží jej obsah do pamäte, pričom ju priradí k názvu udalosti. Zároveň skontroluje, či sa v tomto zozname nenachádzajú ďalšie udalosti, na ktoré neprišla odpoveď. Ak je, slučka v tomto bode končí.

4. V opačnom prípade, to znamená, že ak všetky udalosti v zozname dostali odpoveď, služba ich zlepí a odošle zlepený výsledok pod názvom udalosti „R“, ktorú ste si predtým zapamätali. Potom, aby sa ušetrila pamäť, zoznam s výsledkami sa jednoducho vymaže z pamäte - už nie je potrebný.

5. Rovnaká služba alebo iná služba (podľa uváženia projektanta systému) prijme výslednú udalosť „R“ so všetkými výsledkami paralelného spracovania. To, čo nasleduje, je zrejmé.

Ak sa vám z popisu zdalo, že je to dlhá doba, vysvetlím - hovoríme o tisícoch a desiatkach tisíc udalostí za sekundu (!) Na jednom priemernom serveri.

Použitie úložiska v pamäti znamená, že aj keď sa služba zastaví (spadne, aktualizuje), aktuálny obchodný proces sa nestratí. Po opätovnom spustení bude služba naďalej prijímať udalosti z ESB a spracovávať ich podľa vyššie opísaného algoritmu.

Transakcia, vrátenie operácií (rollback) a scenáre zlyhania v SOA

Pretože v SOA, peer udalosti „prechádzajú“ cez ESB, potrebujete nejaký druh náznaku, že „táto odpoveď tu“ odkazuje na „tamto požiadavku“. Tu nie je potrebné znovu vymýšľať koleso - v špecifikáciách akéhokoľvek populárneho protokolu nájdete parameter s názvom ako id korelácie. Zvyčajne ide o reťazec. Musí byť obsiahnutý v parametroch všetkých udalostí každého jednotlivého obchodného procesu, od vstupu až po výstup, aby bolo možné identifikovať reťazec správ, ktorý patrí do tohto obchodného procesu. Pri pohľade zo strany webového rozhrania webová aplikácia ukladá aktuálne aktívne (odoslané) požiadavky a pomocou correlation_id „rozumie“, na akú požiadavku prišla každá konkrétna odpoveď.

Poďme sa zaoberať terminológiou: transakcia je vlastnosť systému vykonávať niekoľko akcií ako jednu spoločnú operáciu, ktorá má zmysel a môže byť dokončená iba úplne. Keďže v distribuovanom systéme s paralelnými vláknami je fyzicky nemožné vykonať niekoľko operácií atomicky, systém poskytuje takzvané scenáre zlyhania a návraty.

Scenár zlyhania je vo všeobecnosti akcia, ktorá sa má vykonať, keď sa vyskytne chyba. Vrátenie zmien je v tomto kontexte skript akcií, ktoré je potrebné vykonať, aby sa „vrátila“ séria predchádzajúcich akcií, ktoré nakoniec viedli k chybe. Zhruba povedané, vrátenia sú procesy, ktoré sú opakom bežných obchodných procesov v systéme.

Vrátenie zmien nie je vždy potrebné a nie vždy možné. Napríklad, ak ste pripojili nejakú možnosť k používateľovi a potom „spadli“ na fakturáciu, potom môžete túto možnosť vypnúť. Potom to môžete skúsiť znova, automaticky alebo pomocou druhého príkazu od používateľa. A ak ste fyzicky odstránili obsah a niektoré následné operácie nefungovali ... Situácia je nejednoznačná.

Preto treba k scenárom zlyhania a vráteniam pristupovať rozumne. Autor môže odporučiť nasledujúcu cestu: Vždy píšte neúspešné skripty, ale nepíšte vždy návraty. Vaše zlyhania sa okamžite premietnu do monitorovania - a tím podpory bude môcť rýchlo opraviť situáciu vlastnými rukami, získať skúsenosti a formulovať technické požiadavky na programátorov. Zatiaľ čo napísanie jedinečne správneho návratu od začiatku môže byť veľmi, veľmi ťažké.

Malo by sa však chápať, že vrátenia späť, vrátenia späť, riešenie chybných situácií sú rovnaké obchodné procesy ako všetko ostatné. Sú tiež založené na udalostiach prechádzajúcich systémom. Bude pekné, ak si na začiatku stanovíte dve protichodné cesty (vpred a vzad, úspech a neúspech) v každej udalosti a každom psovodovi, aby ste ich implementovali do špecifických úloh.

škálovanie SOA

Každý systém bude musieť byť skôr či neskôr rozšírený. V prípade SOA sa to robí jednoducho a prirodzene:

1. Duplicitný vstupný bod. Týka sa to rovnakej brány WebSocket, o ktorej sme uvažovali na začiatku článku. Môže byť duplikovaný neobmedzene veľakrát, keďže komunikácia medzi ním a klientom je zjednotená a oddelená od vnútorných častí systému a komunikácia medzi ním a systémom je zase oddelená od komunikácie s klientom.

2. Duplicitné inštancie(inštancie) služieb. Služby, ktoré nevyžadujú databázu alebo z nej iba „čítajú“, sú bez problémov duplikované. A bežná funkčnosť RabbitMQ vám umožní prihlásiť sa na odber N inštancií do rovnakého frontu, správy z ktorých budú náhodne prichádzať do jednej alebo druhej inštancie. Pri duplikovaní služieb, ktoré sa zaoberajú externými aplikáciami (databázy, softvér tretích strán), musíte zvážiť, ako tieto aplikácie poskytujú transakčné požiadavky od niekoľkých paralelných klientov.

3. Duplikácia dátových úložísk. Tu môžete voľne použiť akýkoľvek sharding, ktorý poznáte. Ak máte čo do činenia s 10 miliónmi používateľov a zdá sa vám to veľa, vydeľte ich 10 miliónmi báz (napríklad na základe CRC32 z prihlásenia používateľa alebo inou cyklickou metódou). Ak sa databáza jednej služby neustále rozrastá a stáva sa komplexnejšou, rozdeľte ju na dve služby.

4. Duplikovanie AMQP makléra a úložisko v pamäti. Z autorovej praxe dokonale plnia svoju úlohu RabbitMQ a Redis. Ak máte zariadenie vo viac ako jednom stojane s jednosmerným prúdom, vyberte režim králika, ktorý je odolný voči zlyhaniam sieťového pripojenia.

5. Úplná strojová duplikácia. OD moderné technológie virtualizácie (KVM) a konfigurácie (Chef), úloha „vytvoriť ten istý stroj“ spočíva v stlačení jedného tlačidla.

Šifrovanie prenosu medzi frontendom a backendom

Odporúča sa zorganizovať pripojenie WebSocket cez SSL. Okrem toho zvyšuje „penetráciu“ proti zaostalým poskytovateľom kancelárskych služieb, ktorí blokujú „akúkoľvek podivnú prevádzku“ okrem HTTP[S].

Ak sa vám to však zdá nedostatočné, môžete si pri každom prihlásení klienta dohodnúť generovanie párov kľúčov (jeden pár na frontende, druhý na backende), vymieňať si verejné kľúče a ďalej šifrovať všetku komunikáciu pomocou bežného RSA.

Ochrana pred DDOS a podobným zneužitím

Autor zámerne vynecháva otázku „nízkoúrovňovej“ ochrany pri zaplavení SYN a zaplavení kanálov stovkami gigabitov, keďže o tom boli napísané stovky kníh odbornej literatúry. Poďme sa porozprávať o tom, ako ochrániť systém už vo vnútri, na jeho logických úrovniach, keď útočník našiel spôsob, ako „zaplaviť“ váš systém (SOA + ESB) tisíckami udalostí.

1. Prvé pravidlo: pokiaľ nie je potvrdená platnosť, nič by sa nemalo spracovávať. Ak očakávate ako vstup malý text v JSON zabalený v BASE64, potom by mal byť prichádzajúci reťazec dlhší ako megabajt vyslovene vyradený – nepokúšajte sa ho rozbaliť. Reťazec obsahujúci znaky „iné ako latinka“ je podobný. Keď rozbalíte reťazec, nepokúšajte sa okamžite vykonať json_decode, najskôr skontrolujte počet a paritu zátvoriek. A tak ďalej.

Vyzerá to ako paranoja, ale inak sa môžete ľahko „zaplniť z pamäte“, to znamená, že to vedie k zlyhaniu služby, čo ju prinúti zabrať všetku dostupnú RAM.

2. Služba, ktorá spracováva prichádzajúce správy, by nemala nič zapisovať do pamäte, do databázy a iných úložísk. Dôvod je rovnaký. Najprv sa uistite, že správa ako celok je platná a až potom ju pustite „hlbšie“ do systému.

3. Služba, ktorá môže byť nútená „prejsť do databázy“, musí byť často chránená pomocou vyrovnávacej pamäte. Jednoduchým príkladom je služba autorizácie používateľov. Ak nie je chránený, útočník môže za sebou odoslať tisíce žiadostí o autorizáciu, čím preťaží databázu.

4. Na vstupe do systému potrebujete službu, ktorá odmieta požiadavky z „podozrivých“ zdrojov, napríklad z IP adries z „čiernej listiny“.

Znie to ako klasická rada, tak o čo ide? Hlavným problémom je, že ak na vstup do systému umiestnime službu analyzátora-filtra (ako sa to robí v klasických webových projektoch), tak výkon celého systému nebude vyšší ako výkon tohto analyzátora-filtra. Je mimoriadne nákladné kontrolovať každé hlásenie na podozrenie „v reálnom čase“. Môžete a mali by ste to urobiť dodatočne a takto:

1. Vytvorte službu, ktorá bude „počúvať“ všetky správy v systéme. V RabbitMQ sa to dosiahne prihlásením sa k smerovaciemu kľúču "#".

2. Naučte túto službu určitým pravidlám, podľa ktorých dokáže diagnostikovať „podozrivých“ odosielateľov. Ide napríklad o odosielateľov, ktorí posielajú príliš veľa podobných správ v časovom intervale, prípadne posielajú opakované správy, prípadne posielajú správy v mene toho istého používateľa z rôznych IP adries... Možností je veľa, zapnite si predstavivosť. Zároveň nezáleží na tom, ako rýchlo takáto služba funguje (samozrejme v rozumných medziach) – nemá to vplyv na rýchlosť celého systému.

3. Akonáhle služba dospeje k záveru, že ten a ten odosielateľ je podozrivý, odošle túto udalosť do systému a ďalej si robí po svojom.

4. Dajte na vstup veľmi jednoduchého a rýchleho démona – filtrovaciu službu, ktorej úlohou bude jednoducho „hlúpo“ blokovať podozrivých odosielateľov. Žiadna analýza, žiadna analýza, žiadne dodatočné náklady. Je ľahké uhádnuť, kto je považovaný za podozrivého: služba sa o nich dozvie z udalostí opísaných v predchádzajúcom odseku a pridá ich na svoju internú čiernu listinu.

Koniec prvej časti. Pokračovanie: SOA: distribuovaná architektúra a jej údržba.

Som mentor v IT projektoch. To znamená, že ak ste vlastník alebo vodca, môžem vám pomôcť dosiahnuť nové výšky. Vyčistiť procesy, pochopiť motiváciu tímu, implementovať nástroje a dosiahnuť konkrétne ciele. Neučím podnikať, ale iba pomáham obísť štedro rozhádzané hrable na vašej ceste. .