Az anyagot elsősorban kezdő webprogramozóknak szánjuk.

Bevezetés.

Gyakran fordulnak hozzám olyan ügyfelek, akiknek saját maguk által írt CMS-eket vagy modulokat telepítettek kezdő webprogramozók, akik nem értik, mi kell az adatok védelméhez, és gyakran másolják a szűrési funkciókat anélkül, hogy átgondolnák, hogyan működnek, és pontosan mit kell velük csinálni.

Itt megpróbálom a lehető legrészletesebben leírni. gyakori hibák az adatok beszűrésekor PHP szkriptés adja egyszerű tippeket hogyan kell megfelelően szűrni az adatokat.

A neten rengeteg cikk található az adatok szűréséről, de ezek, ahogy kell, nem teljesek és részletes példák nélkül.

Kikérdezés.

Szűrés. Hiba #1
A numerikus változók esetében a következő ellenőrzést kell használni:
$szám = $_GET["bemeneti_szám"]; if (intval($szám)) ( ... SQL lekérdezés végrehajtása... )
Miért vezet ahhoz SQL injekció? A lényeg az, hogy a felhasználó megadhat egy változót bemeneti_szám jelentése:
1"+UNION+SELECT
Ilyen esetekben az ellenőrzés sikeresen megy, mert az intval függvény a változó egész értékét kapja, azaz. 1, hanem magában a változóban $szám semmi sem változott, szóval rosszindulatú kódátadásra kerül az SQL lekérdezésnek.
Helyes szűrés:
$szám = intval($_GET["bemeneti_szám"]); if ($szám) ( ... SQL lekérdezés végrehajtása... )
Természetesen a feltétel változhat, például ha csak egy bizonyos tartományt kell megadnia:
if ($szám >= 32 ÉS $szám<= 65)

Ha jelölőnégyzeteket vagy többszörös kijelöléseket használ számértékekkel, ellenőrizze a következőket:
$checkbox_arr = array_map("intval", $_POST["checkbox"]);
array_map
Szűréssel is találkozom a következő formában:
$szám = htmlspecialchars(intval($_GET["bemeneti_szám"]));
htmlspecialchars
Vagy:
$szám = mysql_escape_string(intval($_GET["bemeneti_szám"]));
mysql_escape_string

Csak egy mosoly okozhatja :)

Szűrés. 2. hiba.
A karakterlánc-változók esetében a következő szűrést alkalmazzuk:
$bemeneti_szöveg = addslashes($_GET["bemeneti_szöveg"]);
Az addslashes függvény elkerüli a specifikációt. karaktereket, de nem veszi figyelembe az adatbázis kódolását, és lehetséges a szűrés megkerülése. Nem másolom le annak a szerzőnek a szövegét, aki leírta ezt a sebezhetőséget, és egyszerűen adok egy linket Chris Shifletthez (a fordítást a Runetben keresheti).

Használja a mysql_escape_string vagy mysql_real_escape_string függvényt, például:
$bemeneti_szöveg = mysql_escape_string($_GET["bemeneti_szöveg"]);
Ha nem szándékozik belépni html címkék, akkor a legjobb a következő szűrést végrehajtani:
$bemeneti_szöveg = strip_tags($_GET["bemeneti_szöveg"]); $bemeneti_szöveg = htmlspeciális karakterek($bemeneti_szöveg); $bemeneti_szöveg = mysql_escape_string($bemeneti_szöveg);
strip_tags - HTML címkék lehúzása.
htmlspecialchars – speciálisat alakít át. karakterek a html entitásban.
Így védheti meg magát az XSS-támadásoktól, az SQL injekció mellett.
Ha szüksége van html címkékre, de csak a forráskód megjelenítésére, akkor elég a következőt használni:
$bemeneti_szöveg = htmlspecialchars($_GET["bemeneti_szöveg"]); $bemeneti_szöveg = mysql_escape_string($bemeneti_szöveg);

Ha Önnek fontos, hogy a változó értéke ne legyen üres, akkor használja a trim függvényt, például:
$bemeneti_szöveg = trim($_GET["bemeneti_szöveg"]); $bemeneti_szöveg = htmlspeciális karakterek($bemeneti_szöveg); $bemeneti_szöveg = mysql_escape_string($bemeneti_szöveg);

Szűrés. 3. hiba.
Az adatbázisban való keresésről van szó.
Számok szerinti kereséshez használja az első hibában leírt szűrést.
Szöveg szerinti kereséshez használja a második hibában leírt szűrést, de fenntartásokkal.
Annak érdekében, hogy a felhasználó ne hajtson végre logikai hibát, el kell távolítania vagy ki kell lépnie a speciális. SQL karakterek.
Példa hozzáadás nélkül. soros feldolgozás:
$bemeneti_szöveg = htmlspecialchars($_GET["bemeneti_szöveg"]); // Keresés: "%" $input_text = mysql_escape_string($input_text);
Ennek eredményeként egy ilyen lekérdezést kapunk:
... WHERE text_row LIKE "%".$input_text."%" ... // WHERE text_row LIKE "%%%"
Ez jelentősen megnöveli az alap terhelését.
A szkriptemben egy olyan függvényt használok, amely eltávolítja a nem kívánt karaktereket a keresésből:
függvény strip_data($text) ( $quotes = tömb ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!"); $goodquotes = tömb ("-", "+", "#"); $repquotes = tömb ("\-", "\+", "\#"); $szöveg = trim(csík_címkék($szöveg)); $szöveg = str_csere($idézőjelek, "", $szöveg); $szöveg = str_csere($jó idézetek, $repquotes, $szöveg); $szöveg = ereg_replace(" +" , " ", $szöveg); vissza $szöveg; )
Természetesen a fenti szimbólumok közül nem mindegyik veszélyes, de az én esetemben nincs rájuk szükség, ezért keresést és cserét hajtok végre.
Példa a szűrés használatára:
$bemeneti_szöveg = strip_data($_GET["bemeneti_szöveg"]); $bemeneti_szöveg = htmlspeciális karakterek($bemeneti_szöveg); $bemeneti_szöveg = mysql_escape_string($bemeneti_szöveg);
Azt is tanácsolom, hogy korlátozza a karakterek számát a keresésben, legalább 3-nál, mert. ha sok rekord van az adatbázisban, akkor 1-2 karakter keresése jelentősen megnöveli az adatbázis terhelését.
Szűrés. Hiba #4.
A változó értékek nem szűrhetők $_COOKIE. Vannak, akik úgy gondolják, hogy mivel ezt a változót nem lehet átadni az űrlapon, ez egy biztonsági garancia.
Ezt a változót bármely böngésző nagyon könnyen meghamisíthatja a webhely cookie-jainak szerkesztésével.
Például az egyik jól ismert CMS-ben ellenőrizték a használt webhelysablont:
if (@is_dir (MAIN_DIR . "/template/" . $_COOKIE["bőr"]))( $config["bőr"] = $_COOKIE["bőr"]; ) $tpl->dir = FŐ_DIR . "/sablon/" . $config["bőr"];
Ebben az esetben megváltoztathatja a változó értékét $_COOKIE["bőr"]és hibát jelez, aminek eredményeként látni fogja a webhelymappa abszolút elérési útját.
Ha a cookie-k értékét használja az adatbázisba mentéshez, akkor használja a fent leírt szűrések egyikét, ugyanez vonatkozik a változóra $_SERVER.
Szűrés. Hiba #5.
irányelv tartalmazza register_globals. Feltétlenül kapcsold ki, ha be van kapcsolva.
Bizonyos helyzetekben lehetőség van egy olyan változó értékének átadására, amelyet nem kellett volna átadni, például ha az oldalon vannak csoportok, akkor a 2. csoportnál a $group változó legyen üres vagy egyenlő 0-val, de ez elég az űrlap meghamisításához a kód hozzáadásával:

Változó PHP szkriptben $csoport 5 lesz, ha nem volt deklarálva alapértelmezett értékkel a szkriptben.
Szűrés. Hiba #6.
Ellenőrizze a letöltött fájlokat.
Ellenőrizze a következőket:
  1. Fájlkiterjesztés. A kiterjesztésű fájlok betöltését célszerű letiltani: php, php3, php4, php5 stb.
  2. Fel van töltve a fájl a kiszolgálóra move_uploaded_file
  3. fájl méret
Vizsgálat. Hiba #1.
Találkoztam olyan esetekkel, amikor egy AJAX kéréshez (például: hírnév növelése) egy felhasználónevet vagy azonosítót adtak át (kinek a hírnevet növelik), de maga a PHP nem ellenőrizte, hogy van-e ilyen felhasználó.
Például:
$felhasználói_azonosító = intval($_KÉRÉS["felhasználói_azonosító"]); ... INSERT INTO REPLOG SET uid = "($user_id)", plus = "1" ... ... UPDATE Users SET reputation = hírnév+1 WHERE user_id = "($user_id)" ...
Kiderült, hogy létrehozunk egy rekordot az adatbázisban, ami számunkra teljesen haszontalan.
Vizsgálat. 2. hiba.
Az adatokkal végzett különféle műveletek (hozzáadás, szerkesztés, törlés) során ne felejtse el ellenőrizni a felhasználó jogosultságait a funkció eléréséhez és további jellemzők (html használat címkék vagy az anyag ellenőrzés nélküli közzétételének lehetősége).

Sokáig javítottam egy hasonló hibát egy fórum modulban, amikor bármelyik felhasználó szerkesztheti az adminisztrációs üzenetet.

Vizsgálat. 3. hiba.
Több használata esetén php fájlok végezzen egy egyszerű ellenőrzést.
Fájlban index.php(vagy bármely más fő fájlban) írja be ezt a sort, mielőtt más php fájlokat tartalmazna:
define("READFILE", igaz);
A többi php fájl elejére írja be:
if (! definiált ("READFILE")) ( exit ("Hiba, rossz a fájl.
Ugrás a főoldalra."); }
Ez korlátozza a fájlok elérését.
Vizsgálat. Hiba #4.
Használjon kivonatokat a felhasználók számára. Ez segít megakadályozni, hogy egy adott függvényt az XSS hívjon meg.
Példa hash összeállítására a felhasználók számára:
$titkos_kulcs = md5(strtolower("http://site.ru/" . $tag["név"] . sha1($jelszó) . dátum("Ymd"))); // A $titkos_kulcs a mi hashünk
Ezután minden fontos formában helyettesítse a bemenetet a felhasználó aktuális hash értékével:

A szkript végrehajtása során ellenőrizze:
if ($_POST["titkos_kulcs"] !== $titkos_kulcs) ( kilépés ("Hiba: titkos_kulcs!"); )
Vizsgálat. Hiba #5.
Az SQL-hibák kiadásakor korlátozza az információkhoz való hozzáférést. Például állítson be jelszót a következőhöz GET változó:
if ($_GET["passsql"] == "jelszó") ( ... SQL hibakimenet... ) else ( ... Csak hibainformáció, részletek nélkül... )
Ez elrejti a hacker információkat, amelyek segíthetnek neki a webhely feltörésében.
Vizsgálat. Hiba #5.
Próbáljon meg ne foglalni fájlokat azáltal, hogy kívülről szerzi be a fájlneveket.
Például:
if (isset($_GET["fájl_név"])) ( include $_GET["fájl_név"] ..php"; )
Használjon kapcsolót

Létrehozok egy egyszerű listát PHP-ben, ahol a felhasználó nevet, életkort, e-mail címeket stb. adhat hozzá. Hozzáadtam egy törlési lehetőséget is, de szeretnék egy megerősítő üzenetet hozzáadni, amikor a felhasználó a törlés gombra kattint.

Próbáltam guglizni, de csak jQuery és JavaScript megoldásokat találtam. Ezt csak PHP-vel lehet megtenni?

NévKor"; while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["név"].""; visszhang" ".$query2["életkor"].""; visszhang" Szerkesztés"; visszhang" x"; } ?>

Delete.php

ban ben

Ha csak PHP-ben szeretné megtenni, akkor "lépéseket" kell hozzáadnia a szkripthez, például:

1. lépés (űrlap megjelenítése) -> 2. lépés (ellenőrzés kérése) -> 3. lépés (ellenőrzés)

Ehhez munkameneteket használhat az űrlap tartalmának mentésére, és egy GET paramétert a lépés nyomon követésére. Egyébként a legtöbb egyszerű megoldás Javascriptet kell használni:

visszhang" x"; //használjon idézőjeleket a js-hez a php-n belül!

Ez az, amire szüksége van

While($query2=mysql_fetch_array($query1)) ( echo " ".$query2["név"].""; visszhang" ".$query2["életkor"].""; visszhang" Szerkesztés"; visszhang" x"; ) in while($query2=mysql_fetch_array($query1)) ( echo " ".$query2["név"].""; visszhang" ".$query2["életkor"].""; visszhang" Szerkesztés"; visszhang" x"; }

és hozzon létre egy javascript függvényt

Funkció megerősítéseDelete(anchor) ( var conf = megerősítés("Biztosan törli ezt a rekordot?"); if(conf) window.location=anchor.attr("href"); )

higgy nekem, ez munka 🙂

Adjon hozzá egy onClick eseményt a párbeszédpanel elindításához, és javascript:return confirm("Biztosan törölni akarja ezt?");

visszhang" x";

//add onclick esemény onclick="return deleteconfig()"

nekem működik, de változtass ezen:

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

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

Az alábbiakban a fentiek egy változata látható, amely megerősítő mezőt ad, és átadja a változót PHP-ről Javascript-re, majd vissza a PHP-re.
Ezzel a választógombbal választottam ki egy fájlt a fájllistából.
Lásd a php $fileName nevű OnClick trigger függvényt a Javascriptben, erősítse meg a fájlnévvel, és ha igen, adja meg a href-t a $_GET változóival

PHP/HTML kód:

$fileName $extn $ méret $modtime "; ?>

A cikk nem a fürtökről szól, nem a replikációval való felosztásról, és még csak nem is a felhőkről. A cikk egy rendkívül megbízható számítástechnikai architektúra felépítéséről szól, amelyben lavinaszerűen nőhet a felhasználók száma és kéréseik. Egy vállalkozás számára pedig kritikus, hogy egy webszolgáltatás minden kérést elfogadjon, helyesen és a végsőkig dolgozzon fel (egyes komponensek meghibásodásától és leállásától függetlenül), és garantáltan választ adjon az ügyfélnek. És természetesen a berendezés „helyköltsége” és a rendszergazdák fizetése nélkül.

Más szóval, először is gondoljon arra, hogy „szükségem van rá”. Ha valakinek van webáruháza, ahol beszélő hörcsögöket árulnak havi 100 rendelés forgalommal, akkor valószínűleg nem. Ha pedig olyan vállalkozást tervez, amely több százezer és millió felhasználó fogadására képes, nagy mennyiségű számítást igényel, nagy értékű adatokkal dolgozik, garantálja minden üzleti folyamat tranzakcióképességét és párhuzamos adatfeldolgozást igényel, ez ez.

A pénzügyi szektor, nagy online áruházak több százezres egységek választékával, online aukciók, szálloda- és légitársaság foglalási rendszerek, új „felhő” vagy közösségi szolgáltatások, amelyek célja, hogy a hirdetés indulását követő napon milliós felhasználói bázist szerezzenek. kampánya potenciálisan érdeklődik egy rendkívül megbízható rendszer iránt az Ön webszolgáltatásaihoz.

Kinek szól ez az anyag

1. Nagy webprojektek fejlesztői, akik nagy terhelésű és hibatűrő számítástechnikai szolgáltatások létrehozásában érdekeltek.

2. Új vagy bővülő vállalkozások tulajdonosai, akik a felhasználói bázis "robbanásszerű" növekedésére számítanak, és magas követelményeket támasztanak a számítástechnikai részleggel szemben.

3. Nagy webprojektek technikai vezetői, menedzserei, akik nincsenek megelégedve a jelenlegi állapottal, és alapvető átszervezésen gondolkodnak.

Miért olyan sok szó a „számításokról”?

Mivel a nagy webprojektek közvetlen jövője a „ nagy adat” („Big Data”) egy olyan trend, amelyet 2011-ben a virtualizáció, az energiatakarékosság és a monitorozás mellett az egyik legjobbnak tartottak, 2013 óta pedig szilárdan megállja a helyét az iparban, sőt az akadémikusok közé is bekerült. tantárgyak nagy külföldi egyetemeken.

Az üzleti problémák megoldásához feldolgozandó adatok mennyisége ma folyamatosan növekszik, és a jövőben ez a folyamat csak felgyorsul. Ha tíz évvel ezelőtt még elég volt egy „online kirakatot” megmutatni a felhasználónak egy termékkel, akkor egy éve elég volt elemezni a felhasználó útvonalát az oldalon, és megmutatni neki egy szigorúan releváns terméket (az ún. „viselkedési technológiákat” ), ma már az a norma, hogy mindent tudni kell a felhasználóról, beleértve a magasságot, súlyt, életkort és kedvenc kutyája nevét.

A természetes verseny törvényei azt diktálják, hogy ha több lehetőséget akarunk biztosítani az ügyfeleknek, mint a versenytársak, akkor több adatra és több számításra van szükség. És előbb-utóbb a projektje megfelelő megközelítések nélkül belefulladhat – ahogyan mostanság mindenhol megfulladnak a különböző projektek: valaki a támogatás összetettsége miatt, valaki egyszerűen rossz kód miatt, valaki a modulok magas összekapcsolhatósága miatt, valaki megbízhatatlan alkatrészek használata miatt.

Ezért mindenki, aki ma nagy ambíciókkal kezd bele egy webes projektbe, több előnyhöz jut a riválisokkal szemben, ha kezdetben nem csak programkódnak, hanem számítási környezetnek is tekinti projektjét – egy rendszernek, amelynek saját lét- és fejlődéstörvényei vannak. Minél jobban odafigyelsz számítástechnikai menedzsment az elején, annál valószínűbb, hogy a következő években megelőzi a versenytársakat.

E sorok írója meg van győződve arról, hogy a nagy terhelésű webszolgáltatások építésének „klasszikus” modern megközelítése számos komoly hátránnyal jár. Lássuk, miért. Először vegyünk egy tipikus modern sémát:

A klasszikus megközelítés egy nagy terhelésű webszolgáltatás felépítéséhez

1. Sok szerver szerepekre osztva.

2. A szerverek egy része (a Frontend szerepe) úgy van kialakítva, hogy statikus erőforrásokat (képek, CSS, JS-fájlok) adjon vissza, és a bejövő forgalom elejét „elosztja” a downstream csomópontokhoz. A fő szoftver általában az Nginx.

3. A downstream csomópontok (backend szerepkör) dinamikus számításokat végeznek. Egyszerűen fogalmazva, ez egy tipikus Apache + PHP csomag lehet.

4. A szerverek másik csoportja adattárolásra szolgál. Ezek a MySQL, a Memcache, a Redis és így tovább.

5. Maga a webszolgáltatás kódja (in ezt a példát– PHP kód) egyformán másolódik minden csomópontra, ahol van Apache + PHP, és egyformán dolgozza fel azokat a kéréseket, amelyek egyik vagy másik csomópontra „esnek”.

6. Az adatbázisok valamilyen sharding segítségével „elkenődnek” a szervercsoportjukon, és hasonló módon kiegyenlítik a rájuk eső terhelést.

A figyelmes olvasó észreveszi, hogy a DNS-kiegyenlítés és a CDN nem szerepel a sémában, de a szerző szándékosan kihagyta őket, nehogy túlbonyolítsa a sémát. Ezeknek a daraboknak a működési elve nagyon hasonló a fentiekhez.

A klasszikus megközelítés hátrányai

1. A fő tendencia a komplikáció. A projekt élettartama során a „klasszikus” séma egyre bonyolultabbá válik. Minden új szerver hozzáadásával be kell írnia a forgalomelosztási sémába. Természetesen a nagy projekteknél a szerver szerepbe helyezése „egygombos” művelet, de ennek ellenére ez az infrastruktúra növelése, amit támogatni kell. És még inkább - abban az esetben, ha az adatbázis jelenlegi kapacitása már nem elegendő, és „élőben” kell (a szolgáltatás leállítása nélkül) átvinni vagy elosztani az adatbázist új szerverekre.

De a fő probléma az, hogy a forgalomelosztási fürt növelése nem vezet a programkód összetettségének csökkenéséhez. A fürtöt hibátlanul építhet, de a kód ugyanaz marad.

2. A telepítés nem atomi. Egyszerű szavakkal, kirakás új verzió a projekt harci szervereken eltart egy ideig. Fizikailag le kell töltenie a fájlokat N-20 gépre, módosítania kell az adatbázist, alaphelyzetbe kell állítania a gyorsítótárakat (sok különböző gyorsítótár), és ezzel egyidejűleg minden szerveren be kell fejeznie a kérések feldolgozását a „régi kóddal”, és el kell kezdenie a feldolgozást a „új kód”. Ellenkező esetben sok apró konfliktus adódhat, amikor a felhasználó kérésének egy része a régi módon, egy része új módon kerül feldolgozásra, egy része a „régi séma szerint”, egy része „az új szerint” került be az adatbázisba, ill. hamar.

Ezért ideális esetben mindenki szüneteltetni szeretné a szolgáltatást a frissítés idejére (néhány másodpercre vagy tíz másodpercre), majd újra bekapcsolni. A valóságban a másodpercenkénti legalább 1000 kérés áramlása mellett ezt senki nem teszi meg, inkább rendszeresen „kézzel” javítja ki a kisebb ütközéseket, vagy „a hetedik generációig” visszamenőleges kompatibilitást támogató defenzív programozással fedi le. A rendszeres támogatásról visszafelé kompatibilitás bonyolítja a programozók életét (és megnöveli a projekt egészének költségeit) – gondolhatja magában egy okos olvasó.

3. HTTP használja. A HTTP protokoll nyilvánvalóan erkölcsileg és technikailag elavult, és ha követed (pl. mobil fejlesztés- Tudja, hogy mindenhol felváltják a könnyebb protokollok. A fő hátrány azonban más: a „böngészőben” lévő HTTP-protokoll megköveteli a hurok befejezését - korlátozott időn belül választ igényel. Ez arra kötelezi a szolgáltatást, hogy a választ szigorúan a böngésző által megengedett kis időn belül számítsa ki és készítse el. Ha a szolgáltatás Ebben a pillanatban túlterhelt - a kérés örökre elveszik.

Ezért a „tipikus webes projektekben” különféle trükkökhöz folyamodnak, mint például a Long polling, vagy az időszakos kérések egyéb formája, ami nem csak az architektúrát bonyolítja, hanem felesleges „elpazarolt húzással” is túlterheli a szolgáltatást.

4. Szkript inicializálása kérésenként. Ez a HTTP és a szkriptnyelvek, például a PHP használatának a következménye, amelyek a régi hagyomány szerint minden kérésre újraindulnak. Igen, igen, a másodpercenkénti 1000 kérés mindegyikére válaszul a PHP szkript újraindul, újra inicializálja az összes változót, és újra kapcsolatot létesít az adatbázissal. A gyakorlatban előfordul, hogy egy kérés feldolgozása 0,005 másodpercet vesz igénybe, és a szkript inicializálása 0,05 másodperc nagyságrendben történik - tízszer tovább!

Más szóval, a szerverei az esetek 90%-ában nem az ügyfélkérések feldolgozásával vannak elfoglalva, hanem a parancsfájlok haszontalan inicializálásával. Próbáld meg pénzre váltani. Ezért számos megoldást találtak ki, például az OPcode gyorsítótárat, az állandó adatbázis-kapcsolatokat, a helyi gyorsítótárakat, mint a Memcache vagy a Redis, amelyek ezt a kellemetlen hatást ellensúlyozzák.

5. Monolitikus alkalmazás. Nem számít, hogyan osztja fel az alkalmazást modulokra, bármennyire is próbálja szétszórni a kódot egy bonyolult könyvtárszerkezeten, bármilyen lusta automatikus betöltést használ is, egyetlen kritérium van: ha a teljes alkalmazást fel kell töltenie a feltöltéshez. legalább egy változás, monolitikus alkalmazásod van. Semmi mást nem adnak.

A monolitikus alkalmazások hátrányait a szakirodalom tömegesen leírja. Az egyik fő röviden megemlíthető: ha azt szeretnénk, hogy a legkisebb funkció is egy órán belül gyártásba kerüljön, akkor a teljes gyártási láncot egy órába kell illeszteni. Problémameghatározás, implementáció, visszafelé kompatibilitás ellenőrzése, tesztírás, dokumentáció írás, átfutás a kézi tesztelési osztályon, hibák kijavítása – mindezt egy órán belül.

Mert ha minden óra pontosan 00 perckor töltöd fel a teljes alkalmazást, akkor minden óra végére hoznod kell az egész alkalmazást stabil állapotba.

6. A webes felületet a háttérrendszer jeleníti meg. Tipikus esetben megjelenés A projektoldalak HTML kódja (és ennek megfelelően a HTML kód) rendszerint minden kérésre válaszul a Backend oldalon jelenik meg. Ez túlzott, indokolatlan forrás- és pénzkiadás.

7. Az osztályok politikai felosztása. Osztály rendszergazdák felelős azért, hogy a bejövő forgalom frontja „elkenődik” egy csomó szerveren, amelyen a PHP kód fut. A programozási osztály felelős a PHP kódért. Ha a PHP kódnak nem volt ideje feldolgozni egy adott kérést, akkor nem világos, hogy ki a felelős ezért - akár az adminisztrátor, aki túl sok forgalmat "engedett" a szerverre és túlterhelte, vagy a programozó, aki nem írt - optimális szkript. Ha az adatbázis lassulni kezd, akkor az sem világos, hogy ki marad extrém: az admin, aki nem vette észre időben, hogy „szilánkokat” vágjon, vagy a programozó, aki szintén kitalálhatta.

Ha a példák eltúlzottnak tűnnek és „nem a valós életből”, ne feledje, hogy a szerző egy olyan projektben dolgozott, amely 200 szerveren volt tárolva, és ezek közül 60-at foglalt el az adatbázis. Ijesztő visszaemlékezni arra, hogy hány embert alkalmaztak ennek a projektnek a kiszolgálására.

Fő hátránya

Megismételjük a fenti gondolatot: a klasszikus séma fő hátránya a szerző szerint az, hogy a műszaki szakemberek rossz dolgot optimalizálnak. Optimalizálják a bejövő kérések elejét, tulajdonképpen a gépek nagy csoportján „elkenik” azt, ahelyett, hogy a lényeget – a számítási részt – optimalizálnák. És sokkal könnyebb, mint amilyennek látszik.

elméleti ideál

Ó, bárcsak tudnánk:

1. Szabaduljon meg egy csomó drága szervertől, és használjon egy vagy két kis csoportot.

2. Hagyja fel a Nginx->Apache->PHP sémát, melynek vad „rezsije” az elfogyasztott erőforrások tekintetében, ami pénzbe kerül.

3. Szüntesse meg a PHP szkriptek inicializálásának szörnyű költségeit, ugyanezen okból.

4. Ne kelljen oldalakat „renderelni” a háttérben. Nagy álom lenne, ha egy webszolgáltatás instabil vagy semmilyen internetkapcsolattal működne (például használat közben mobilhálózat az úton).

5. Szabaduljon meg a HTTP időtúllépési „huroktól”, csak akkor küldje el a választ a kliensnek, ha ez a válasz kész, és kézbesítési garanciával.

6. Frissítse a projektet kis részletekben, megállás és egyetlen ügyfél kérés elvesztése nélkül.

7. Ne aggódjon az elveszett kérések miatt, ha a projekt egy része (egyik összetevője) "leesett" vagy átmenetileg kikapcsolt hibakeresés céljából.

Irreális? Könnyen!

Első lépések a kiválóság felé

Először is, tanuljunk mit meg kell tenni, ezért megbeszéljük - hogyan.

1. Tervezze meg az egész rendszert SOA-ként(szolgáltatás-orientált architektúra) ESB-vel (enterprise messaging bus), felhagyva a monolitikus megközelítéssel, így az üzleti logika minden független részét külön „szolgáltatás” dolgozza fel, és egy független cserebuszon keresztül kommunikálnának egymással.

2. Engedd el a szinkronitást. Például egy szinkron "kérés - feldolgozás - válasz" sémában ez egy HTTP hurok, amely nem rendelkezik szigorú leállítási vezérléssel, és könnyen megszakítható. Aszinkronban három különálló folyamat van: kérés (elküldve és megerősítve), feldolgozás (újrapróbálkozás sikertelenség esetén), válasz kézbesítése (garanciával).

3. Ossza fel a projektet két alkalmazásra- Frontend és Backend. Webszolgáltatás esetén a frontend (általában) JavaScript alkalmazás. A lényeg az, hogy az alkalmazások aszinkron módon és egymástól elválasztva működnek, és kétirányú kommunikációs protokollon keresztül cserélnek üzeneteket.

4. Leiratkozás a HTTP-ről a WebSocket javára. A WebSocket protokoll fantasztikus teljesítményt nyújt a HTTP-hez képest, nincs benne "időtúllépéses hurok", és lehetővé teszi az adatok (beleértve a bináris adatokat is) mindkét irányba történő átvitelét.

5. Biztosítson „tárhelyet” a lekérdezések futtatásához. Miután megkapta a kérést az ügyféltől, mondja az ügyfélnek a „Confirm” kifejezést, és mentse el a kérést. Amint a háttérrendszer felszabadul az előző feldolgozási ciklusból, adja át neki a kérést. Amíg a kérés „sétál” a háttér-csomópontok között, tartsa meg attól a pillanattól kezdve, hogy „belépett” a csomópontba, és véglegesítse, amint „elhagyta” a csomópontot. Így ha néhány csomópont „leesik”, a rendszer nem veszíti el a kérést, és azonnal visszaküldi a feldolgozáshoz. A feldolgozás végén küldje el az eredményt a kliensnek, és tárolja mindaddig, amíg a kliens a „Megerősítés” szót nem mondja.

6. Biztosítsa a párhuzamos számítást az üzleti logika szempontjából párhuzamosan végrehajtható műveletekre, a szigorúan szekvenciálisan végrehajtandó műveletekre pedig a sorrend. Ez a bekezdés nem a „Captain Obviousness” követelésével íródott, hanem azért, hogy megmutassa, egyetlen üzleti folyamatot sem lehet „vakon ráhelyezni” a többszálú kódra.

7. Hagyja fel a szkriptet a „démonok” javára. A démon egy olyan folyamat, amely egyszer elindul, majd folyamatosan „lóg” a memóriában. Mivel folyamatosan fut, nem kell minden kérésnél újra inicializálni. A jövőre nézve azt mondom, hogy a PHP démonnak (a PHP modern verzióinak használatakor) nincs alapvető különbség a normál PHP-szkripttől.

SOA tervezési megközelítés

A SOA – Service Oriented Architecture – nem újkeletű. A szoftverfejlesztésnek ezt a moduláris megközelítését az IBM kezdeményezte még a múlt században, és jelenleg az iparág vezetői támogatják és népszerűsítik, főként a .NET és JAVA „vállalati szintű” termékeiben.

A webszolgáltatások programozásának klasszikus megközelítésében PHP nyelvekés hasonlók - a tervezés a modellekből, azok tulajdonságaiból és az azokon végzett műveletekből indul ki. A modellek valós objektumokat, a műveletek pedig az objektumokon végzett műveleteket képviselik. A gyakorlat azonban azt mutatja, hogy a valós világ sokkal sokrétűbb és összetettebb, és sokkal hatékonyabban írja le az események és az azokra adott reakciók nyelvezetét (további részletekért lásd a #1593. bejegyzést leírással és példákkal).

A való világ olyan eseményekből áll, amelyek egyszerre (programozási szempontból - „párhuzamosan”) és többnyire a mi részvételünk nélkül következnek be, és amelyekre különféle reakciók lépnek fel vagy nem. A reakciók pedig a következő eseményeket generálhatják. A SOA ideális „valódi programozáshoz”, mivel a legkényelmesebb az eseményekkel, a köztük lévő kapcsolatokkal és az azokra adott reakciókkal operálni. Sőt, at helyes megközelítés az architektúra megszervezéséhez, és az események és az azokra adott reakciók párhuzamosan történnek, még akkor is, ha olyan „egyszálú” programozási nyelvet használunk, mint a PHP.

A SOA-terméket az alapján kell megtervezni, hogy az üzleti logikájában milyen események fordulnak elő, ezek hogyan kapcsolódnak egymáshoz, illetve hogyan kell követniük egymást, milyen reakciók léphetnek fel bizonyos eseményekre válaszul, és pontosan ki fogja ezeket vagy azokat az eseményeket feldolgozni. egyéb események. Az adatmodellek megvalósítása és a rajtuk végzett műveletek háttérbe szorulnak ("szolgáltatásba" foglalva), és előtérbe kerül a "szolgáltatások" listája és a köztük lévő interakció terve (inter-service API).

Megvalósítás: első közelítés

1. Frontend, mint független alkalmazás. Bármely népszerű JavaScript-MVC-keretrendszer alkalmas a megvalósításra. A gyakorlatból azonban megjegyzem, ha fájni kezdesz, amikor egy mondatban összevonod a „JavaScript, MVC és keretrendszer” szavakat, akkor nehéz lesz. Az alkalmazásnak képesnek kell lennie az összes „képernyőjének” megrajzolására anélkül, hogy a háttérre hivatkozna, navigációt kell adnia a felhasználó számára (átmenetek a „képernyők között”) anélkül, hogy a háttérre hivatkozna, és támogatnia kell a kétirányú kommunikációs csatornát a háttérrel.

2. Belépési pont a WebSocket-kapcsolathoz a háttérrendszerhez. A NodeJS-ben számos kész megoldás található, amelyek szintén támogatják a hosszú lekérdezés és az ajax tartalék kérelmeit. ideológiailag elavult böngészők. A jövőre nézve megjegyzem, hogy ez a csomópont tiszta HTTP-n is elérhető, ha valaki más szolgáltatásaival kell néhány átjárót írni, azonban az egyszerűsítés kedvéért írhat egy külön „tiszta HTTP” csomópontot.

A belépési pont kétirányú kommunikációs csatornát biztosít a front-end alkalmazással (más szóval a böngészővel), fogadja az onnan érkező kéréseket és küldi vissza a válaszokat.

3. Futó kérések tárolása a rendszerben. Ehhez a népszerű AMQP szerver a legmegfelelőbb, amely üzenetsorokat és azok közötti útválasztást biztosít. Amint a következő kérés érkezik az ügyféltől, helyezze a „bejövő” sorba. Ezenkívül a démon kivonja ebből a sorból, amely elemzi a kérés tartalmát, és elküldi azt a rendszeren belüli „útválasztáshoz” (ami valójában azt jelenti, hogy bizonyos algoritmusok szerint egy vagy több sorba kell áthelyezni). Minden démon, amely az üzleti logika saját részével foglalkozik, megkapja ezt vagy azt az üzenetet a „saját” bejövő sorától, feldolgozza és a választ a „kimenő” sorba helyezi.

Megjegyzem, hogy a népszerű RabbitMQ bróker terminológiájában nincs fogalma a kimenő sorokról. Az üzenetek a központban (changerben) kerülnek közzétételre, ahonnan maga a bróker az útválasztási szabályok szerint meghatározott sorokba kerül. Itt úgy van megírva, hogy a feltételes megértést szolgálja, hogy a választ nem közvetlenül a kérelmezőnek küldik el.

4. Démon irányítás(felügyelő). Egy egyszerű PHP szkript démonként való futtatásához csak csomagolja be a futtatható kódot a while(true) (...) karakterláncba, és írja be parancs sor valami ilyesmi: „php your-script.php”. De jobb ehhez bármilyen megfelelő felügyelőt használni, aki lényegében ugyanazt teszi, de biztosítja a szükséges környezeti állapotot, figyelemmel kíséri a folyamat állapotát, és még hasznos dolgokat tesz.

A való életben a PHP démon egy kicsit bonyolultabb: vezérlőjeleket és újrakonfigurálási üzeneteket kell fogadnia, nem szabad memóriaszivárogtatnia, fenn kell tartania (vagy helyre kell állítania a megszakadt) kapcsolatokat az adatbázissal - de általában nem bonyolultabb, mint az általad megszokott PHP szkriptek .

Egy lépéssel közelebb a valósághoz: eseményvezérelt megközelítés a SOA-ban

A moduláris alkalmazások felépítésének egyes (a szerző véleménye szerint elavult) megközelítései az RPC (Remote Procedure Calling) elven alapulnak, amely egy távoli projektkomponensben meghatározott módszerek vagy eljárások közvetlen meghívását jelenti. Ez a megközelítés teljesen megsemmisíti a SOA minden előnyét, mivel általában közvetlen és kemény kapcsolatot jelent a küldő és a végrehajtó csomópontok között. Egy komplex termék tervezésénél és kivitelezésénél a lehető legnagyobb mértékben be kell tartani a lazán csatolt komponensek elvét, hiszen az architektúra és a kód összetettsége határozza meg végső soron a birtoklási költségeket (a termék korrekcióit, változtatásait). indulása után).

A SOA eseményvezérelt megközelítése azt feltételezi, hogy az összetevők (szolgáltatások) aszinkron események („események”, az Event szóból eredően) küldésével kommunikálnak egymással. Az esemény egy üzenet (például az AMQP terminológiájában), amelynek neve (név) és paraméterkészlete van. Az esemény célja, hogy közölje a rendszerrel, hogy valami történt, vagy „kérdést tegyen fel” a rendszernek. Általános esetben az eseményeket cím nélkül küldik „a rendszernek” (pontosabban a közös ESB-busznak), vagyis konkrét szándék nélkül, hogy konkrét csomópontokhoz vagy előadókhoz továbbítsák.

Éppen ellenkezőleg, bizonyos csomópontok (összetevők, szolgáltatások) a közös buszra figyelnek bizonyos eseményekre, amelyekre készek reagálni. Ez azt jelentheti, hogy a szolgáltatás készen áll valamilyen esemény meghallgatására és a megfelelő művelet végrehajtására. Vagy a szolgáltatás rendelkezik bizonyos ismeretekkel (például rendelkezik egy adatbázissal, amely információkat tartalmaz a felhasználókról), és készen áll arra, hogy ezeket a „kérésekre” válaszul megadja. Mindkét esetben egy eseményre adott válasz eredménye egy új esemény generálása (más névvel és más paraméterekkel), amelyet más érdeklődő szolgálatok is hallhatnak.

A tábornok megfelelő szervezésével ESB gumik, a szolgáltatások aszinkron módon küldik és fogadják az eseményeket, egymásra várás nélkül. Ez azt jelenti, hogy a küldő szolgáltatás tetszőleges számú eseményt tud küldeni az ESB-nek időbeli késedelem nélkül, és továbblép a következő feladatok megoldására. Hasonlítsa össze ezt a klasszikus HTTP-vel, ami azt jelenti, hogy várni kell a válaszra az aktuális feldolgozási ciklusban, és látni fogja az előnyöket. És a fogadó szolgáltatások is aszinkron módon, egymástól függetlenül kapják meg az új eseményeket az előző esemény feldolgozása után azonnal.

SOA eseménymodell kódban

Röviden, a kódot nem függvényekkel (metódusokkal) rendelkező osztályoknak kell tekintenie, hanem eseményeknek és műveleteknek, amelyek ezekre az eseményekre válaszul fordulnak elő. Ráadásul a cselekvések eredményei is események. A tárgyalt architektúrával kapcsolatban elmondhatjuk, hogy a helyi események olyan események, amelyek egy adott PHP szkripten belül történtek, a távoli események pedig olyan események, amelyek az AMQP-sorból érkeztek ehhez a szkripthez (vagy ennek eredményeként kerülnek oda). Ha az összes kódot így kezeli, az azonnal meglepő és nagyon fontos hatáshoz vezet:

Ha a helyi és a távoli események megegyeznek, akkor a helyi és a távoli eseménykezelő is ugyanaz!

Miért olyan fontos? Mert a csapatod programozói továbbra is rendes PHP kódot írnak, anélkül, hogy meggondolnák, hol lesz feldolgozva ez vagy az az esemény – ott, ebben vagy egy szomszédos PHP szkriptben, vagy valahol a rendszer másik végén, egy másik démonban, legalábbis a másik programozási nyelven. Ha nyilvános API-val készít projektet, akkor bármely külső résztvevő „aláírhatja” a kódját az eseményeihez (és feldolgozhatja azokat), vagy fordítva – elküldheti a sajátját, hogy az eseményeit úgy dolgozza fel. kéréseket (és pénzt is kap érte, ha használatonkénti fizetős SAAS üzleti modellt használ, mint például az Amazon).

Emlékezzen arra, amit a klasszikus nagy webprojektek fő hátrányának neveztünk - folyamatosan növekszik bonyolultság, és ebből következően a tulajdonosi költség, a támogatás és a változtatások költsége. Eseményvezérelt SOA architektúra esetén − a komplexitás folyamatosan csökken, hiszen a „komplex csomópontok” könnyen feloszthatók független szolgáltatásokra (jelen esetben démonokra), miközben a rendszer alapelvei változatlanok maradnak, teljesítménye pedig csak nő.

Telepítsen egy új verziót a jelenlegi folyamatok elvesztése nélkül

Mivel már nincs monolitikus rendszere, nem kell a teljes rendszert telepítenie. Sőt, egy összetevő (szolgáltatás, démon) telepítése bármikor eltarthat, természetesen ésszerű határokon belül. Az a fontos, hogy a komponens telepítési ideje alatt (az a néhány másodperc vagy több tíz másodperc) a teljes projekt egy pillanatra se szakítsa meg a szolgáltatást. Hogyan történik?

Egyszerűen kikapcsolja azt a szolgáltatást, amelyet frissíteni kell. Frissítse a kódját és az adatbázis szerkezetét (ha szükséges), majd futtassa újra. A szolgáltatáshoz intézett összes jelenlegi kérés az AMQP-sorban várakozik, amíg a szolgáltatás meg nem jelenik. Megjegyzem, mivel a szolgáltatások kicsik (kis mennyiségű kód szükséges az üzleti logika csak egy kis részének megoldásához) - ez sokkal gyorsabb, mint egy teljes monolitikus alkalmazás telepítése. De semmi esetre sem lesz veszteség.

Problémák a webes felülettel

A nagy terhelésű projektek előfeltétele a gyors, reszponzív webes felület. Nézzük meg, miért „lelassul” általában a webes felület a megvalósítás klasszikus megközelítésével:

1. Az interfész a háttérben van megrajzolva, amely túlterhelt és lassan csinálja. Az oldalak közötti váltás lassú. Még AJAX esetén is túl lassan rajzolódnak át a blokkok.

2. Az interfész forráskódja (HTML, CSS, JS) redundáns és lassan továbbítódik a kommunikációs csatornákon, különösen, ha ez az egyes oldalak betöltésekor történik, amikor a felhasználó a felületen keresztül navigál.

3. A felület nagy mennyiségű optimalizálatlan JavaScript logikát tartalmaz, ami gyenge eszközökön (elsősorban mobileszközökön) lassú.

Próbáljuk meg megoldani ezeket a problémákat:

Hogyan készítsünk gyors és reszponzív webes felületet

1. Először is, és ami a legfontosabb, forrás interfész kell legfeljebb egyszer továbbítják az ügyfélnek. Ennek egyetlen civilizált módja egy teljes értékű JavaScript alkalmazás elkészítése. Egyszer letöltődik a kliensre (ebben az esetben egy gyönyörű animált előtöltőt mutathat), majd a szolgáltatással való munkavégzés teljes ideje alatt az ügyfélnek nem kell várnia a letöltésre.

2. Minden átmenetet el kell végezni a webes felület "képernyői" között JavaScript alkalmazáson belül, és semmi esetre sem külön kérésként a háttérrendszer felé. Van rá egy kifejezés, az „egyoldalas webalkalmazás”, amelyben a navigáció lényegében a „képernyők” váltásával történik, míg a tartalom címsor dinamikusan változik, megteremtve a klasszikus „oldalátmenetek” teljes érzetét.

3. Üzenetek (események) küldése a háttérrendszernek és válaszok fogadása kötelező elválasztva egymástól és a felhasználói navigációtól(aszinkron). A fent említett WebSocket eleve éppen egy ilyen megvalósítást „ajánl”. Minden hosszadalmas műveletnek nem szabad blokkolnia az interfészt, kivéve, ha kifejezetten erre történik.

Így a felhasználónak csak internetkapcsolatra van szüksége az alkalmazás első letöltéséhez (néhány másodperc). Ezenkívül még akkor is működik a szolgáltatással, ha átmenetileg hiányzik a kapcsolat (például mobileszközről a metróban, a városon kívül, egy túlzsúfolt külföldi szállodában stb.) - az alkalmazás rögzíti a kéréseket, és megpróbálja elküldi őket, amint megjelenik az internet, és így ugyanúgy kap válaszokat.

Ez természetesen nem mentesíti a fejlesztőt a kód optimalizálásának és minimalizálásának szükségessége alól. A gyakorlat azonban azt mutatja (például a Trello szolgáltatás), ez a feladat nem nehezebb, mint mások.

Megjegyzés a mobileszközökre szánt webszolgáltatások kételkedő fejlesztőinek: a szerző gyakorlata szerint 2013-ban a websocket transzporton futó egyoldalas JavaScript alkalmazások sikeresen működnek iPaden.

Felhasználói munka több eszközről

Munkavégzésből, munkából igénybe veszi a szolgáltatásodat asztali számítógép, hazafelé elővesz egy iPhone-t, otthon pedig bekapcsolja a tabletet. Ha a felhasználó valamilyen parancsot küldött a felületről a szolgáltatásnak, akkor választ vár a feldolgozás eredményéről. Könnyen érthető, hogy ha (amikor) a feldolgozás kézzelfogható időt vett igénybe, akkor a választ arra az eszközre kell elküldeni, amelyet a felhasználó éppen használ (elnézést a szójátékért) válasz kézbesítése, nem a kérés időpontjában.

A probléma az, hogy nem lehet egyértelműen megmondani, hogy a felhasználó abbahagyta-e (már megint elnézést) ezt vagy azt konkrét eszköz. Talán bezárta a böngészőt. Lehet, hogy lemerült az akkumulátora. Talán elindult a metróalagútba, ahol nincs összeköttetés, és fél perc múlva újra megjelenik. Sok lehetőség van, és a szerző ismeretlen A legjobb mód definíciók. Íme azonban, amit hasznosnak találhat:

1. Rögzítse (a háttérben) a felhasználó összes eszközét és mindegyikről az utolsó tevékenység idejét.

2. Osztályozza azokat a rendszereseményeket, amelyeket jelenteni kell a felhasználónak, azokra, amelyeket csak az aktív eszközökre kell eljuttatni, és azokra, amelyeket „sugárzott” (minden eszközre) kell továbbítani.

3. Írja be extra réteg absztrakciók - olyan szolgáltatás, amely elfog bizonyos, a felhasználó számára érdekes eseményeket, és üzeneteket formál belőlük. Így könnyedén sugározhatja ugyanazt az üzenetet a művelet sikerességéről - többféle formában: rövid értesítés be mobil eszköz, kicsit hitelesebb - a böngészőnek, részletes üzenet - által email.

4. Biztosítson sorokat az egyes felhasználóknak történő küldéshez az egyes kommunikációs csatornákon (webes felület, mobil eszköz, levél). A szabványos AMQP funkcionalitás az üzenetek lejárati időkorlátjaiban is segít, hogy azok egy bizonyos ideig ne maradjanak ott, és ne tömítsék el a rendszert. Amikor egy felhasználó egy adott csatornán keresztül csatlakozik az internethez, az adott típusú friss, függőben lévő üzenetek eljutnak hozzá.

A szerző hozzáteheti, hogy ugyanezen rendszer alapján kiépíthető az értesítések késleltetett küldése (amelyek egy bizonyos időpontnál nem korábban kerülnek kiküldésre), és akár valódi papíralapú időszakos levelezés (cselekmények, kifizetések stb.) küldése. ), de ez egy külön cikk témája .

Hangsúlyozom a lényeget: ne tekintse a kézbesített üzeneteket valamiféle értesítésnek, amihez hozzászokott a Facebookon vagy a Vkontakte-on. A kézbesített üzenetek lekérdezési eredmények felhasználó! A felületen végrehajtott összes felhasználói művelet, amely valamilyen kérést jelent a háttérrendszer felé, egységes formában, „kézbesített üzenetek” formájában kapja meg a válaszokat, egyetlen egységes kommunikációs csatornán keresztül. És akkor a webalkalmazás algoritmusa megérti, mit kell tenni ezzel vagy azzal az üzenettel - rajzoljon értesítést szöveggel, adjon hozzá egy sort a táblázathoz, kapcsoljon valamit a felületen, és így tovább.

Párhuzamos és szekvenciális számítástechnika

Felesleges lenne gyors frontend webes felületet tervezni, ha lassú háttérrendszerünk van. Nem, ez nem a patakokról, nem az elágazásokról és nem az Erlangról szól. Maradunk a szokásos PHP-n, amely minden kezdő/középhaladó programozó számára elérhető.

Egyáltalán miért van szükségünk párhuzamosságra? Még ha általában nem is beszélünk az egyszálú nyelvek hiányosságairól, a párhuzamosság jelentősen felgyorsítja a feladat kiszámítását, ami azt jelenti, hogy jelentősen csökkenti a hardver erőforrásokkal (hardverekkel) szembeni követelményeket, és növeli a felhasználói elégedettséget a munkavégzés során. a felületet (gyorsabban érnek el eredményt).

Vegyen fel bármilyen meglehetősen összetett üzleti folyamatot a webprojektben, és rajzolja meg lépések láncolataként. A kéréstől a válaszig egy műveletsort kap a rendszerben. Valószínűleg először lesz néhány ellenőrzés, majd a fő feladat végrehajtása, majd a másodlagos részfeladatok, végül az eredmény kimenete. Nézze meg alaposan: elvégezhető bármelyik művelet párhuzamosan?

Mondok egy példát: tegyük fel, hogy egy felhasználó olyan szolgáltatást szeretne vásárolni, amely további fizetős opcióként szerepel a tarifacsomagjában. A lehetőségek száma korlátozott. Ha az opció sikeresen be van kapcsolva, akkor értesítést kell küldenie a felhasználónak a böngészőben, másolatot kell küldenie egy e-mailt, le kell vonnia pénzt a számlázási számlájáról, és értesítenie kell az ügyfélosztályt. Rajzolj láncot:

1. A rendszer kérést kapott az opció engedélyezésére.
2. Engedélyezzük a felhasználót és megtudjuk a díjcsomagját.
3. Ellenőrizzük, hogy lehetséges-e egyáltalán engedélyezni ezt az opciót díjcsomag felhasználó.
4. Ellenőrizze, hogy a felhasználónak van-e elég pénze a számlán.
5. Ellenőrizze, hogy ez az opció ütközik-e más beállításokkal.
6. Ha minden rendben van, akkor engedélyezze az opciót.
7. Értesítést küldünk a böngészőnek.
8. Értesítést küldünk postai úton.
9. Írjon le pénzt a számlázásból.
10. Értesítjük az ügyfélosztályt.

Egy figyelmes olvasó hibát találhat a műveletek sorrendjében, de a szerző emlékeztetni fogja, hogy ez egy hozzávetőleges példa.

Mit látunk? Vegye figyelembe, hogy nincs ok az összes lépést egymás után végrehajtani. Sokkal helyesebb lenne a 3,4,5-öt három szálra „párhuzamba állítani”, a végén pedig a 7,8,9,10-et négy szálra.

Az áramlásokra és az elágazásokra gondol? Hiába, van SOA!

Hogyan készítsünk párhuzamos számítást a SOA-ban

Azoknak az olvasóknak, akik mostanáig végiggörgették a cikket, elmagyarázom, hogy itt nem ugyanazon feladat párhuzamosításáról van szó a SOA-ban - ehhez általában elég, ha a démont N példányban lefuttatjuk, és gondoskodunk a az adatbázishoz való hozzáférésről szóló vita.

Tehát ebben a példában három-négy-több különböző feladatunk van, amelyeket különböző szolgáltatások hajtanak végre, és amelyeket párhuzamosan szeretnénk végrehajtani. Párhuzamos feldolgozásra küldeni nem nehéz: elég egy eseményt elküldeni a „felhasználónév engedélyezheti az X opciót?” eseményt, és az erre az eseményre előfizetett összes szolgáltatás elkapja, elvégzi az ellenőrzéseket, és elküldi a keletkező eseményeket.

A probléma pontosan az, hogy összegyűjtsük ezeket az eredő eseményeket, amikor szükségünk van munkájuk teljes eredményére a továbblépéshez. Például a fenti listában a 3+4+5 eredményre van szükségünk, a 7+8+9+10 pedig figyelmen kívül hagyható.

Valójában a tranzakciók kötelező teljesítésére vonatkozó magas követelmények mellett minden láncot a végéig ellenőriznie kell, de erről később beszélünk.

Természetesen, ha a démonunk "lóg és vár", erőforrásokat fogyaszt (az úgynevezett "tétlen"), akkor nem lehet ilyen magasan terhelt szolgáltatást felépíteni. A lényeg csak az, hogy a démon más feladatokat old meg és más kliensek kéréseit szolgálja ki, miközben három különálló „szál” (3,4,5) oldja meg az ő részfeladatait. Nehézséget okoz az is, hogy az ebből fakadó események tetszőleges sorrendben jöhetnek. Mindez azonban egyszerűen és egyszerűen megoldható:

A szerző tudomása szerint a ma létező, beépített AMQP implementációk egyike sem teszi lehetővé, hogy több eseményt várjunk el és „egybe ragasszunk”, hogy csak azt kapjuk – egy eredményt. Tehát magának kell gondoskodnia róla, például:

1. Mielőtt eseményt küldene az AMQP-nek, kötelezze el magát gyors memória(használjon bármilyen megfelelő memórián belüli tárolót) az eredményül kapott események nevének listája, amelyet a szolgáltatás fogadni vár, valamint az esemény nevét (nevezzük „R”), amelyet el kell küldeni a az eredmények.

2. Ezt követően a szolgáltatás befejezi az aktuális esemény feldolgozási ciklusát, és felszabadul a következő feladatokra.

3. Amint megérkezik bármelyik esemény a listáról, amit a memóriában tároltunk, a szolgáltatás „kicsomagolja” és a memóriában tárolja a tartalmát, hozzárendelve az esemény nevéhez. Ugyanakkor ellenőrzi, hogy vannak-e még olyan események a listában, amelyekre nem érkezett válasz. Ha igen, akkor a hurok ezen a ponton ér véget.

4. Ellenkező esetben, ha a listában szereplő összes eseményre válasz érkezett, a szolgáltatás ezeket összeragasztja, és az összeragasztott eredményt a korábban megjegyzett „R” esemény néven küldi el. Ezt követően a memória megtakarítása érdekében az eredmények listája egyszerűen törlődik a memóriából - már nincs rá szükség.

5. Ugyanaz a szolgáltatás, vagy más (a rendszertervező döntése szerint) megkapja az eredményül kapott „R” eseményt a párhuzamos feldolgozás összes eredményével együtt. Ami ezután következik, az nyilvánvaló.

Ha a leírásból úgy tűnt, hogy ez hosszú idő, akkor elmagyarázom - másodpercenként (!) ezer és tízezer eseményről beszélünk egy átlagos szerveren.

A memórián belüli tárhely használata azt jelenti, hogy még ha a szolgáltatás leáll (leesik, frissül), az aktuális üzleti folyamat nem vész el. A szolgáltatás újraindítása után továbbra is fogadja az eseményeket az ESB-től, és feldolgozza azokat a fent leírt algoritmus szerint.

Tranzakcionalitás, műveletek visszaállítása (visszagörgetés) és meghibásodási forgatókönyvek a SOA-ban

Mivel a SOA-ban a peer események „átmennek” az ESB-n, szükség van valamilyen jelzésre, hogy jelezze, hogy „ez itt a válasz” „arra a kérésre ott” utal. Itt nem kell újra feltalálni a kereket – minden népszerű protokoll specifikációjában talál egy paramétert, amelynek neve például correlation_id. Általában ez egy karakterlánc. Minden egyes üzleti folyamat minden eseményének paraméterében szerepelnie kell a belépéstől a kilépésig, hogy azonosítani lehessen az ehhez az üzleti folyamathoz tartozó üzenetláncot. A webes felület oldaláról nézve a webes alkalmazás tárolja az aktuális aktív (elküldött) kéréseket, és a correlation_id alapján „megérti”, hogy az egyes válaszok melyik kérésre érkeztek.

Foglalkozzunk a terminológiával: a tranzakciós képesség a rendszer azon tulajdonsága, hogy több műveletet egyetlen közös műveletként hajt végre, aminek van értelme és csak teljesen befejezhető. Mivel fizikailag lehetetlen több műveletet atomosan végrehajtani egy elosztott rendszerben párhuzamos szálakkal, a rendszer rendelkezik úgynevezett hibaforgatókönyvekkel és visszagörgetésekkel.

A sikertelen forgatókönyv általában egy hiba esetén végrehajtandó művelet. Ebben az összefüggésben a visszagörgetés olyan műveletek szkriptje, amelyeket végre kell hajtani egy sor olyan korábbi művelet „visszavonásához”, amelyek végül hibához vezettek. Durván szólva a visszagörgetések olyan folyamatok, amelyek a rendszer normál üzleti folyamatainak a fordítottja.

Visszaállításra nincs mindig szükség, és nem mindig lehetséges. Például, ha a felhasználóhoz kapcsolt valamilyen opciót, majd „beesett” a számlázáson, akkor az opció visszakapcsolható. Nos, akkor megpróbálhatja újra, automatikusan vagy a felhasználó második parancsával. És ha fizikailag törölte a tartalmat, és néhány későbbi művelet nem működött... A helyzet nem egyértelmű.

Ezért a sikertelen forgatókönyveket és a visszaállításokat bölcsen kell megközelíteni. A szerző javasolhatja a következő elérési utat: Mindig írjon sikertelen szkripteket, de ne mindig írjon visszagörgetést. Meghibásodásai azonnal tükröződnek a felügyeletben - és a támogatási csapat gyorsan meg tudja oldani a helyzetet, tapasztalatot szerezhet és technikai követelményeket fogalmazhat meg a programozók számára. Míg egy egyedileg helyes visszaállítást a semmiből írni nagyon-nagyon nehéz lehet.

Mindazonáltal meg kell érteni, hogy a visszaállítások, visszaállítások, a hibás helyzetek kezelése ugyanolyan üzleti folyamatok, mint minden más. A rendszeren áthaladó eseményeken is alapulnak. Jó lesz, ha kezdetben két ellentétes utat (előre és hátra, siker és kudarc) határoz meg minden eseményben és minden kezelőben, hogy ezeket konkrét feladatokban megvalósítsa.

SOA méretezés

Minden rendszert előbb-utóbb bővíteni kell. A SOA esetében ez egyszerűen és természetesen történik:

1. Ismétlődő belépési pont. Ez ugyanarra a WebSocket átjáróra vonatkozik, amelyet a cikk elején tárgyaltunk. Korlátlan sokszor megkettőzhető, mivel a közte és a kliens közötti kommunikáció egységes és leválasztható a rendszer belső részeiről, a közte és a rendszer közötti kommunikáció pedig leválasztható a klienssel való kommunikációról.

2. Ismétlődő példányok szolgáltatások (példányai). Azok a szolgáltatások, amelyek nem igényelnek adatbázist, vagy csak „olvasnak” belőlük, zökkenőmentesen duplikálódnak. A RabbitMQ rendszeres funkcionalitása pedig lehetővé teszi, hogy N példányra feliratkozzon ugyanabba a sorba, amelyekből az üzenetek véletlenszerűen érkeznek egyik vagy másik példányba. A külső alkalmazásokkal foglalkozó szolgáltatások (adatbázisok, harmadik féltől származó szoftverek) másolásakor figyelembe kell venni, hogy ezek az alkalmazások hogyan biztosítanak tranzakciós kéréseket több párhuzamos klienstől.

3. Adattárak megkettőzése. Itt szabadon használhatja az Ön által ismert szilánkokat. Ha 10 millió felhasználóval van dolgunk, és ez soknak tűnik, osszuk el 10 millió bázissal (például a felhasználó bejelentkezéséből származó CRC32 alapján, vagy valamilyen más körbefutó módszer alapján). Ha egy szolgáltatás adatbázisa folyamatosan növekszik és egyre bonyolultabbá válik, bontsa két szolgáltatásra.

4. AMQP Broker sokszorosításaés a memórián belüli tároló. A szerző gyakorlata szerint a RabbitMQ és a Redis tökéletesen betölti szerepét. Ha egynél több egyenáramú rackben van berendezés, válasszon olyan nyúl módot, amely tolerálja a hálózati csatlakozási hibákat.

5. Teljes gépi sokszorosítás. TÓL TŐL modern technológiák virtualizáció (KVM) és konfigurálás (Chef), az „ugyanannak a gépnek a felemelése” egyetlen gombnyomásra esik le.

A frontend és a háttérrendszer közötti forgalom titkosítása

Javasoljuk, hogy a WebSocket kapcsolatot SSL-en keresztül szervezze meg. Ráadásul növeli a "penetrációt" az olyan visszamaradt irodai szolgáltatókkal szemben, amelyek blokkolnak "bármilyen furcsa forgalmat", kivéve a HTTP[S]-t.

Ha azonban ez nem tűnik elegendőnek, minden ügyfél-bejelentkezéskor megszervezheti a kulcspárok generálását (egy pár az előoldalon, a második a hátsó oldalon), nyilvános kulcsokat cserélhet, és tovább titkosíthatja az összes forgalmat a normál RSA-val.

DDOS és hasonló visszaélések elleni védelem

A szerző szándékosan mellőzi az „alacsony szintű” védelem kérdését, amikor a SYN több száz gigabites elárasztásáról és csatornáinak elárasztásáról van szó, hiszen erről több száz szakirodalom született. Beszéljünk arról, hogyan védhetjük meg a rendszert már belül, annak logikai szintjein, amikor egy támadó megtalálta a módját, hogy több ezer eseménnyel „árassza el” a rendszert (SOA + ESB).

1. Első szabály: semmit sem szabad feldolgozni, amíg az érvényességét meg nem erősítik. Ha BASE64-be csomagolt kis JSON-szöveget vár bemenetként, akkor a megabájtnál hosszabb bejövő karakterláncot kifejezetten el kell dobni – ne próbálja meg kicsomagolni. A „nem latin” karaktereket tartalmazó karakterlánc hasonló. Ha kicsomagolt egy karakterláncot, ne próbálja meg azonnal végrehajtani a json_decode-ot, először ellenőrizze a zárójelek számát és párosítását. Stb.

Paranoiának tűnik, de egyébként könnyen „memóriából töltődik fel”, vagyis a szolgáltatás meghibásodásához vezethet, és arra kényszeríti, hogy az összes rendelkezésére álló RAM-ot lefoglalja.

2. A bejövő üzeneteket feldolgozó szolgáltatás nem írhat semmit a memóriába, az adatbázisba és más tárolókra. Az ok ugyanaz. Először győződjön meg arról, hogy az üzenet egésze érvényes, és csak ezután engedje „mélyebbre” a rendszerbe.

3. Egy olyan szolgáltatást, amely gyakran „adatbázisba lépésre” kényszeríthető, gyorsítótárazással kell védeni. Egy egyszerű példa egy felhasználói engedélyezési szolgáltatás. Ha nem védett, akkor a támadó több ezer engedélyezési kérelmet küldhet egymás után, ezáltal túlterhelve az adatbázist.

4. A rendszer bejáratánál olyan szolgáltatásra van szüksége, amely elutasítja a „gyanús” forrásokból származó kéréseket, például a „feketelistán” szereplő IP-címekről.

Klasszikus tanácsnak hangzik, szóval mi a helyzet? A fő probléma az, hogy ha egy analizátor-szűrő szolgáltatást helyezünk el a rendszer bejáratánál (ahogyan ez a klasszikus webes projektekben történik), akkor a teljes rendszer teljesítménye nem lesz magasabb, mint ennek az analizátor-szűrőnek a teljesítménye. Rendkívül költséges minden egyes bejelentés „valós idejű” gyanúsított áttekintése. Ezt utólag is megteheti és meg kell tennie, és a következőképpen teheti meg:

1. Készítsen szolgáltatást, amely „meghallgatja” a rendszer összes üzenetét. A RabbitMQ-ban ez a „#” útválasztó kulcsra való feliratkozással érhető el.

2. Tanítsa meg ezt a szolgáltatást bizonyos szabályokra, amelyek alapján képes diagnosztizálni a "gyanús" küldőket. Például ezek a feladók, akik túl sok hasonló üzenetet küldenek egy időintervallumban, vagy akik ismétlődő üzeneteket küldenek, vagy akik ugyanazon felhasználó nevében küldenek üzeneteket különböző IP-címekről... Rengeteg lehetőség van, kapcsolja be a képzelet. Ugyanakkor nem mindegy, hogy egy ilyen szolgáltatás milyen gyorsan működik (természetesen ésszerű határokon belül) - ez nem befolyásolja az egész rendszer sebességét.

3. Amint a szolgáltatás arra a következtetésre jut, hogy egy ilyen vagy ilyen feladó gyanús, elküldi ezt az eseményt a rendszernek, és folytatja a dolgát.

4. Tegyen a bemenetre egy nagyon egyszerű és gyors démont - egy szűrési szolgáltatást, aminek a feladata egyszerűen az lesz, hogy "hülye módon" blokkolja a gyanús küldőket. Nincs elemzés, nincs elemzés, nincs többletköltség. Könnyen kitalálható, ki számít gyanúsnak: a szolgáltatás az előző bekezdésben leírt eseményekből értesül róluk, és felveszi belső feketelistájára.

Az első rész vége. Folytatás: SOA: elosztott architektúra és karbantartása.

Mentor vagyok informatikai projektekben. Ez azt jelenti, hogy ha Ön tulajdonos vagy vezető, segíthetek új magasságokba lépni. Tisztítsa meg a folyamatokat, értse meg a csapat motivációját, alkalmazzon eszközöket és érjen el konkrét célokat. Nem üzletelni tanítok, hanem csak segítek megkerülni a nagylelkűen szétszórt gereblyét. .