Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Formáli

Vefsíðan mín, sem ég rek sem áhugamál, er hönnuð til að hýsa áhugaverðar heimasíður og persónulegar síður. Þetta efni byrjaði að vekja áhuga minn strax í upphafi dagskrárferðar minnar; á þeirri stundu heillaðist ég af því að finna frábært fagfólk sem skrifar um sjálfan sig, áhugamál sín og verkefni. Venjan að uppgötva þá fyrir sjálfan mig er enn þann dag í dag: á næstum öllum auglýsingum og ekki mjög auglýsingum síðum, held ég áfram að líta í fótinn í leit að tenglum á höfundana.

Framkvæmd hugmyndarinnar

Fyrsta útgáfan var bara html síða á persónulegu vefsíðunni minni, þar sem ég setti tengla með undirskriftum inn á ul lista. Eftir að hafa slegið inn 20 síður á tímabili fór ég að halda að þetta væri ekki mjög áhrifaríkt og ákvað að reyna að gera ferlið sjálfvirkt. Á stackoverflow tók ég eftir því að margir gefa til kynna síður í prófílunum sínum, svo ég skrifaði þáttara í php, sem fór einfaldlega í gegnum prófílana, byrjaði á þeim fyrsta (heimilisföng á SO til þessa dags eru svona: `/notendur/1` ), dró út tengla úr merkinu sem óskað er eftir og bætti því við í SQLite.

Þetta má kalla seinni útgáfuna: safn tugþúsunda vefslóða í SQLite töflu, sem kom í stað kyrrstöðulistans í HTML. Ég gerði einfalda leit á þessum lista. Vegna þess að það voru bara vefslóðir, þá var leitin einfaldlega byggð á þeim.

Á þessu stigi yfirgaf ég verkefnið og fór aftur í það eftir langan tíma. Á þessu stigi var starfsreynsla mín þegar orðin meira en þrjú ár og ég fann að ég gæti gert eitthvað alvarlegra. Auk þess var mikill vilji til að ná tökum á tiltölulega nýrri tækni.

Nútíma útgáfa

Project notaður í Docker, gagnagrunnurinn var fluttur yfir í mongoDb og nýlega var radish bætt við, sem fyrst var bara til að vista í skyndiminni. Eitt af PHP örrammanum er notað sem grunnur.

vandamálið

Nýjum síðum er bætt við með stjórnborðsskipun sem samstillt gerir eftirfarandi:

  • Niðurhal efni eftir slóð
  • Setur fána sem gefur til kynna hvort HTTPS hafi verið tiltækt
  • Varðveitir kjarna vefsíðunnar
  • Uppruna HTML og hausarnir eru vistaðir í „skráning“ sögunni
  • Þýðir innihald, dregur út titil og lýsingu
  • Vistar gögn í sérstakt safn

Þetta var nóg til að einfaldlega geyma síður og birta þær á lista:

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

En hugmyndin um að flokka, flokka og raða öllu sjálfkrafa, halda öllu uppfærðu, passaði ekki vel inn í þessa hugmyndafræði. Jafnvel einfaldlega að bæta við vefaðferð til að bæta við síðum þurfti afritun kóða og loka til að forðast hugsanlega DDoS.

Almennt séð er auðvitað hægt að gera allt samstillt og í vefaðferðinni er einfaldlega hægt að vista slóðina þannig að voðalegi púkinn framkvæmi öll verkefnin fyrir slóðirnar af listanum. En samt, jafnvel hér gefur orðið „röð“ til kynna. Og ef biðröð er útfærð, þá er hægt að skipta öllum verkum og framkvæma að minnsta kosti ósamstillt.

ákvörðun

Innleiða biðraðir og búa til atburðadrifið kerfi til að vinna úr öllum verkefnum. Og mig hefur lengi langað til að prófa Redis Streams.

Notkun Redis strauma í PHP

Vegna þess að Þar sem umgjörðin mín er ekki einn af þremur risunum Symfony, Laravel, Yii, langar mig að finna sjálfstætt bókasafn. En eins og það kom í ljós (við fyrstu athugun) er ómögulegt að finna einstök alvarleg bókasöfn. Allt sem tengist biðröðum er annað hvort verkefni frá 3 skuldbindingum fyrir fimm árum eða er bundið við rammann.

Ég hef heyrt mikið um Symfony sem birgir einstakra gagnlegra íhluta og ég nota nú þegar suma þeirra. Og einnig er hægt að nota suma hluti frá Laravel, til dæmis ORM þeirra, án þess að umgjörðin sjálf sé til staðar.

sinfónía/boðberi

Fyrsti frambjóðandinn virtist strax tilvalinn og án nokkurs vafa setti ég það upp. En það reyndist erfiðara að gúgla dæmi um notkun utan Symfony. Hvernig á að setja saman úr fullt af bekkjum með alhliða, tilgangslausum nöfnum, rútu til að senda skilaboð og jafnvel á Redis?

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Skjölin á opinberu síðunni voru nokkuð ítarleg, en frumstillingunni var aðeins lýst fyrir Symfony með því að nota uppáhalds YML þeirra og aðrar töfraaðferðir fyrir þá sem ekki eru sinfónleikarar. Ég hafði engan áhuga á uppsetningarferlinu sjálfu, sérstaklega á nýársfríinu. En ég þurfti að gera þetta óvænt lengi.

Að reyna að finna út hvernig á að stofna kerfi með Symfony heimildum er heldur ekki léttvægasta verkefnið fyrir stuttan frest:

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Eftir að hafa kafað ofan í þetta allt saman og reynt að gera eitthvað með höndunum komst ég að þeirri niðurstöðu að ég væri að gera einhverja hækju og ákvað að prófa eitthvað annað.

upplýst/biðröð

Það kom í ljós að þetta bókasafn var þétt tengt Laravel innviðum og fullt af öðrum ósjálfstæðum, svo ég eyddi ekki miklum tíma í það: ég setti það upp, skoðaði það, sá ósjálfstæðin og eyddi því.

yiisoft/yii2-röð

Jæja, hér var strax gert ráð fyrir af nafninu, aftur, ströng tenging við Yii2. Ég þurfti að nota þetta bókasafn og það var ekki slæmt, en ég hugsaði ekki um þá staðreynd að það fer algjörlega eftir Yii2.

Restin

Allt annað sem ég fann á GitHub voru óáreiðanleg, úrelt og yfirgefin verkefni án stjarna, gaffla og fjölda skuldbindinga.

Fara aftur í symfony/messenger, tæknilegar upplýsingar

Ég þurfti að finna út þetta bókasafn og eftir að hafa eytt meiri tíma gat ég það. Í ljós kom að allt var frekar hnitmiðað og einfalt. Til að stofna rútuna bjó ég til litla verksmiðju vegna þess að... Ég átti að vera með nokkur dekk og með mismunandi stýrimenn.

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Bara nokkur skref:

  • Við búum til skilaboðastjórnun sem ætti að vera einfaldlega hægt að hringja í
  • Við vefjum þeim inn í HandlerDescriptor (bekkurinn frá bókasafninu)
  • Við vefjum þessum „lýsingum“ inn í HandlersLocator dæmi
  • Bætir HandlersLocator við MessageBus tilvikið
  • Við sendum sett af `SenderInterface` til SendersLocator, í mínu tilviki tilvik af `RedisTransport` flokkum, sem eru stilltir á augljósan hátt
  • Bætir SendersLocator við MessageBus tilvikið

MessageBus er með `->dispatch()` aðferð sem flettir upp viðeigandi meðferðaraðilum í HandlersLocator og sendir skilaboðin til þeirra með því að nota samsvarandi `SenderInterface` til að senda í gegnum strætó (Redis straumar).

Í gámastillingunni (í þessu tilfelli php-di) er hægt að stilla allan pakkann svona:

        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);
        },

Hér geturðu séð að í SendersLocator höfum við úthlutað mismunandi „flutningum“ fyrir tvö mismunandi skilaboð, sem hvert um sig hefur sína tengingu við samsvarandi strauma.

Ég gerði sérstakt kynningarverkefni sem sýndi notkun þriggja púka sem eiga samskipti sín á milli með því að nota eftirfarandi rútu: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

En ég skal sýna þér hvernig hægt er að byggja upp neytanda:

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();

Notkun þessa innviða í forriti

Eftir að hafa innleitt rútuna í bakendanum mínum, skildi ég einstök stig frá gömlu samstilltu skipuninni og bjó til aðskilda meðhöndlun, sem hver og einn gerir sitt.

Leiðsla til að bæta nýrri síðu við gagnagrunninn leit svona út:

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Og strax eftir það varð það miklu auðveldara fyrir mig að bæta við nýjum virkni, til dæmis að draga út og flokka Rss. Vegna þess að þetta ferli krefst einnig upprunalega innihaldsins, þá gerist RSS-tenglaútdráttarstjórinn, eins og WebsiteIndexHistoryPersistor, áskrifandi að „Content/HtmlContent“ skilaboðunum, vinnur úr þeim og sendir viðkomandi skilaboð áfram með leiðslunni.

Að flytja PHP bakendann yfir í Redis straumstrætuna og velja rammaóháð bókasafn

Á endanum enduðum við með nokkra púka, sem hver um sig heldur aðeins tengingum við nauðsynlegar auðlindir. Til dæmis púki crawlers inniheldur alla meðhöndlunina sem krefjast þess að fara á internetið fyrir efni, og púkann viðvarandi heldur tengingu við gagnagrunninn.

Nú, í stað þess að velja úr gagnagrunninum, eru nauðsynleg auðkenni eftir innsetningu af persister einfaldlega send í gegnum strætó til allra áhugasamra umsjónarmanna.

Heimild: www.habr.com

Bæta við athugasemd