ИТ развој

Mastering PHP's Asynchronous Capabilities for Snappy Backend Performance

Совладување на асинхроните можности на PHP за брзи перформанси на задниот дел

PHP има репутација дека прави по една работа во исто време: прима барање, создава одговор, исчезнува. Тој модел останува извонредно ефикасен за многу апликации. Проблемот започнува кога барањето поголем дел од времето го поминува чекајќи — HTTP услуга, база на податоци, кеш или бавна операција на датотечниот систем. Работник што чека не врши корисна работа, а под оптоварување тие паузи се натрупуваат во редици и фрустрирачко доцнење.

Асинхрониот PHP не значи секоја линија код да биде паметна. Станува збор за препознавање независни периоди на чекање и овозможување корисната работа да продолжи додека тие се разрешуваат. Ако се примени внимателно, може да ги направи заднинските услуги поодзивни без да се жртвува јасноста што го прави PHP продуктивен.

Разберете го проблемот пред да изберете асинхрона алатка

Асинхроното извршување најмногу помага кога работата е ограничена од I/O. Типични примери се повикување неколку независни услуги, преземање повеќе оддалечени ресурси или пренос на податоци до клиент. Тоа не прави трансформација на слики што бара многу CPU, пресметка на извештај или задача за шифрирање суштински побрза на едно CPU јадро.

Таа разлика е важна. Ако крајната точка врши скапа пресметка, преместете ја во заднински работник, оптимизирајте го алгоритмот или додадете капацитет. Ако чека три неповрзани мрежни повици, конкурентноста може да го намали вкупното време според часовникот приближно до траењето на најбавниот повик, наместо до збирот на сите три.

Започнете со временска линија на барањето. Наведете ја секоја излезна зависност, нејзиното временско ограничување, дали зависи од друг резултат и што треба да се случи кога ќе откаже. Оваа вежба често открива поедноставно подобрување од воведување нов модел на извршување: отстранете непотребен повик, кеширајте стабилни податоци или направете надолен API да ги враќа полињата што навистина се потребни.

Користете конкурентност таму каде што зависностите се навистина независни

Корисен прв чекор се конкурентните HTTP барања. PHP-овиот cURL multi интерфејс може да управува со повеќе преноси без да бара рамка. Примерот подолу презема две независни крајни точки и го задржува телото на одговорот за секоја рачка.

<?php

$urls = [
    'profile' => 'https://api.example.test/profile/42',
    'orders' => 'https://api.example.test/orders?customer=42',
];

$multi = curl_multi_init();
$handles = [];

foreach ($urls as $name => $url) {
    $handle = curl_init($url);
    curl_setopt_array($handle, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 2,
        CURLOPT_TIMEOUT => 5,
    ]);

    $handles[$name] = $handle;
    curl_multi_add_handle($multi, $handle);
}

do {
    $status = curl_multi_exec($multi, $running);
    if ($running) {
        curl_multi_select($multi, 1.0);
    }
} while ($running && $status === CURLM_OK);

$responses = [];

foreach ($handles as $name => $handle) {
    $body = curl_multi_getcontent($handle);
    $error = curl_error($handle);

    $responses[$name] = $error === '' ? $body : null;

    curl_multi_remove_handle($multi, $handle);
    curl_close($handle);
}

curl_multi_close($multi);

Кодот е намерно скромен, но продукциските грижи не се. Проверувајте HTTP статусни кодови, како и грешки при преносот, декодирајте и валидирајте ги податоците од одговорот и одлучете кој резултат е задолжителен. Страница на профил може да се прикаже без препораки; потврдата за плаќање не треба да продолжи кога потребниот одговор за авторизација е неизвесен.

Библиотеките за event loop и асинхроните рамки можат да понудат поструктуриран модел за поголеми услуги, вклучувајќи тајмери, неблокирачки текови, ветувања и откажување. Современиот PHP нуди и Fibers, кои им овозможуваат на библиотеките да го паузираат и продолжат извршувањето во кооперативен стил. Fibers се градбен блок, а не event loop или прекинувач за перформанси сами по себе. Изберете библиотека или рамка само кога нејзиниот животен циклус, моделот на распоредување и познавањето на тимот одговараат на услугата.

Временските ограничувања, лимитите и резервното однесување се вистинскиот дизајн

Конкурентноста го зголемува бројот на операции во тек. Без лимити, зафатена крајна точка може бавна надолна зависност да ја претвори во бура од конекции. На секој излезен повик му се потребни временско ограничување за поврзување, вкупен рок и ограничена политика за повторни обиди. Непосредното и неограничено повторување не е отпорност; тоа е начин да се засили прекинот.

  • Поставете рок за барањето. Распределете време меѓу надолните повици наместо да дозволите секој да го потроши целиот животен век на барањето.
  • Ограничете ја конкурентноста. Обработувајте големи серии во мали групи за да останат заштитени дескрипторите на датотеки, сокетите и оддалечените услуги.
  • Повторувајте селективно. Повторувајте привремени неуспеси само кога операцијата е безбедна за повторување и користете backoff со jitter.
  • Дефинирајте достоинствено деградирање. Враќајте кеширани, делумни или одложени резултати само кога однесувањето на производот го дозволува тоа.
  • Зачувајте ја набљудливоста. Пренесувајте ID-а на барања и евидентирајте го времетраењето на зависностите, неуспесите и причините за истекување на времето.

Идемпотентноста заслужува посебно внимание. Неуспешно читање често може да се повтори. Барање што создава нарачка, испраќа е-пошта или наплаќа картичка можеби успеало дури и ако клиентот никогаш не го примил одговорот. Користете клуч за идемпотентност или друг механизам за дедупликација на серверската страна пред да додадете автоматски повторни обиди на операции со несакани ефекти.

Нека работата со базата на податоци биде едноставна и сигурна

Конекциите со базата на податоци не се бесплатни, а асинхроната апликација може да создаде притисок побрзо од традиционалното распоредување со барање по процес. Избегнувајте да извршувате неколку прашања конкурентно само затоа што е можно. Најпрво намалете ги повратните патувања со соодветни индекси, добро обликувани прашања и намерно групирање. Потоа користете конкурентност за независна надворешна работа околу базата на податоци кога тоа ја подобрува патеката на барањето.

Трансакциите треба да останат кратки и фокусирани. Не држете трансакција отворена додека чекате оддалечен API ако работниот тек може да се редизајнира. Побезбеден образец е да ја потврдите локалната состојба, по потреба да запишете outbox настан во истата трансакција и да му дозволите на работник да ја изврши надворешната испорака со логика за повторни обиди и дедупликација.

Распоредувањето го менува одговорот

Традиционалните PHP-FPM распоредувања чисто го изолираат секое барање. Долготрајните работници, event loop-овите и апликациските сервери одржуваат процес во живот, што може да ја подобри пропусноста за I/O-интензивни оптоварувања, но воведува одговорности за животниот циклус. Ресетирајте ја состојбата специфична за барањето, затворајте или ослободувајте ресурси, справувајте се со достоинствено исклучување и планирајте рециклирање на работниците по истекувања или неочекуван раст.

Контејнерите ги прават овие грижи видливи. Конфигурирајте здравствени проверки што одразуваат дали процесот може да опслужува сообраќај, пренесувајте сигнали за исклучување преку влезната точка на контејнерот и дајте им на работниците доволно време да ја завршат или безбедно да ја напуштат работата во тек за време на распоредувањето. Одржувајте ги обработката на веб-барања и долготрајните заднински потрошувачи како одделни улоги на процеси, дури и ако споделуваат слика и база на код.

Измерете го резултатот што го гледа корисникот

Асинхрониот код вреди само кога подобрува забележливо ограничување: доцнење, пропусност, ефикасност на конекциите или сигурност на интеграција. Мерете ги перцентилните времиња на одговор, длабочината на редицата, стапките на грешки, времето на надолните услуги и користењето ресурси пред и по промена. Пониско просечно време на одговор не е победа ако доцнењето во опашката, потрошувачката на меморија или оперативната сложеност се влошат.

Најсилните асинхрони PHP системи ретко се најегзотичните. Тие се експлицитни за границите на зависностите, конзервативни со повторните обиди, дисциплинирани со временските ограничувања и искрени за тоа која работа припаѓа во барањето. Направете го чекањето конкурентно таму каде што е безбедно, преместете ја трајната работа надвор од критичната патека и направете однесувањето при неуспех полесно за разбирање од успешната патека. Така перформансите на заднината стануваат брзи без да станат кршливи.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.