Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Rhagair

Mae fy ngwefan, yr wyf yn ei rhedeg fel hobi, wedi'i chynllunio i gynnal tudalennau cartref diddorol a gwefannau personol. Dechreuodd y pwnc hwn fy niddori ar ddechrau fy siwrnai raglennu; ar y foment honno cefais fy swyno gan ddod o hyd i weithwyr proffesiynol gwych sy'n ysgrifennu amdanynt eu hunain, eu hobïau a'u prosiectau. Erys yr arferiad o’u darganfod i mi fy hun hyd heddiw: ar bron bob safle masnachol ac nid masnachol iawn, rwy’n parhau i edrych yn y troedyn i chwilio am ddolenni i’r awduron.

Gweithredu'r syniad

Dim ond tudalen html oedd y fersiwn gyntaf ar fy ngwefan bersonol, lle rhoddais ddolenni gyda llofnodion i mewn i restr ul. Wedi teipio 20 tudalen dros gyfnod o amser, dechreuais feddwl nad oedd hyn yn effeithiol iawn a phenderfynais geisio awtomeiddio’r broses. Ar stackoverflow, sylwais fod llawer o bobl yn nodi gwefannau yn eu proffiliau, felly ysgrifennais ddosraniad yn php, a aeth trwy'r proffiliau yn syml, gan ddechrau gyda'r cyntaf (mae'r cyfeiriadau ar SO hyd heddiw fel hyn: `/users/1` ), wedi tynnu dolenni o'r tag a ddymunir a'i ychwanegu yn SQLite.

Gellir galw hwn yn ail fersiwn: casgliad o ddegau o filoedd o URLau mewn tabl SQLite, a ddisodlodd y rhestr statig yn html. Fe wnes i chwiliad syml ar y rhestr hon. Achos dim ond URLs oedd, yna roedd y chwiliad yn syml yn seiliedig arnynt.

Ar y cam hwn, gadewais y prosiect a dychwelyd ato ar ôl amser hir. Ar y cam hwn, roedd fy mhrofiad gwaith eisoes yn fwy na thair blynedd ac roeddwn yn teimlo y gallwn wneud rhywbeth mwy difrifol. Yn ogystal, roedd awydd mawr i feistroli technolegau cymharol newydd.

Fersiwn modern

Prosiect Wedi'i ddefnyddio yn Docker, trosglwyddwyd y gronfa ddata i mongoDb, ac yn fwy diweddar, ychwanegwyd radish, a oedd ar y dechrau ar gyfer caching yn unig. Defnyddir un o'r microfframweithiau PHP fel sail.

problem

Mae gwefannau newydd yn cael eu hychwanegu gan orchymyn consol sy'n gwneud y canlynol yn gydamserol:

  • Yn lawrlwytho cynnwys yn ôl URL
  • Yn gosod baner yn nodi a oedd HTTPS ar gael
  • Yn cadw hanfod y wefan
  • Mae'r ffynhonnell HTML a'r penawdau yn cael eu cadw yn yr hanes “mynegeio”.
  • Dosrannu cynnwys, detholiadau Teitl a Disgrifiad
  • Yn cadw data i gasgliad ar wahân

Roedd hyn yn ddigon i storio gwefannau a'u harddangos mewn rhestr:

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Ond nid oedd y syniad o fynegeio, categoreiddio a graddio popeth yn awtomatig, gan gadw popeth yn gyfredol, yn cyd-fynd yn dda â'r patrwm hwn. Roedd hyd yn oed ychwanegu dull gwe i ychwanegu tudalennau yn gofyn am ddyblygu cod a blocio er mwyn osgoi DDoS posibl.

Yn gyffredinol, wrth gwrs, gellir gwneud popeth yn gydamserol, ac yn y dull gwe gallwch arbed yr URL fel bod yr ellyll gwrthun yn cyflawni'r holl dasgau ar gyfer yr URLau o'r rhestr. Ond o hyd, hyd yn oed yma mae'r gair “ciw” yn awgrymu ei hun. Ac os gweithredir ciw, yna gellir rhannu'r holl dasgau a'u perfformio yn anghydamserol o leiaf.

penderfyniad

Gweithredu ciwiau a gwneud system a yrrir gan ddigwyddiadau ar gyfer prosesu pob tasg. Ac rydw i wedi bod eisiau rhoi cynnig ar Redis Streams ers amser maith.

Defnyddio ffrydiau Redis yn PHP

Achos Gan nad yw fy fframwaith yn un o'r tri cawr Symfony, Laravel, Yii, hoffwn ddod o hyd i lyfrgell annibynnol. Ond, fel y digwyddodd (ar yr archwiliad cyntaf), mae'n amhosibl dod o hyd i lyfrgelloedd difrifol unigol. Mae popeth sy'n ymwneud â chiwiau naill ai'n brosiect o 3 ymrwymiad bum mlynedd yn ôl, neu'n gysylltiedig â'r fframwaith.

Rwyf wedi clywed llawer am Symfony fel cyflenwr cydrannau defnyddiol unigol, ac rwyf eisoes yn defnyddio rhai ohonynt. A hefyd gellir defnyddio rhai pethau o Laravel hefyd, er enghraifft eu ORM, heb bresenoldeb y fframwaith ei hun.

symffoni/negesydd

Roedd yr ymgeisydd cyntaf yn ymddangos yn ddelfrydol ar unwaith a heb unrhyw amheuaeth fe wnes i ei osod. Ond daeth yn anoddach google enghreifftiau o ddefnydd y tu allan i Symfony. Sut i ymgynnull bws ar gyfer trosglwyddo negeseuon o griw o ddosbarthiadau gydag enwau cyffredinol, diystyr, a hyd yn oed ar Redis?

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Roedd y ddogfennaeth ar y safle swyddogol yn eithaf manwl, ond dim ond ar gyfer Symfony y disgrifiwyd y cychwyniad gan ddefnyddio eu hoff YML a dulliau hud eraill ar gyfer y rhai nad ydynt yn symffonydd. Nid oedd gennyf unrhyw ddiddordeb yn y broses osod ei hun, yn enwedig yn ystod gwyliau'r Flwyddyn Newydd. Ond bu'n rhaid i mi wneud hyn am gyfnod annisgwyl o hir.

Nid yw ceisio darganfod sut i gychwyn system gan ddefnyddio ffynonellau Symfony ychwaith y dasg fwyaf dibwys ar gyfer terfyn amser tynn:

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Ar ôl ymchwilio i hyn i gyd a cheisio gwneud rhywbeth gyda fy nwylo, deuthum i'r casgliad fy mod yn gwneud rhyw fath o faglau a phenderfynais roi cynnig ar rywbeth arall.

goleuedig/ciw

Daeth i'r amlwg bod y llyfrgell hon wedi'i chlymu'n dynn â seilwaith Laravel a llawer o ddibyniaethau eraill, felly ni threuliais lawer o amser arno: fe'i gosodais, edrychais arno, gwelais y dibyniaethau a'i ddileu.

yiisoft/yii2-ciw

Wel, yma y tybiwyd ar unwaith oddiwrth yr enw, eto, gysylltiad caeth ag Yii2. Roedd yn rhaid i mi ddefnyddio'r llyfrgell hon ac nid oedd yn ddrwg, ond ni feddyliais am y ffaith ei fod yn dibynnu'n llwyr ar Yii2.

Y gweddill

Roedd popeth arall a ddarganfyddais ar GitHub yn brosiectau annibynadwy, hen ffasiwn ac wedi'u gadael heb sêr, ffyrc a nifer fawr o ymrwymiadau.

Dychwelyd i symffoni/negesydd, manylion technegol

Roedd yn rhaid i mi ddarganfod y llyfrgell hon ac, ar ôl treulio mwy o amser, roeddwn i'n gallu. Mae'n troi allan bod popeth yn eithaf cryno a syml. I gychwyn y bws, fe wnes i ffatri fach, oherwydd ... Roeddwn i fod i gael sawl teiars a gyda thrinwyr gwahanol.

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Dim ond ychydig o gamau:

  • Rydym yn creu trinwyr negeseuon y dylid eu galw'n syml
  • Rydyn ni'n eu lapio mewn HandlerDescriptor (dosbarth o'r llyfrgell)
  • Rydym yn lapio'r “Disgrifyddion” hyn mewn enghraifft HandlersLocator
  • Ychwanegu HandlersLocator at yr enghraifft MessageBus
  • Rydyn ni'n trosglwyddo set o `SenderInterface` i SendersLocator, yn fy achos i, achosion o ddosbarthiadau `RedisTransport`, sydd wedi'u ffurfweddu mewn ffordd amlwg
  • Ychwanegu SendersLocator at yr enghraifft MessageBus

Mae gan MessageBus ddull `->dispatch()` sy'n edrych i fyny'r trinwyr priodol yn y HandlersLocator ac yn trosglwyddo'r neges iddynt, gan ddefnyddio'r `SenderInterface` cyfatebol i'w hanfon ar y bws (nentydd Redis).

Yn y cyfluniad cynhwysydd (php-di yn yr achos hwn), gellir ffurfweddu'r bwndel cyfan hwn fel hyn:

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

Yma gallwch weld ein bod yn SendersLocator wedi neilltuo “cludiant” gwahanol ar gyfer dwy neges wahanol, ac mae gan bob un ohonynt ei gysylltiad ei hun â'r ffrydiau cyfatebol.

Gwneuthum brosiect demo ar wahân yn arddangos cymhwysiad o dri daemon yn cyfathrebu â'i gilydd gan ddefnyddio'r bws canlynol: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

Ond byddaf yn dangos i chi sut y gellir strwythuro defnyddiwr:

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

Defnyddio'r seilwaith hwn mewn cais

Ar ôl gweithredu'r bws yn fy nghefn, gwahanais gamau unigol o'r hen orchymyn cydamserol a gwneud trinwyr ar wahân, pob un ohonynt yn gwneud eu peth eu hunain.

Roedd yr arfaeth ar gyfer ychwanegu safle newydd at y gronfa ddata yn edrych fel hyn:

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Ac yn syth ar ôl hynny, daeth yn llawer haws i mi ychwanegu ymarferoldeb newydd, er enghraifft, echdynnu a dosrannu Rss. Achos mae'r broses hon hefyd yn gofyn am y cynnwys gwreiddiol, yna mae'r triniwr echdynnu cyswllt RSS, fel WebsiteIndexHistoryPersistor, yn tanysgrifio i'r neges “Cynnwys / HtmlContent”, yn ei phrosesu ac yn trosglwyddo'r neges a ddymunir ar hyd ei biblinell ymhellach.

Trosglwyddo'r backend PHP i fws ffrydiau Redis a dewis llyfrgell annibynnol ar fframwaith

Yn y diwedd, daeth sawl daemon gennym i ben, ac mae pob un ohonynt yn cynnal cysylltiadau â'r adnoddau angenrheidiol yn unig. Er enghraifft cythraul crawlers yn cynnwys yr holl drinwyr sydd angen mynd i'r Rhyngrwyd ar gyfer cynnwys, a'r ellyll dyfal yn dal cysylltiad â'r gronfa ddata.

Nawr, yn lle dewis o'r gronfa ddata, mae'r ids gofynnol ar ôl eu mewnosod gan y persister yn cael eu trosglwyddo'n syml ar y bws i'r holl drinwyr sydd â diddordeb.

Ffynhonnell: hab.com

Ychwanegu sylw