PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

hitzaurrea

Nire webgunea, zaletasun gisa zuzentzen dudana, hasierako orrialde interesgarriak eta gune pertsonalak hartzeko diseinatuta dago. Gai hau nire programazio-bidaiaren hasieran hasi zen interesatzen; momentu horretan, bere buruaz, zaletasunez eta proiektuez idazten duten profesional handiak aurkitzeak liluratuta nengoen. Horiek neuk ezagutzeko ohiturak gaur arte jarraitzen du: ia gune komertzialetan eta ez oso komertzialetan, oin-oinean begiratzen jarraitzen dut egileentzako esteken bila.

Ideia gauzatzea

Lehenengo bertsioa nire webgune pertsonaleko html orri bat besterik ez zen, non sinaduradun estekak ul zerrenda batean jartzen nituen. Denbora tarte batean 20 orrialde idatzita, hau oso eraginkorra ez zela pentsatzen hasi eta prozesua automatizatzen saiatzea erabaki nuen. Stackoverflow-en, jende askok bere profilean guneak adierazten dituela ohartu nintzen, beraz, php-n analizatzaile bat idatzi nuen, profiletatik besterik gabe pasa zena, lehenengotik hasita (SO-n gaur egunera arteko helbideak honelakoak dira: `/users/1` ), nahi duzun etiketatik estekak atera eta SQLite-n gehitu ditu.

Hau bigarren bertsioa dei daiteke: SQLite taula batean milaka URLren bilduma bat, HTMLn zerrenda estatikoa ordezkatu zuena. Zerrenda honetan bilaketa sinple bat egin nuen. Zeren URLak bakarrik zeuden, orduan bilaketa haietan oinarritzen zen.

Fase honetan proiektua bertan behera utzi eta denbora luze baten ondoren bertara itzuli nintzen. Etapa honetan, nire lan-esperientzia jada hiru urte baino gehiagokoa zen eta zerbait serioagoa egin nezakeela sentitu nuen. Horrez gain, teknologia berri samarrak menperatzeko gogo handia zegoen.

Bertsio modernoa

Proiektu Docker-en zabalduta, datu-basea mongoDb-ra transferitu zen, eta azkenaldian, errefautxoa gehitu zen, hasieran cachean gordetzeko besterik ez zena. PHP mikroesparruetako bat oinarri gisa erabiltzen da.

arazoa

Gune berriak sinkronoki honako hau egiten duen kontsolaren komando baten bidez gehitzen dira:

  • URLaren arabera deskargatzen du edukia
  • HTTPS erabilgarri zegoen ala ez adierazten duen bandera ezartzen du
  • Webgunearen funtsa gordetzen du
  • Iturburu HTMLa eta goiburuak "indexatzeko" historian gordetzen dira
  • Edukia aztertzen du, Izenburua eta Deskribapena ateratzen ditu
  • Datuak aparteko bilduma batean gordetzen ditu

Hau nahikoa zen guneak gordetzeko eta zerrenda batean bistaratzeko:

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Baina dena automatikoki indexatu, sailkatu eta sailkatzeko ideia, dena eguneratuta edukitzea, ez zegoen ondo paradigma honetan. Nahiz eta orriak gehitzeko web-metodo bat gehitzeak kodea bikoiztu eta blokeatu behar izan zuen DDoS potentzialak saihesteko.

Orokorrean, noski, dena modu sinkronikoan egin daiteke, eta web-metodoan URLa besterik gabe gorde dezakezu, daemon munstroak zerrendako URLen zeregin guztiak egin ditzan. Baina hala ere, hemen ere "ilara" hitzak bere burua iradokitzen du. Eta ilara bat ezartzen bada, zeregin guztiak zatitu eta gutxienez modu asinkronoan egin daitezke.

Erabaki

Ilarak ezartzea eta zeregin guztiak prozesatzeko gertaerak gidatutako sistema bat egin. Eta aspalditik nuen Redis Streams probatu nahi.

Redis korronteak PHPn erabiliz

Zeren Nire esparrua Symfony, Laravel, Yii hiru erraldoietako bat ez denez, liburutegi independente bat aurkitu nahiko nuke. Baina, ondorioztatu denez (lehen azterketan), ezinezkoa da banakako liburutegi serioak aurkitzea. Ilarekin zerikusia duen guztia duela bost urteko 3 konpromezuetako proiektu bat da, edo esparruari lotuta dago.

Asko entzun dut Symfonyri buruz banakako osagai erabilgarrien hornitzaile gisa, eta dagoeneko erabiltzen ditut horietako batzuk. Eta, gainera, Laravel-eko gauza batzuk ere erabil daitezke, beren ORM adibidez, markoa bera egon gabe.

symfony/messenger

Lehen hautagaia berehala iruditu zitzaidan aproposa eta dudarik gabe instalatu nuen. Baina zailagoa izan da Symfony-tik kanpo erabilera-adibide batzuk bilatzea. Nola muntatu izen unibertsalak, zentzurik gabekoak, mezuak pasatzeko autobusa eta baita Redis-en klase mordoa?

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Webgune ofizialeko dokumentazioa nahiko zehatza zen, baina hasieratzea Symfonyrentzat bakarrik deskribatu zen bere YML gogokoena eta sinfonista ez zenentzako beste metodo magikoak erabiliz. Ez nuen interesik instalatzeko prozesuan bertan, batez ere Urte Berriko oporretan. Baina hori egin behar izan nuen ustekabeko denbora luzez.

Symfony iturriak erabiliz sistema bat instantziatzen saiatzea ere ez da epe estu baterako zereginik hutsunea:

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Honetan guztian sakondu eta eskuekin zerbait egiten saiatu ondoren, makulu mota batzuk egiten ari nintzela ondorioztatu eta beste zerbait probatzea erabaki nuen.

argiztatua/ilara

Liburutegi hau Laravel azpiegiturari eta beste menpekotasun mordo bati oso lotuta zegoela ikusi zen, beraz, ez nuen denbora askorik eman: instalatu, begiratu, mendekotasunak ikusi eta ezabatu egin nuen.

yiisoft/yii2-ilara

Beno, hemen berehala hartu zen izenetik, berriro ere, Yii2-rekin lotura zorrotza. Liburutegi hau erabili behar nuen eta ez zegoen gaizki, baina ez nuen pentsatu Yii2-ren guztiz menpe dagoenik.

Gainerakoak

GitHub-en aurkitu nuen beste guztia proiektu ez fidagarriak, zaharkituak eta abandonatuak ziren izarrik, sardexkarik eta konpromiso kopuru handirik gabe.

Itzuli symfony/messengerra, xehetasun teknikoak

Liburutegi hau asmatu behar nuen eta, denbora gehiago eman ondoren, lortu nuen. Dena nahiko zehatza eta sinplea zela ikusi zen. Autobusa instantziatzeko, fabrika txiki bat egin nuen, zeren... Hainbat pneumatiko eta kudeatzaile ezberdinekin izan behar nituen.

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Urrats batzuk besterik ez:

  • Mezu-kudeatzaileak sortzen ditugu, besterik gabe deitu behar direnak
  • HandlerDescriptor-en biltzen ditugu (liburutegiko klasea)
  • "Deskribatzaile" hauek HandlersLocator instantzia batean biltzen ditugu
  • HandlersLocator gehitzea MessageBus instantziara
  • `SenderInterface` SendersLocator-era pasatzen dugu, nire kasuan `RedisTransport` klaseen kasuak, modu ageriko batean konfiguratuta daudenak.
  • SendersLocator gehitzea MessageBus instantziara

MessageBus-ek `->dispatch()` metodo bat du, HandlersLocator-en kudeatzaile egokiak bilatzen dituena eta mezua haiei pasatzen diena, dagokion `SenderInterface' erabiliz, autobusaren bidez bidaltzeko (Redis korronteak).

Edukiontziaren konfigurazioan (kasu honetan php-di), sorta osoa honela konfigura daiteke:

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

Hemen ikus dezakezu SendersLocator-en bi mezu ezberdinentzako "garraio" desberdinak esleitu ditugula, bakoitzak dagozkion korronteekin bere konexioa duela.

Demo-proiektu bereizi bat egin nuen elkarren artean komunikatzen diren hiru deabruren aplikazioa frogatuz honako autobus hau erabiliz: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

Baina kontsumitzailea nola egituratu daitekeen erakutsiko dizut:

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

Azpiegitura hau aplikazio batean erabiltzea

Nire backend-ean autobusa ezarrita, komando sinkrono zaharretik etapa indibidualak bereizi eta kudeatzaile bereiziak egin nituen, bakoitzak berea egiten du.

Datu-basean gune berri bat gehitzeko kanalizazioa honelakoa zen:

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Eta berehala, askoz errazagoa egin zitzaidan funtzionalitate berriak gehitzea, adibidez, Rss ateratzea eta analizatzea. Zeren prozesu honek jatorrizko edukia ere behar du, eta, ondoren, RSS estekak erauzteko kudeatzaileak, WebsiteIndexHistoryPersistorrek bezala, "Edukia/HtmlEdukia" mezura harpidetzen du, prozesatu eta nahi den mezua bere kanalizazioan zehar pasatzen du.

PHP backend-a Redis korronteen busera transferitzea eta framework-a independentea den liburutegia aukeratzea

Azkenean, hainbat deabrurekin amaitu genuen, eta horietako bakoitzak beharrezko baliabideekin soilik mantentzen ditu konexioak. Adibidez deabru bat crawlers edukia lortzeko Internetera joatea eskatzen duten kudeatzaile guztiak eta deabrua ditu iraun datu-baserako konexioa dauka.

Orain, datu-basetik hautatu beharrean, iraunkorrak txertatu ondoren beharrezkoak diren IDak bus bidez transmititzen zaizkie kudeatzaile interesdun guztiei.

Iturria: www.habr.com

Gehitu iruzkin berria