Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Avètisman

Sit entènèt mwen an, ke mwen kouri kòm yon plezi, fèt pou òganize paj lakay enteresan ak sit pèsonèl. Sijè sa a te kòmanse enterese m nan kòmansman vwayaj pwogram mwen an; nan moman sa a mwen te kaptive pa jwenn gwo pwofesyonèl ki ekri sou tèt yo, pastan yo ak pwojè yo. Abitid la dekouvri yo pou tèt mwen rete jouk jounen jodi a: sou prèske chak sit komèsyal ak pa trè komèsyal, mwen kontinye gade nan pye a pou chèche lyen ki mennen nan otè yo.

Aplikasyon lide a

Premye vèsyon an te jis yon paj html sou sit entènèt pèsonèl mwen, kote mwen te mete lyen ak siyati nan yon lis ul. Èske w te tape 20 paj sou yon peryòd de tan, mwen te kòmanse panse ke sa a pa t 'trè efikas epi mwen deside eseye otomatize pwosesis la. Sou stackoverflow, mwen remake ke anpil moun endike sit nan pwofil yo, kidonk mwen te ekri yon analizeur nan php, ki tou senpleman te ale nan pwofil yo, kòmanse ak premye a (adrès sou SO jiska jodi a se tankou sa a: `/users/1` ), ekstrè lyen ki soti nan tag vle a epi ajoute li nan SQLite.

Yo ka rele sa dezyèm vèsyon an: yon koleksyon dè dizèn de milye URL nan yon tab SQLite, ki ranplase lis la estatik nan HTML. Mwen te fè yon rechèch senp sou lis sa a. Paske te gen sèlman URL, Lè sa a, rechèch la te tou senpleman baze sou yo.

Nan etap sa a mwen abandone pwojè a epi retounen nan li apre yon bon bout tan. Nan etap sa a, eksperyans travay mwen te deja plis pase twa ane e mwen te santi ke mwen te kapab fè yon bagay ki pi grav. Anplis de sa, te gen yon gwo dezi metrize relativman nouvo teknoloji.

Vèsyon modèn

Pwojè deplwaye nan Docker, yo te transfere baz done a nan mongoDb, epi pi resamman, yo te ajoute radi, ki nan premye te jis pou kachèt. Youn nan microframeworks PHP yo itilize kòm yon baz.

pwoblèm

Nouvo sit yo ajoute pa yon lòd konsole ki synchrone fè bagay sa yo:

  • Telechaje kontni pa URL
  • Mete yon drapo ki endike si HTTPS te disponib
  • Prezève sans nan sit entènèt la
  • Sous HTML ak headers yo sove nan istwa "indexing".
  • Analize kontni, ekstrè Tit ak Deskripsyon
  • Sove done nan yon koleksyon separe

Sa a te ase tou senpleman magazen sit epi montre yo nan yon lis:

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Men, lide otomatikman endèks, kategorize ak plase tout bagay, kenbe tout bagay ajou, pa t 'anfòm byen nan paradigm sa a. Menm tou senpleman ajoute yon metòd entènèt pou ajoute paj mande kopi kòd ak bloke pou evite potansyèl DDoS.

An jeneral, nan kou, tout bagay ka fè synchronously, ak nan metòd la entènèt ou ka tou senpleman sove URL la pou ke demon nan kolosal fè tout travay yo pou URL yo nan lis la. Men, toujou, menm isit la mo "keu" sijere tèt li. Men, si yon keu aplike, Lè sa a, tout travay yo ka divize epi fè omwen asynchrone.

desizyon

Aplike ke moun kap kriye epi fè yon sistèm ki baze sou evènman pou trete tout travay yo. Apre sa, mwen te vle eseye Redis Streams pou yon tan long.

Sèvi ak kouran Redis nan PHP

Paske Depi kad mwen an pa youn nan twa jeyan Symfony, Laravel, Yii, mwen ta renmen jwenn yon bibliyotèk endepandan. Men, kòm li te tounen soti (nan premye egzamen an), li enposib jwenn bibliyotèk endividyèl ki grav. Tout bagay ki gen rapò ak keu se swa yon pwojè ki soti nan 3 komèt senk ane de sa, oswa se mare nan kad la.

Mwen te tande anpil bagay sou Symfony kòm yon founisè konpozan endividyèl itil, e mwen deja itilize kèk nan yo. Epi tou kèk bagay ki soti nan Laravel ka itilize tou, pou egzanp ORM yo, san prezans nan kad li menm.

symfony/messenger

Premye kandida a imedyatman te sanble ideyal e san okenn dout mwen te enstale li. Men, li te vin pi difisil pou google egzanp itilizasyon deyò Symfony. Ki jan yo rasanble nan yon pakèt klas ak inivèsèl, non san sans, yon otobis pou pase mesaj, e menm sou Redis?

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Dokimantasyon an sou sit ofisyèl la te byen detaye, men inisyalizasyon an te sèlman dekri pou Symfony lè l sèvi avèk YML pi renmen yo ak lòt metòd majik pou ki pa senfonis la. Mwen pa te gen okenn enterè nan pwosesis enstalasyon an tèt li, espesyalman pandan jou ferye yo New Year. Men, mwen te oblije fè sa pou yon tan san atann.

Eseye konnen ki jan yo enstansye yon sistèm lè l sèvi avèk sous Symfony tou se pa travay ki pi trivial pou yon delè sere:

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Apre fouye nan tout bagay sa yo epi eseye fè yon bagay ak men m ', mwen te rive nan konklizyon an ke mwen te fè kèk kalite beki ak deside eseye yon lòt bagay.

eklere / keu

Li te vin parèt ke bibliyotèk sa a te byen mare ak enfrastrikti Laravel la ak yon pakèt lòt depandans, kidonk mwen pa te pase anpil tan sou li: mwen enstale li, gade li, wè depandans yo epi efase li.

yiisoft/yii2-queue

Oke, isit la li te imedyatman sipoze soti nan non an, ankò, yon koneksyon strik nan Yii2. Mwen te oblije sèvi ak bibliyotèk sa a epi li pa t 'mal, men mwen pa t' panse sou lefèt ke li konplètman depann sou Yii2.

Rès la

Tout lòt bagay ke mwen te jwenn sou GitHub yo te enfidèl, demode ak abandone pwojè san zetwal, fouchèt ak yon gwo kantite komèt.

Retounen nan symfony/messenger, detay teknik

Mwen te oblije konnen bibliyotèk sa a epi, apre mwen te pase kèk tan ankò, mwen te kapab. Li te tounen soti ke tout bagay te byen kout ak senp. Pou enstansye otobis la, mwen te fè yon ti faktori, paske... Mwen te sipoze gen plizyè kawotchou ak moun kap okipe yo diferan.

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Jis kèk etap:

  • Nou kreye moun kap okipe mesaj ki ta dwe tou senpleman rele
  • Nou vlope yo nan HandlerDescriptor (klas ki soti nan bibliyotèk la)
  • Nou vlope "Deskriptè" sa yo nan yon egzanp HandlersLocator
  • Ajoute HandlersLocator nan egzanp MessageBus la
  • Nou pase yon seri `SenderInterface` bay SendersLocator, nan ka mwen an ka nan klas `RedisTransport`, ki konfigirasyon nan yon fason evidan.
  • Ajoute SendersLocator nan egzanp MessageBus la

MessageBus gen yon metòd `->dispatch()` ki gade moun kap okipe yo nan HandlersLocator la epi li pase mesaj la ba yo, lè l sèvi avèk `SenderInterface` ki koresponn lan pou voye atravè otobis la (Redis streams).

Nan konfigirasyon veso a (nan ka sa a php-di), tout pake sa a ka konfigirasyon konsa:

        CONTAINER_REDIS_TRANSPORT_SECRET => function (ContainerInterface $c) {
            return new RedisTransport(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
                $c->get(CONTAINER_SERIALIZER))
            ;
        },
        CONTAINER_REDIS_TRANSPORT_LOG => function (ContainerInterface $c) {
            return new RedisTransport(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
                $c->get(CONTAINER_SERIALIZER))
            ;
        },
        CONTAINER_REDIS_STREAM_RECEIVER_SECRET => function (ContainerInterface $c) {
            return new RedisReceiver(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
                $c->get(CONTAINER_SERIALIZER)
            );
        },
        CONTAINER_REDIS_STREAM_RECEIVER_LOG => function (ContainerInterface $c) {
            return new RedisReceiver(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
                $c->get(CONTAINER_SERIALIZER)
            );
        },
        CONTAINER_REDIS_STREAM_BUS => function (ContainerInterface $c) {
            $sendersLocator = new SendersLocator([
                AppMessagesSecretJsonMessages::class => [CONTAINER_REDIS_TRANSPORT_SECRET],
                AppMessagesDaemonLogMessage::class => [CONTAINER_REDIS_TRANSPORT_LOG],
            ], $c);
            $middleware[] = new SendMessageMiddleware($sendersLocator);

            return new MessageBus($middleware);
        },
        CONTAINER_REDIS_STREAM_CONNECTION_SECRET => function (ContainerInterface $c) {
            $host = 'bu-02-redis';
            $port = 6379;
            $dsn = "redis://$host:$port";
            $options = [
                'stream' => 'secret',
                'group' => 'default',
                'consumer' => 'default',
            ];

            return Connection::fromDsn($dsn, $options);
        },
        CONTAINER_REDIS_STREAM_CONNECTION_LOG => function (ContainerInterface $c) {
            $host = 'bu-02-redis';
            $port = 6379;
            $dsn = "redis://$host:$port";
            $options = [
                'stream' => 'log',
                'group' => 'default',
                'consumer' => 'default',
            ];

            return Connection::fromDsn($dsn, $options);
        },

Isit la ou ka wè ke nan SendersLocator nou te asiyen diferan "transpò" pou de mesaj diferan, chak nan yo ki gen koneksyon pwòp li yo ak kouran ki koresponn yo.

Mwen te fè yon pwojè demonstrasyon apa ki demontre yon aplikasyon twa demon ki kominike youn ak lòt lè l sèvi avèk otobis sa a: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

Men, mwen pral montre w ki jan yon konsomatè ka estriktire:

use AppMessagesDaemonLogMessage;
use SymfonyComponentMessengerHandlerHandlerDescriptor;
use SymfonyComponentMessengerHandlerHandlersLocator;
use SymfonyComponentMessengerMessageBus;
use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware;
use SymfonyComponentMessengerMiddlewareSendMessageMiddleware;
use SymfonyComponentMessengerTransportSenderSendersLocator;

require_once __DIR__ . '/../vendor/autoload.php';
/** @var PsrContainerContainerInterface $container */
$container = require_once('config/container.php');

$handlers = [
    DaemonLogMessage::class => [
        new HandlerDescriptor(
            function (DaemonLogMessage $m) {
                error_log('DaemonLogHandler: message handled: / ' . $m->getMessage());
            },
            ['from_transport' => CONTAINER_REDIS_TRANSPORT_LOG]
        )
    ],
];
$middleware = [];
$middleware[] = new HandleMessageMiddleware(new HandlersLocator($handlers));
$sendersLocator = new SendersLocator(['*' => [CONTAINER_REDIS_TRANSPORT_LOG]], $container);
$middleware[] = new SendMessageMiddleware($sendersLocator);

$bus = new MessageBus($middleware);
$receivers = [
    CONTAINER_REDIS_TRANSPORT_LOG => $container->get(CONTAINER_REDIS_STREAM_RECEIVER_LOG),
];
$w = new SymfonyComponentMessengerWorker($receivers, $bus, $container->get(CONTAINER_EVENT_DISPATCHER));
$w->run();

Sèvi ak enfrastrikti sa a nan yon aplikasyon

Lè m te aplike otobis la nan backend mwen an, mwen te separe etap endividyèl ak ansyen kòmandman synchrone a epi m te fè moun k ap okipe yo apa, chak nan yo fè pwòp bagay pa yo.

Tiyo a pou ajoute yon nouvo sit nan baz done a te sanble ak sa a:

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Epi imedyatman apre sa, li te vin pi fasil pou m ajoute nouvo fonksyonalite, pou egzanp, ekstrè ak analize Rss. Paske pwosesis sa a mande tou kontni orijinal la, Lè sa a, reskonsab lyen extracteur RSS, tankou WebsiteIndexHistoryPersistor, abònman nan "Content/HtmlContent" mesaj la, trete li epi pase mesaj la vle sou tiyo li yo pi lwen.

Transfere backend PHP nan otobis Redis streams epi chwazi yon bibliyotèk endepandan

Nan fen a, nou te fini ak plizyè demon, chak nan yo ki kenbe koneksyon sèlman ak resous ki nesesè yo. Pa egzanp yon demon robo gen tout moun kap okipe yo ki mande pou ale nan Entènèt la pou kontni, ak demon an pèsiste kenbe yon koneksyon ak baz done a.

Koulye a, olye pou yo chwazi nan baz done a, id yo mande yo apre ensèsyon pa pèsistan an yo tou senpleman transmèt atravè otobis la bay tout moun kap okipe yo.

Sous: www.habr.com

Add nouvo kòmantè