Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Pambuka

Situsku, sing daklakoni minangka hobi, ditujokake kanggo nyimpen kaca ngarep lan situs pribadi sing menarik. Topik iki dadi menarik kanggo kula ing awal dalan ing program, ing wektu iku aku kesengsem nemokake profesional gedhe sing nulis bab piyambak, hobi lan proyèk. Kebiasaan kanggo nemokake dhewe saiki isih ana: ing meh kabeh situs komersial lan ora komersial, aku terus nggoleki footer kanggo nggoleki tautan menyang penulis.

Implementasi gagasan

Versi pisanan mung minangka kaca html ing situs pribadiku, ing ngendi aku sijine pranala karo teken ing ul-daftar. Sawise ngumpulake babagan 20 kaca saka wektu, aku wiwit mikir yen iki ora efektif banget lan mutusake kanggo nyoba ngotomatisasi proses kasebut. Ing stackoverflow, aku weruh yen akeh wong sing nuduhake situs ing profil, mula aku nulis parser ing php sing mung ngliwati profil, diwiwiti kanthi sing pisanan (alamat ing SO nganti saiki katon kaya iki: `/users/1`), ngekstrak pranala saka tag sing dibutuhake lan dilebokake ing SQLite.

Iki bisa diarani versi kapindho: koleksi sepuluh ewu URL ing tabel SQLite, sing ngganti dhaptar statis ing html. Aku nggawe panelusuran prasaja ing dhaftar iki. Amarga mung ana URL, telusuran mung ana.

Ing tataran iki aku nilar project lan bali menyang sawise dangu. Ing tahap iki pengalaman kerjaku wis luwih saka telung taun lan aku rumangsa bisa nindakake sing luwih serius. Kajaba iku, ana kepinginan gedhe kanggo nguwasani teknologi sing relatif anyar kanggo aku.

Versi modern

Proyek kasebut disebarake ing docker, database wis ditransfer kanggo mongoDb, lan relatif anyar, redis wis ditambahake, kang pisanan mung kanggo caching. Salah sawijining microframework PHP digunakake minangka basis.

masalah

Situs anyar ditambahake dening printah console sing sinkron nindakake ing ngisor iki:

  • Ngundhuh konten kanthi URL
  • Nyetel gendera sing nuduhake manawa HTTPS kasedhiya
  • Ngreksa inti saka website
  • HTML lan header asli disimpen ing riwayat "indeksasi".
  • Parses isi, extract Judhul lan Deskripsi
  • Nyimpen data ing koleksi kapisah

Iki cukup kanggo nyimpen situs lan nampilake ing dhaptar:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Nanging ide kanthi otomatis ngindeks, ngategorikake, lan menehi peringkat kabeh, supaya kabeh tetep anyar, ora cocog karo paradigma iki. Malah mung nambahake cara web kanggo nambahake kaca sing dibutuhake duplikasi kode lan pamblokiran kanggo nyegah DDoS potensial.

Umumé, mesthi, kabeh bisa rampung bebarengan, lan ing cara web, mung nyimpen URL supaya setan monstrous bisa nindakake kabeh tugas kanggo URL saka dhaftar. Nanging malah ing kene, tembung "antrean" teka ing pikiran. Lan yen sampeyan nindakake antrian, sampeyan bisa mbagi kabeh tugas lan nindakake paling ora sinkron.

kaputusan

Ngleksanakake antrian lan nggawe sistem acara-mimpin kanggo proses kabeh tugas. Lan aku wis suwe pengin nyoba Redis Streams.

Nggunakake Redis Streams ing PHP

Amarga kerangkaku dudu salah siji saka telung raksasa Symfony, Laravel, Yii, aku pengin golek perpustakaan mandiri. Nanging, minangka ternyata (ing kawitan marketing) - iku mokal kanggo nemokake perpustakaan serius kapisah. Kabeh sing ana gandhengane karo antrian yaiku proyek saka 3 sing ditindakake limang taun kepungkur, utawa diikat karo kerangka kasebut.

Aku wis krungu bab Symfony minangka panyedhiya sawetara komponen migunani, lan aku wis nggunakake sawetara wong. Lan uga sawetara bab saka Laravel bisa digunakake, contone ORM sing, tanpa ngarsane framework dhewe.

symfony / utusan

Calon pisanan langsung katon becik lan aku nginstal tanpa mangu-mangu. Nanging conto googling panggunaan ing njaba Symfony dadi luwih angel. Kepiye carane ngumpulake bis pesen saka pirang-pirang kelas kanthi jeneng universal, tanpa arti, lan ing Redis?

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Dokumentasi ing situs resmi cukup rinci, nanging initialization diterangake mung kanggo Symfony nggunakake YML kinasih lan cara gaib liyane kanggo non-symphonist. Aku ora kapentingan ing proses instalasi dhewe, utamané sak preian Taun Anyar. Nanging aku kudu nindakake lan ora dikarepke kanggo dangu.

Nyoba kanggo mangerteni carane instantiate sistem nggunakake sumber Symfony uga dudu tugas sing paling sepele kanggo tenggat wektu sing ketat:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Sawise poking ing kabeh iki lan nyoba kanggo nindakake soko karo tangan, Aku teka menyang kesimpulan sing aku nggunakake sawetara jenis crutches lan mutusaké kanggo nyoba mergo.

madhangi / antrian

Ternyata perpustakaan iki diikat banget karo infrastruktur Laravel lan akeh dependensi liyane, mula aku ora ngentekake wektu akeh: Aku nginstal, ndeleng, ndeleng dependensi, lan mbusak.

yiisoft / yii2-antrean

Inggih, ing kene langsung dianggep saka jeneng, maneh ikatan kaku kanggo Yii2. Aku kudu nggunakake perpustakaan iki lan iku ora ala, nanging aku ora mikir sing rampung gumantung ing Yii2.

Liyane

Kabeh liyane sing aku temokake ing GitHub ora bisa dipercaya, ketinggalan jaman, lan ditinggalake tanpa lintang, garpu, utawa akeh komitmen.

Bali menyang symfony / messenger, rincian teknis

Aku kudu ngerteni perpustakaan iki lan sawise mbuwang sawetara wektu aku bisa. Ternyata kabeh iku cukup ringkes lan prasaja. Kanggo instantiating bis aku nggawe pabrik cilik, amarga aku nganggep yen aku bakal duwe sawetara bus karo handler beda.

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Mung sawetara langkah:

  • Nggawe panangan pesen sing mung bisa ditelpon
  • Kita mbungkus ing HandlerDescriptor (kelas saka perpustakaan)
  • Kita mbungkus "Deskriptor" iki ing conto HandlersLocator
  • Tambah HandlersLocator kanggo MessageBus conto
  • Kita ngirim set `SenderInterface` menyang SendersLocator, ing kasusku, kelas `RedisTransport`, sing dikonfigurasi kanthi jelas.
  • Tambah SendersLocator menyang MessageBus instance

MessageBus nduweni cara `-> dispatch ()` sing nggoleki pawang sing cocog ing HandlersLocator lan ngirim pesen kasebut menyang wong-wong mau nggunakake `SenderInterface` sing cocok kanggo ngirim liwat bis (Redis streams).

Ing konfigurasi wadhah (ing kasus iki php-di) bundel iki bisa dikonfigurasi kaya iki:

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

Ing kene sampeyan bisa ndeleng manawa ing SendersLocator kita menehi "transportasi" sing beda kanggo rong pesen sing beda-beda, sing saben duwe sambungan dhewe menyang aliran sing cocog.

Aku nggawe proyek demo sing kapisah sing nuduhake aplikasi telung daemon sing sesambungan karo bus kasebut: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

Nanging aku bakal nuduhake carane konsumen bisa disusun:

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

Nggunakake framework iki ing aplikasi

Sawise ngetrapake bis ing mburiku, aku misahake tahapan individu saka perintah sinkron lawas lan nggawe pawang sing kapisah, saben-saben nindakake dhewe.

Pipa kanggo nambah situs anyar menyang basis data katon kaya iki:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Lan sakwise iku dadi luwih gampang kanggo kula kanggo nambah fungsi anyar, contone, RSS extraction lan parsing. Amarga proses iki uga mbutuhake konten asli, pawang extractor link RSS, kaya WebsiteIndexHistoryPersistor, langganan pesen "Konten / HtmlContent", ngolah lan ngirim pesen sing dibutuhake ing saluran pipa luwih lanjut.

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Pungkasane, ana sawetara daemon, sing saben-saben duwe sambungan mung karo sumber daya sing dibutuhake. Contone, daemon crawler ngemot kabeh pawang sing mbutuhake menyang Internet kanggo isi, lan daemon tetep njaga sambungan menyang database.

Saiki, tinimbang milih saka database, id sing dibutuhake sawise dilebokake dening persister mung dikirim liwat bis menyang kabeh pawang sing kasengsem.

Source: www.habr.com

Tuku hosting sing dipercaya kanggo situs kanthi proteksi DDoS, server VPS VDS 🔥 Tuku hosting situs web sing bisa dipercaya nganggo proteksi DDoS, server VPS VDS | ProHoster